Unleashed v1.4
[unleashed.git] / usr / src / uts / common / io / fibre-channel / fca / emlxs / emlxs_thread.c
blob907d1a0cae5c8e6986de6eddca45ecd86af084f8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2004-2011 Emulex. All rights reserved.
24 * Use is subject to license terms.
27 #include <emlxs.h>
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_THREAD_C);
33 static void emlxs_thread(emlxs_thread_t *ethread);
34 static void emlxs_taskq_thread(emlxs_taskq_thread_t *tthread);
37 static void
38 emlxs_taskq_thread(emlxs_taskq_thread_t *tthread)
40 emlxs_taskq_t *taskq;
41 void (*func) ();
42 void *arg;
44 taskq = tthread->taskq;
46 mutex_enter(&tthread->lock);
47 tthread->flags |= EMLXS_THREAD_STARTED;
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);
56 tthread->flags |= EMLXS_THREAD_ASLEEP;
57 cv_wait(&tthread->cv_flag, &tthread->lock);
58 tthread->flags &= ~EMLXS_THREAD_ASLEEP;
60 if (tthread->func) {
61 func = tthread->func;
62 arg = tthread->arg;
64 tthread->flags |= EMLXS_THREAD_BUSY;
65 mutex_exit(&tthread->lock);
67 func(taskq->hba, arg);
69 mutex_enter(&tthread->lock);
70 tthread->flags &= ~EMLXS_THREAD_BUSY;
74 tthread->flags |= EMLXS_THREAD_ENDED;
75 mutex_exit(&tthread->lock);
77 thread_exit();
79 } /* emlxs_taskq_thread() */
83 uint32_t
84 emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg)
86 emlxs_taskq_thread_t *tthread = NULL;
88 mutex_enter(&taskq->get_lock);
90 /* Make sure taskq is open for business */
91 if (!taskq->open) {
92 mutex_exit(&taskq->get_lock);
93 return (0);
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;
105 /* Else check put_list for a thread */
106 else if (taskq->put_head) {
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);
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;
123 mutex_exit(&taskq->get_lock);
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);
133 return (1);
136 return (0);
138 } /* emlxs_taskq_dispatch() */
142 void
143 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq)
145 emlxs_taskq_thread_t *tthread;
146 uint32_t i;
149 /* If taskq is already open then quit */
150 if (taskq->open) {
151 return;
154 /* Zero the taskq */
155 bzero(taskq, sizeof (emlxs_taskq_t));
157 mutex_init(&taskq->get_lock, NULL, MUTEX_DRIVER,
158 DDI_INTR_PRI(hba->intr_arg));
160 mutex_enter(&taskq->get_lock);
162 taskq->hba = hba;
164 mutex_init(&taskq->put_lock, NULL, MUTEX_DRIVER,
165 DDI_INTR_PRI(hba->intr_arg));
167 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
168 tthread = &taskq->thread_list[i];
169 tthread->taskq = taskq;
171 mutex_init(&tthread->lock, NULL, MUTEX_DRIVER,
172 DDI_INTR_PRI(hba->intr_arg));
174 cv_init(&tthread->cv_flag, NULL, CV_DRIVER, NULL);
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);
182 /* Open the taskq */
183 taskq->open = 1;
185 mutex_exit(&taskq->get_lock);
187 return;
189 } /* emlxs_taskq_create() */
192 void
193 emlxs_taskq_destroy(emlxs_taskq_t *taskq)
195 emlxs_taskq_thread_t *tthread;
196 uint32_t i;
198 /* If taskq already closed, then quit */
199 if (!taskq->open) {
200 return;
203 mutex_enter(&taskq->get_lock);
205 /* If taskq already closed, then quit */
206 if (!taskq->open) {
207 mutex_exit(&taskq->get_lock);
208 return;
211 taskq->open = 0;
212 mutex_exit(&taskq->get_lock);
215 /* No more threads can be dispatched now */
217 /* Kill the threads */
218 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
219 tthread = &taskq->thread_list[i];
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.
229 mutex_enter(&tthread->lock);
230 tthread->flags |= EMLXS_THREAD_KILLED;
231 cv_signal(&tthread->cv_flag);
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);
239 mutex_exit(&tthread->lock);
241 /* Clean up thread */
242 mutex_destroy(&tthread->lock);
243 cv_destroy(&tthread->cv_flag);
246 /* Clean up taskq */
247 mutex_destroy(&taskq->put_lock);
248 mutex_destroy(&taskq->get_lock);
250 return;
252 } /* emlxs_taskq_destroy() */
256 static void
257 emlxs_thread(emlxs_thread_t *ethread)
259 emlxs_hba_t *hba;
260 void (*func) ();
261 void *arg1;
262 void *arg2;
264 if (ethread->flags & EMLXS_THREAD_RUN_ONCE) {
265 hba = ethread->hba;
266 ethread->flags |= EMLXS_THREAD_STARTED;
268 if (!(ethread->flags & EMLXS_THREAD_KILLED)) {
269 func = ethread->func;
270 arg1 = ethread->arg1;
271 arg2 = ethread->arg2;
273 func(hba, arg1, arg2);
276 ethread->flags |= EMLXS_THREAD_ENDED;
277 ethread->flags &= ~EMLXS_THREAD_INITD;
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;
286 if (ethread->prev)
287 ethread->prev->next = ethread->next;
288 if (ethread->next)
289 ethread->next->prev = ethread->prev;
291 ethread->next = ethread->prev = NULL;
293 kmem_free(ethread, sizeof (emlxs_thread_t));
295 mutex_exit(&EMLXS_SPAWN_LOCK);
297 else
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.
307 mutex_enter(&ethread->lock);
308 ethread->flags |= EMLXS_THREAD_STARTED;
310 while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
311 if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
312 ethread->flags |= EMLXS_THREAD_ASLEEP;
313 cv_wait(&ethread->cv_flag, &ethread->lock);
316 ethread->flags &=
317 ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
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;
327 ethread->flags |= EMLXS_THREAD_BUSY;
328 mutex_exit(&ethread->lock);
330 func(ethread->hba, arg1, arg2);
332 mutex_enter(&ethread->lock);
333 ethread->flags &= ~EMLXS_THREAD_BUSY;
337 ethread->flags |= EMLXS_THREAD_ENDED;
338 mutex_exit(&ethread->lock);
341 thread_exit();
343 } /* emlxs_thread() */
346 void
347 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
349 uint16_t pri;
351 if (ethread->flags & EMLXS_THREAD_INITD) {
352 return;
355 bzero(ethread, sizeof (emlxs_thread_t));
357 mutex_init(&ethread->lock, NULL, MUTEX_DRIVER,
358 DDI_INTR_PRI(hba->intr_arg));
360 cv_init(&ethread->cv_flag, NULL, CV_DRIVER, NULL);
362 ethread->hba = hba;
363 ethread->flags |= EMLXS_THREAD_INITD;
365 pri = v.v_maxsyspri - 2;
367 ethread->thread =
368 thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
369 TS_RUN, pri);
371 } /* emlxs_thread_create() */
374 void
375 emlxs_thread_destroy(emlxs_thread_t *ethread)
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.
385 if (!(ethread->flags & EMLXS_THREAD_INITD)) {
386 return;
390 mutex_enter(&ethread->lock);
392 if (ethread->flags & EMLXS_THREAD_ENDED) {
393 mutex_exit(&ethread->lock);
394 return;
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(&ethread->cv_flag);
404 /* Wait for thread to end */
405 while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
406 mutex_exit(&ethread->lock);
407 delay(drv_usectohz(10000));
408 mutex_enter(&ethread->lock);
411 mutex_exit(&ethread->lock);
413 cv_destroy(&ethread->cv_flag);
414 mutex_destroy(&ethread->lock);
416 return;
418 } /* emlxs_thread_destroy() */
421 void
422 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
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.
433 if (!(ethread->flags & EMLXS_THREAD_INITD)) {
434 return;
437 mutex_enter(&ethread->lock);
439 if (ethread->flags & EMLXS_THREAD_ENDED) {
440 return;
443 while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
444 mutex_exit(&ethread->lock);
445 delay(drv_usectohz(10000));
446 mutex_enter(&ethread->lock);
448 if (ethread->flags & EMLXS_THREAD_ENDED) {
449 return;
453 ethread->flags |= EMLXS_THREAD_TRIGGERED;
454 ethread->func = func;
455 ethread->arg1 = NULL;
456 ethread->arg2 = NULL;
458 if (ethread->flags & EMLXS_THREAD_ASLEEP) {
459 cv_signal(&ethread->cv_flag);
462 mutex_exit(&ethread->lock);
464 return;
466 } /* emlxs_thread_trigger1() */
469 void
470 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), CHANNEL *cp)
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.
481 if (!(ethread->flags & EMLXS_THREAD_INITD)) {
482 return;
485 mutex_enter(&ethread->lock);
487 if (ethread->flags & EMLXS_THREAD_ENDED) {
488 return;
491 while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
492 mutex_exit(&ethread->lock);
493 delay(drv_usectohz(10000));
494 mutex_enter(&ethread->lock);
496 if (ethread->flags & EMLXS_THREAD_ENDED) {
497 return;
501 ethread->flags |= EMLXS_THREAD_TRIGGERED;
502 ethread->func = func;
503 ethread->arg1 = (void *)cp;
504 ethread->arg2 = NULL;
506 if (ethread->flags & EMLXS_THREAD_ASLEEP) {
507 cv_signal(&ethread->cv_flag);
510 mutex_exit(&ethread->lock);
512 return;
514 } /* emlxs_thread_trigger2() */
517 void
518 emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2)
520 emlxs_port_t *port = &PPORT;
521 emlxs_thread_t *ethread;
523 /* Create a thread */
524 ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t),
525 KM_NOSLEEP);
527 if (ethread == NULL) {
528 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
529 "Unable to allocate thread object.");
531 return;
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;
541 /* Queue the thread on the spawn thread list */
542 mutex_enter(&EMLXS_SPAWN_LOCK);
544 /* Dont spawn the thread if the spawn list is closed */
545 if (hba->spawn_open == 0) {
546 mutex_exit(&EMLXS_SPAWN_LOCK);
548 /* destroy the thread */
549 kmem_free(ethread, sizeof (emlxs_thread_t));
550 return;
553 if (hba->spawn_thread_head == NULL) {
554 hba->spawn_thread_head = ethread;
556 else
558 hba->spawn_thread_tail->next = ethread;
559 ethread->prev = hba->spawn_thread_tail;
562 hba->spawn_thread_tail = ethread;
563 mutex_exit(&EMLXS_SPAWN_LOCK);
565 (void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
566 TS_RUN, v.v_maxsyspri - 2);
568 } /* emlxs_thread_spawn() */
571 void
572 emlxs_thread_spawn_create(emlxs_hba_t *hba)
574 mutex_enter(&EMLXS_SPAWN_LOCK);
575 if (hba->spawn_open) {
576 mutex_exit(&EMLXS_SPAWN_LOCK);
577 return;
580 hba->spawn_thread_head = NULL;
581 hba->spawn_thread_tail = NULL;
583 hba->spawn_open = 1;
584 mutex_exit(&EMLXS_SPAWN_LOCK);
589 void
590 emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
592 emlxs_thread_t *ethread;
594 mutex_enter(&EMLXS_SPAWN_LOCK);
595 if (hba->spawn_open == 0) {
596 mutex_exit(&EMLXS_SPAWN_LOCK);
597 return;
600 hba->spawn_open = 0;
602 for (ethread = hba->spawn_thread_head; ethread;
603 ethread = ethread->next) {
604 ethread->flags |= EMLXS_THREAD_KILLED;
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);
614 mutex_exit(&EMLXS_SPAWN_LOCK);