1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at
9 * http://www.opensource.org/licenses/cddl1.txt.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2004-2011 Emulex. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <emlxs.h>
28
29
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_THREAD_C);
32
33 static void emlxs_thread(emlxs_thread_t *ethread);
34 static void emlxs_taskq_thread(emlxs_taskq_thread_t *tthread);
35
36
37 static void
emlxs_taskq_thread(emlxs_taskq_thread_t * tthread)38 emlxs_taskq_thread(emlxs_taskq_thread_t *tthread)
39 {
40 emlxs_taskq_t *taskq;
41 void (*func) ();
42 void *arg;
43
44 taskq = tthread->taskq;
45
46 mutex_enter(&tthread->lock);
47 tthread->flags |= EMLXS_THREAD_STARTED;
48
49 while (!(tthread->flags & EMLXS_THREAD_KILLED)) {
50 mutex_enter(&taskq->put_lock);
51 tthread->next = taskq->put_head;
52 taskq->put_head = tthread;
53 taskq->put_count++;
54 mutex_exit(&taskq->put_lock);
55
56 tthread->flags |= EMLXS_THREAD_ASLEEP;
57 cv_wait(&tthread->cv_flag, &tthread->lock);
58 tthread->flags &= ~EMLXS_THREAD_ASLEEP;
59
60 if (tthread->func) {
61 func = tthread->func;
62 arg = tthread->arg;
63
64 tthread->flags |= EMLXS_THREAD_BUSY;
65 mutex_exit(&tthread->lock);
66
67 func(taskq->hba, arg);
68
69 mutex_enter(&tthread->lock);
70 tthread->flags &= ~EMLXS_THREAD_BUSY;
71 }
72 }
73
74 tthread->flags |= EMLXS_THREAD_ENDED;
75 mutex_exit(&tthread->lock);
76
77 thread_exit();
78
79 } /* emlxs_taskq_thread() */
80
81
82
83 uint32_t
emlxs_taskq_dispatch(emlxs_taskq_t * taskq,void (* func)(),void * arg)84 emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg)
85 {
86 emlxs_taskq_thread_t *tthread = NULL;
87
88 mutex_enter(&taskq->get_lock);
89
90 /* Make sure taskq is open for business */
91 if (!taskq->open) {
92 mutex_exit(&taskq->get_lock);
93 return (0);
94 }
95
96 /* Check get_list for a thread */
97 if (taskq->get_head) {
98 /* Get the next thread */
99 tthread = taskq->get_head;
100 taskq->get_count--;
101 taskq->get_head = (taskq->get_count) ? tthread->next : NULL;
102 tthread->next = NULL;
103 }
104
105 /* Else check put_list for a thread */
106 else if (taskq->put_head) {
107
108 /* Move put_list to get_list */
109 mutex_enter(&taskq->put_lock);
110 taskq->get_head = taskq->put_head;
111 taskq->get_count = taskq->put_count;
112 taskq->put_head = NULL;
113 taskq->put_count = 0;
114 mutex_exit(&taskq->put_lock);
115
116 /* Get the next thread */
117 tthread = taskq->get_head;
118 taskq->get_count--;
119 taskq->get_head = (taskq->get_count) ? tthread->next : NULL;
120 tthread->next = NULL;
121 }
122
123 mutex_exit(&taskq->get_lock);
124
125 /* Wake up the thread if one exists */
126 if (tthread) {
127 mutex_enter(&tthread->lock);
128 tthread->func = func;
129 tthread->arg = arg;
130 cv_signal(&tthread->cv_flag);
131 mutex_exit(&tthread->lock);
132
133 return (1);
134 }
135
136 return (0);
137
138 } /* emlxs_taskq_dispatch() */
139
140
141
142 void
emlxs_taskq_create(emlxs_hba_t * hba,emlxs_taskq_t * taskq)143 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq)
144 {
145 emlxs_taskq_thread_t *tthread;
146 uint32_t i;
147
148
149 /* If taskq is already open then quit */
150 if (taskq->open) {
151 return;
152 }
153
154 /* Zero the taskq */
155 bzero(taskq, sizeof (emlxs_taskq_t));
156
157 mutex_init(&taskq->get_lock, NULL, MUTEX_DRIVER,
158 DDI_INTR_PRI(hba->intr_arg));
159
160 mutex_enter(&taskq->get_lock);
161
162 taskq->hba = hba;
163
164 mutex_init(&taskq->put_lock, NULL, MUTEX_DRIVER,
165 DDI_INTR_PRI(hba->intr_arg));
166
167 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
168 tthread = &taskq->thread_list[i];
169 tthread->taskq = taskq;
170
171 mutex_init(&tthread->lock, NULL, MUTEX_DRIVER,
172 DDI_INTR_PRI(hba->intr_arg));
173
174 cv_init(&tthread->cv_flag, NULL, CV_DRIVER, NULL);
175
176 tthread->flags |= EMLXS_THREAD_INITD;
177 tthread->thread =
178 thread_create(NULL, 0, emlxs_taskq_thread,
179 (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
180 }
181
182 /* Open the taskq */
183 taskq->open = 1;
184
185 mutex_exit(&taskq->get_lock);
186
187 return;
188
189 } /* emlxs_taskq_create() */
190
191
192 void
emlxs_taskq_destroy(emlxs_taskq_t * taskq)193 emlxs_taskq_destroy(emlxs_taskq_t *taskq)
194 {
195 emlxs_taskq_thread_t *tthread;
196 uint32_t i;
197
198 /* If taskq already closed, then quit */
199 if (!taskq->open) {
200 return;
201 }
202
203 mutex_enter(&taskq->get_lock);
204
205 /* If taskq already closed, then quit */
206 if (!taskq->open) {
207 mutex_exit(&taskq->get_lock);
208 return;
209 }
210
211 taskq->open = 0;
212 mutex_exit(&taskq->get_lock);
213
214
215 /* No more threads can be dispatched now */
216
217 /* Kill the threads */
218 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
219 tthread = &taskq->thread_list[i];
220
221 /*
222 * If the thread lock can be acquired,
223 * it is in one of these states:
224 * 1. Thread not started.
225 * 2. Thread asleep.
226 * 3. Thread busy.
227 * 4. Thread ended.
228 */
229 mutex_enter(&tthread->lock);
230 tthread->flags |= EMLXS_THREAD_KILLED;
231 cv_signal(&tthread->cv_flag);
232
233 /* Wait for thread to die */
234 while (!(tthread->flags & EMLXS_THREAD_ENDED)) {
235 mutex_exit(&tthread->lock);
236 delay(drv_usectohz(10000));
237 mutex_enter(&tthread->lock);
238 }
239 mutex_exit(&tthread->lock);
240
241 /* Clean up thread */
242 mutex_destroy(&tthread->lock);
243 cv_destroy(&tthread->cv_flag);
244 }
245
246 /* Clean up taskq */
247 mutex_destroy(&taskq->put_lock);
248 mutex_destroy(&taskq->get_lock);
249
250 return;
251
252 } /* emlxs_taskq_destroy() */
253
254
255
256 static void
emlxs_thread(emlxs_thread_t * ethread)257 emlxs_thread(emlxs_thread_t *ethread)
258 {
259 emlxs_hba_t *hba;
260 void (*func) ();
261 void *arg1;
262 void *arg2;
263
264 if (ethread->flags & EMLXS_THREAD_RUN_ONCE) {
265 hba = ethread->hba;
266 ethread->flags |= EMLXS_THREAD_STARTED;
267
268 if (!(ethread->flags & EMLXS_THREAD_KILLED)) {
269 func = ethread->func;
270 arg1 = ethread->arg1;
271 arg2 = ethread->arg2;
272
273 func(hba, arg1, arg2);
274 }
275
276 ethread->flags |= EMLXS_THREAD_ENDED;
277 ethread->flags &= ~EMLXS_THREAD_INITD;
278
279 /* Remove the thread from the spawn thread list */
280 mutex_enter(&EMLXS_SPAWN_LOCK);
281 if (hba->spawn_thread_head == ethread)
282 hba->spawn_thread_head = ethread->next;
283 if (hba->spawn_thread_tail == ethread)
284 hba->spawn_thread_tail = ethread->prev;
285
286 if (ethread->prev)
287 ethread->prev->next = ethread->next;
288 if (ethread->next)
289 ethread->next->prev = ethread->prev;
290
291 ethread->next = ethread->prev = NULL;
292
293 kmem_free(ethread, sizeof (emlxs_thread_t));
294
295 mutex_exit(&EMLXS_SPAWN_LOCK);
296 }
297 else
298 {
299 /*
300 * If the thread lock can be acquired,
301 * it is in one of these states:
302 * 1. Thread not started.
303 * 2. Thread asleep.
304 * 3. Thread busy.
305 * 4. Thread ended.
306 */
307 mutex_enter(ðread->lock);
308 ethread->flags |= EMLXS_THREAD_STARTED;
309
310 while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
311 if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
312 ethread->flags |= EMLXS_THREAD_ASLEEP;
313 cv_wait(ðread->cv_flag, ðread->lock);
314 }
315
316 ethread->flags &=
317 ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
318
319 if (ethread->func) {
320 func = ethread->func;
321 arg1 = ethread->arg1;
322 arg2 = ethread->arg2;
323 ethread->func = NULL;
324 ethread->arg1 = NULL;
325 ethread->arg2 = NULL;
326
327 ethread->flags |= EMLXS_THREAD_BUSY;
328 mutex_exit(ðread->lock);
329
330 func(ethread->hba, arg1, arg2);
331
332 mutex_enter(ðread->lock);
333 ethread->flags &= ~EMLXS_THREAD_BUSY;
334 }
335 }
336
337 ethread->flags |= EMLXS_THREAD_ENDED;
338 mutex_exit(ðread->lock);
339 }
340
341 thread_exit();
342
343 } /* emlxs_thread() */
344
345
346 void
emlxs_thread_create(emlxs_hba_t * hba,emlxs_thread_t * ethread)347 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
348 {
349 uint16_t pri;
350
351 if (ethread->flags & EMLXS_THREAD_INITD) {
352 return;
353 }
354
355 bzero(ethread, sizeof (emlxs_thread_t));
356
357 mutex_init(ðread->lock, NULL, MUTEX_DRIVER,
358 DDI_INTR_PRI(hba->intr_arg));
359
360 cv_init(ðread->cv_flag, NULL, CV_DRIVER, NULL);
361
362 ethread->hba = hba;
363 ethread->flags |= EMLXS_THREAD_INITD;
364
365 pri = v.v_maxsyspri - 2;
366
367 ethread->thread =
368 thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
369 TS_RUN, pri);
370
371 } /* emlxs_thread_create() */
372
373
374 void
emlxs_thread_destroy(emlxs_thread_t * ethread)375 emlxs_thread_destroy(emlxs_thread_t *ethread)
376 {
377 /*
378 * If the thread lock can be acquired,
379 * it is in one of these states:
380 * 1. Thread not started.
381 * 2. Thread asleep.
382 * 3. Thread busy.
383 * 4. Thread ended.
384 */
385 if (!(ethread->flags & EMLXS_THREAD_INITD)) {
386 return;
387 }
388
389
390 mutex_enter(ðread->lock);
391
392 if (ethread->flags & EMLXS_THREAD_ENDED) {
393 mutex_exit(ðread->lock);
394 return;
395 }
396
397 ethread->flags &= ~EMLXS_THREAD_INITD;
398 ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
399 ethread->func = NULL;
400 ethread->arg1 = NULL;
401 ethread->arg2 = NULL;
402 cv_signal(ðread->cv_flag);
403
404 /* Wait for thread to end */
405 while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
406 mutex_exit(ðread->lock);
407 delay(drv_usectohz(10000));
408 mutex_enter(ðread->lock);
409 }
410
411 mutex_exit(ðread->lock);
412
413 cv_destroy(ðread->cv_flag);
414 mutex_destroy(ðread->lock);
415
416 return;
417
418 } /* emlxs_thread_destroy() */
419
420
421 void
emlxs_thread_trigger1(emlxs_thread_t * ethread,void (* func)())422 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
423 {
424
425 /*
426 * If the thread lock can be acquired,
427 * it is in one of these states:
428 * 1. Thread not started.
429 * 2. Thread asleep.
430 * 3. Thread busy.
431 * 4. Thread ended.
432 */
433 if (!(ethread->flags & EMLXS_THREAD_INITD)) {
434 return;
435 }
436
437 mutex_enter(ðread->lock);
438
439 if (ethread->flags & EMLXS_THREAD_ENDED) {
440 return;
441 }
442
443 while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
444 mutex_exit(ðread->lock);
445 delay(drv_usectohz(10000));
446 mutex_enter(ðread->lock);
447
448 if (ethread->flags & EMLXS_THREAD_ENDED) {
449 return;
450 }
451 }
452
453 ethread->flags |= EMLXS_THREAD_TRIGGERED;
454 ethread->func = func;
455 ethread->arg1 = NULL;
456 ethread->arg2 = NULL;
457
458 if (ethread->flags & EMLXS_THREAD_ASLEEP) {
459 cv_signal(ðread->cv_flag);
460 }
461
462 mutex_exit(ðread->lock);
463
464 return;
465
466 } /* emlxs_thread_trigger1() */
467
468
469 void
emlxs_thread_trigger2(emlxs_thread_t * ethread,void (* func)(),CHANNEL * cp)470 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), CHANNEL *cp)
471 {
472
473 /*
474 * If the thread lock can be acquired,
475 * it is in one of these states:
476 * 1. Thread not started.
477 * 2. Thread asleep.
478 * 3. Thread busy.
479 * 4. Thread ended.
480 */
481 if (!(ethread->flags & EMLXS_THREAD_INITD)) {
482 return;
483 }
484
485 mutex_enter(ðread->lock);
486
487 if (ethread->flags & EMLXS_THREAD_ENDED) {
488 return;
489 }
490
491 while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
492 mutex_exit(ðread->lock);
493 delay(drv_usectohz(10000));
494 mutex_enter(ðread->lock);
495
496 if (ethread->flags & EMLXS_THREAD_ENDED) {
497 return;
498 }
499 }
500
501 ethread->flags |= EMLXS_THREAD_TRIGGERED;
502 ethread->func = func;
503 ethread->arg1 = (void *)cp;
504 ethread->arg2 = NULL;
505
506 if (ethread->flags & EMLXS_THREAD_ASLEEP) {
507 cv_signal(ðread->cv_flag);
508 }
509
510 mutex_exit(ðread->lock);
511
512 return;
513
514 } /* emlxs_thread_trigger2() */
515
516
517 void
emlxs_thread_spawn(emlxs_hba_t * hba,void (* func)(),void * arg1,void * arg2)518 emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2)
519 {
520 emlxs_port_t *port = &PPORT;
521 emlxs_thread_t *ethread;
522
523 /* Create a thread */
524 ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t),
525 KM_NOSLEEP);
526
527 if (ethread == NULL) {
528 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
529 "Unable to allocate thread object.");
530
531 return;
532 }
533
534 bzero(ethread, sizeof (emlxs_thread_t));
535 ethread->hba = hba;
536 ethread->flags = EMLXS_THREAD_INITD | EMLXS_THREAD_RUN_ONCE;
537 ethread->func = func;
538 ethread->arg1 = arg1;
539 ethread->arg2 = arg2;
540
541 /* Queue the thread on the spawn thread list */
542 mutex_enter(&EMLXS_SPAWN_LOCK);
543
544 /* Dont spawn the thread if the spawn list is closed */
545 if (hba->spawn_open == 0) {
546 mutex_exit(&EMLXS_SPAWN_LOCK);
547
548 /* destroy the thread */
549 kmem_free(ethread, sizeof (emlxs_thread_t));
550 return;
551 }
552
553 if (hba->spawn_thread_head == NULL) {
554 hba->spawn_thread_head = ethread;
555 }
556 else
557 {
558 hba->spawn_thread_tail->next = ethread;
559 ethread->prev = hba->spawn_thread_tail;
560 }
561
562 hba->spawn_thread_tail = ethread;
563 mutex_exit(&EMLXS_SPAWN_LOCK);
564
565 (void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
566 TS_RUN, v.v_maxsyspri - 2);
567
568 } /* emlxs_thread_spawn() */
569
570
571 void
emlxs_thread_spawn_create(emlxs_hba_t * hba)572 emlxs_thread_spawn_create(emlxs_hba_t *hba)
573 {
574 mutex_enter(&EMLXS_SPAWN_LOCK);
575 if (hba->spawn_open) {
576 mutex_exit(&EMLXS_SPAWN_LOCK);
577 return;
578 }
579
580 hba->spawn_thread_head = NULL;
581 hba->spawn_thread_tail = NULL;
582
583 hba->spawn_open = 1;
584 mutex_exit(&EMLXS_SPAWN_LOCK);
585
586 }
587
588
589 void
emlxs_thread_spawn_destroy(emlxs_hba_t * hba)590 emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
591 {
592 emlxs_thread_t *ethread;
593
594 mutex_enter(&EMLXS_SPAWN_LOCK);
595 if (hba->spawn_open == 0) {
596 mutex_exit(&EMLXS_SPAWN_LOCK);
597 return;
598 }
599
600 hba->spawn_open = 0;
601
602 for (ethread = hba->spawn_thread_head; ethread;
603 ethread = ethread->next) {
604 ethread->flags |= EMLXS_THREAD_KILLED;
605 }
606
607 /* Wait for all the spawned threads to complete */
608 while (hba->spawn_thread_head) {
609 mutex_exit(&EMLXS_SPAWN_LOCK);
610 delay(drv_usectohz(10000));
611 mutex_enter(&EMLXS_SPAWN_LOCK);
612 }
613
614 mutex_exit(&EMLXS_SPAWN_LOCK);
615 }
616