emlxs_thread.c revision 9311:e24814334def
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 usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
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 2009 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 */
31EMLXS_MSG_DEF(EMLXS_THREAD_C);
32
33static void	emlxs_thread(emlxs_thread_t *ethread);
34static void	emlxs_taskq_thread(emlxs_taskq_thread_t *tthread);
35
36
37static void
38emlxs_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	return;
80
81}  /* emlxs_taskq_thread() */
82
83
84
85uint32_t
86emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg)
87{
88	emlxs_taskq_thread_t *tthread = NULL;
89
90	mutex_enter(&taskq->get_lock);
91
92	/* Make sure taskq is open for business */
93	if (!taskq->open) {
94		mutex_exit(&taskq->get_lock);
95		return (0);
96	}
97
98	/* Check get_list for a thread */
99	if (taskq->get_head) {
100		/* Get the next thread */
101		tthread = taskq->get_head;
102		taskq->get_count--;
103		taskq->get_head = (taskq->get_count) ? tthread->next : NULL;
104		tthread->next = NULL;
105	}
106
107	/* Else check put_list for a thread */
108	else if (taskq->put_head) {
109
110		/* Move put_list to get_list */
111		mutex_enter(&taskq->put_lock);
112		taskq->get_head = taskq->put_head;
113		taskq->get_count = taskq->put_count;
114		taskq->put_head = NULL;
115		taskq->put_count = 0;
116		mutex_exit(&taskq->put_lock);
117
118		/* Get the next thread */
119		tthread = taskq->get_head;
120		taskq->get_count--;
121		taskq->get_head = (taskq->get_count) ? tthread->next : NULL;
122		tthread->next = NULL;
123	}
124
125	mutex_exit(&taskq->get_lock);
126
127	/* Wake up the thread if one exists */
128	if (tthread) {
129		mutex_enter(&tthread->lock);
130		tthread->func = func;
131		tthread->arg = arg;
132		cv_signal(&tthread->cv_flag);
133		mutex_exit(&tthread->lock);
134
135		return (1);
136	}
137
138	return (0);
139
140}  /* emlxs_taskq_dispatch() */
141
142
143
144void
145emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq)
146{
147	emlxs_taskq_thread_t *tthread;
148	char buf[64];
149	uint32_t i;
150
151
152	/* If taskq is already open then quit */
153	if (taskq->open) {
154		return;
155	}
156
157	/* Zero the taskq */
158	bzero(taskq, sizeof (emlxs_taskq_t));
159
160	(void) sprintf(buf, "%s%d_thread_taskq_get mutex", DRIVER_NAME,
161	    hba->ddiinst);
162	mutex_init(&taskq->get_lock, buf, MUTEX_DRIVER,
163	    (void *)hba->intr_arg);
164
165	mutex_enter(&taskq->get_lock);
166
167	taskq->hba = hba;
168
169	(void) sprintf(buf, "%s%d_thread_taskq_put mutex", DRIVER_NAME,
170	    hba->ddiinst);
171	mutex_init(&taskq->put_lock, buf, MUTEX_DRIVER,
172	    (void *)hba->intr_arg);
173
174	for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
175		tthread = &taskq->thread_list[i];
176		tthread->taskq = taskq;
177
178		(void) sprintf(buf, "%s%d_thread%d mutex", DRIVER_NAME,
179		    hba->ddiinst, i);
180		mutex_init(&tthread->lock, buf, MUTEX_DRIVER,
181		    (void *)hba->intr_arg);
182
183		(void) sprintf(buf, "%s%d_thread%d cv", DRIVER_NAME,
184		    hba->ddiinst, i);
185		cv_init(&tthread->cv_flag, buf, CV_DRIVER, NULL);
186
187		tthread->flags |= EMLXS_THREAD_INITD;
188		tthread->thread =
189		    thread_create(NULL, 0, emlxs_taskq_thread,
190		    (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
191	}
192
193	/* Open the taskq */
194	taskq->open = 1;
195
196	mutex_exit(&taskq->get_lock);
197
198	return;
199
200}  /* emlxs_taskq_create() */
201
202
203void
204emlxs_taskq_destroy(emlxs_taskq_t *taskq)
205{
206	emlxs_taskq_thread_t *tthread;
207	uint32_t i;
208
209	/* If taskq already closed, then quit */
210	if (!taskq->open) {
211		return;
212	}
213
214	mutex_enter(&taskq->get_lock);
215
216	/* If taskq already closed, then quit */
217	if (!taskq->open) {
218		mutex_exit(&taskq->get_lock);
219		return;
220	}
221
222	taskq->open = 0;
223	mutex_exit(&taskq->get_lock);
224
225
226	/* No more threads can be dispatched now */
227
228	/* Kill the threads */
229	for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
230		tthread = &taskq->thread_list[i];
231
232		/*
233		 * If the thread lock can be acquired,
234		 * it is in one of these states:
235		 * 1. Thread not started.
236		 * 2. Thread asleep.
237		 * 3. Thread busy.
238		 * 4. Thread ended.
239		 */
240		mutex_enter(&tthread->lock);
241		tthread->flags |= EMLXS_THREAD_KILLED;
242		cv_signal(&tthread->cv_flag);
243
244		/* Wait for thread to die */
245		while (!(tthread->flags & EMLXS_THREAD_ENDED)) {
246			mutex_exit(&tthread->lock);
247			delay(drv_usectohz(10000));
248			mutex_enter(&tthread->lock);
249		}
250		mutex_exit(&tthread->lock);
251
252		/* Clean up thread */
253		mutex_destroy(&tthread->lock);
254		cv_destroy(&tthread->cv_flag);
255	}
256
257	/* Clean up taskq */
258	mutex_destroy(&taskq->put_lock);
259	mutex_destroy(&taskq->get_lock);
260
261	return;
262
263}  /* emlxs_taskq_destroy() */
264
265
266
267static void
268emlxs_thread(emlxs_thread_t *ethread)
269{
270	emlxs_hba_t *hba;
271	void (*func) ();
272	void *arg1;
273	void *arg2;
274
275	if (ethread->flags & EMLXS_THREAD_RUN_ONCE) {
276		hba = ethread->hba;
277		ethread->flags |= EMLXS_THREAD_STARTED;
278
279		if (!(ethread->flags & EMLXS_THREAD_KILLED)) {
280			func = ethread->func;
281			arg1 = ethread->arg1;
282			arg2 = ethread->arg2;
283
284			func(hba, arg1, arg2);
285		}
286
287		ethread->flags |= EMLXS_THREAD_ENDED;
288		ethread->flags &= ~EMLXS_THREAD_INITD;
289
290		/* Remove the thread from the spawn thread list */
291		mutex_enter(&hba->spawn_lock);
292		if (hba->spawn_thread_head == ethread)
293			hba->spawn_thread_head = ethread->next;
294		if (hba->spawn_thread_tail == ethread)
295			hba->spawn_thread_tail = ethread->prev;
296
297		if (ethread->prev)
298			ethread->prev->next = ethread->next;
299		if (ethread->next)
300			ethread->next->prev = ethread->prev;
301
302		ethread->next = ethread->prev = NULL;
303
304		kmem_free(ethread, sizeof (emlxs_thread_t));
305
306		mutex_exit(&hba->spawn_lock);
307	}
308	else
309	{
310		/*
311		 * If the thread lock can be acquired,
312		 * it is in one of these states:
313		 * 1. Thread not started.
314		 * 2. Thread asleep.
315		 * 3. Thread busy.
316		 * 4. Thread ended.
317		 */
318		mutex_enter(&ethread->lock);
319		ethread->flags |= EMLXS_THREAD_STARTED;
320
321		while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
322			if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
323				ethread->flags |= EMLXS_THREAD_ASLEEP;
324				cv_wait(&ethread->cv_flag, &ethread->lock);
325			}
326
327			ethread->flags &=
328			    ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
329
330			if (ethread->func) {
331				func = ethread->func;
332				arg1 = ethread->arg1;
333				arg2 = ethread->arg2;
334				ethread->func = NULL;
335				ethread->arg1 = NULL;
336				ethread->arg2 = NULL;
337
338				ethread->flags |= EMLXS_THREAD_BUSY;
339				mutex_exit(&ethread->lock);
340
341				func(ethread->hba, arg1, arg2);
342
343				mutex_enter(&ethread->lock);
344				ethread->flags &= ~EMLXS_THREAD_BUSY;
345			}
346		}
347
348		ethread->flags |= EMLXS_THREAD_ENDED;
349		mutex_exit(&ethread->lock);
350	}
351
352	thread_exit();
353
354}  /* emlxs_thread() */
355
356
357void
358emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
359{
360	char buf[64];
361
362	if (ethread->flags & EMLXS_THREAD_INITD) {
363		return;
364	}
365
366	bzero(ethread, sizeof (emlxs_thread_t));
367
368	(void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME, hba->ddiinst,
369	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
370	mutex_init(&ethread->lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
371
372	/* mutex_enter(&ethread->lock); */
373
374	(void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst,
375	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
376	cv_init(&ethread->cv_flag, buf, CV_DRIVER, NULL);
377
378	ethread->hba = hba;
379	ethread->flags |= EMLXS_THREAD_INITD;
380
381	/* mutex_exit(&ethread->lock); */
382
383	ethread->thread =
384	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
385	    TS_RUN, v.v_maxsyspri - 2);
386
387	return;
388
389}  /* emlxs_thread_create() */
390
391
392void
393emlxs_thread_destroy(emlxs_thread_t *ethread)
394{
395	/*
396	 * If the thread lock can be acquired,
397	 * it is in one of these states:
398	 * 1. Thread not started.
399	 * 2. Thread asleep.
400	 * 3. Thread busy.
401	 * 4. Thread ended.
402	 */
403	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
404		return;
405	}
406
407	mutex_enter(&ethread->lock);
408
409	if (ethread->flags & EMLXS_THREAD_ENDED) {
410		mutex_exit(&ethread->lock);
411		return;
412	}
413
414	ethread->flags &= ~EMLXS_THREAD_INITD;
415	ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
416	ethread->func = NULL;
417	ethread->arg1 = NULL;
418	ethread->arg2 = NULL;
419	cv_signal(&ethread->cv_flag);
420
421	/* Wait for thread to end */
422	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
423		mutex_exit(&ethread->lock);
424		delay(drv_usectohz(10000));
425		mutex_enter(&ethread->lock);
426	}
427
428	mutex_exit(&ethread->lock);
429
430	cv_destroy(&ethread->cv_flag);
431	mutex_destroy(&ethread->lock);
432
433	return;
434
435}  /* emlxs_thread_destroy() */
436
437
438void
439emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
440{
441
442	/*
443	 * If the thread lock can be acquired,
444	 * it is in one of these states:
445	 * 1. Thread not started.
446	 * 2. Thread asleep.
447	 * 3. Thread busy.
448	 * 4. Thread ended.
449	 */
450	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
451		return;
452	}
453
454	mutex_enter(&ethread->lock);
455
456	if (ethread->flags & EMLXS_THREAD_ENDED) {
457		return;
458	}
459
460	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
461		mutex_exit(&ethread->lock);
462		delay(drv_usectohz(10000));
463		mutex_enter(&ethread->lock);
464
465		if (ethread->flags & EMLXS_THREAD_ENDED) {
466			return;
467		}
468	}
469
470	ethread->flags |= EMLXS_THREAD_TRIGGERED;
471	ethread->func = func;
472	ethread->arg1 = NULL;
473	ethread->arg2 = NULL;
474
475	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
476		cv_signal(&ethread->cv_flag);
477	}
478
479	mutex_exit(&ethread->lock);
480
481	return;
482
483}  /* emlxs_thread_trigger1() */
484
485
486void
487emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), RING *rp)
488{
489
490	/*
491	 * If the thread lock can be acquired,
492	 * it is in one of these states:
493	 * 1. Thread not started.
494	 * 2. Thread asleep.
495	 * 3. Thread busy.
496	 * 4. Thread ended.
497	 */
498	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
499		return;
500	}
501
502	mutex_enter(&ethread->lock);
503
504	if (ethread->flags & EMLXS_THREAD_ENDED) {
505		return;
506	}
507
508	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
509		mutex_exit(&ethread->lock);
510		delay(drv_usectohz(10000));
511		mutex_enter(&ethread->lock);
512
513		if (ethread->flags & EMLXS_THREAD_ENDED) {
514			return;
515		}
516	}
517
518	ethread->flags |= EMLXS_THREAD_TRIGGERED;
519	ethread->func = func;
520	ethread->arg1 = (void *)rp;
521	ethread->arg2 = NULL;
522
523	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
524		cv_signal(&ethread->cv_flag);
525	}
526
527	mutex_exit(&ethread->lock);
528
529	return;
530
531}  /* emlxs_thread_trigger2() */
532
533
534void
535emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2)
536{
537	emlxs_port_t	*port = &PPORT;
538	emlxs_thread_t	*ethread;
539
540	/* Create a thread */
541	ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t),
542	    KM_NOSLEEP);
543
544	if (ethread == NULL) {
545		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
546		    "Unable to allocate thread object.");
547
548		return;
549	}
550
551	bzero(ethread, sizeof (emlxs_thread_t));
552	ethread->hba = hba;
553	ethread->flags = EMLXS_THREAD_INITD | EMLXS_THREAD_RUN_ONCE;
554	ethread->func = func;
555	ethread->arg1 = arg1;
556	ethread->arg2 = arg2;
557
558	/* Queue the thread on the spawn thread list */
559	mutex_enter(&hba->spawn_lock);
560
561	/* Dont spawn the thread if the spawn list is closed */
562	if (hba->spawn_open == 0) {
563		mutex_exit(&hba->spawn_lock);
564
565		/* destroy the thread */
566		kmem_free(ethread, sizeof (emlxs_thread_t));
567		return;
568	}
569
570	if (hba->spawn_thread_head == NULL) {
571		hba->spawn_thread_head = ethread;
572	}
573	else
574	{
575		hba->spawn_thread_tail->next = ethread;
576		ethread->prev = hba->spawn_thread_tail;
577	}
578
579	hba->spawn_thread_tail = ethread;
580	mutex_exit(&hba->spawn_lock);
581
582	(void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
583	    TS_RUN, v.v_maxsyspri - 2);
584
585}
586
587
588void
589emlxs_thread_spawn_create(emlxs_hba_t *hba)
590{
591	char	buf[64];
592
593	if (hba->spawn_open)
594		return;
595
596	(void) sprintf(buf, "%s%d_thread_lock mutex", DRIVER_NAME,
597	    hba->ddiinst);
598	mutex_init(&hba->spawn_lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
599
600	hba->spawn_thread_head = NULL;
601	hba->spawn_thread_tail = NULL;
602
603	mutex_enter(&hba->spawn_lock);
604	hba->spawn_open = 1;
605	mutex_exit(&hba->spawn_lock);
606
607}
608
609
610void
611emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
612{
613	emlxs_thread_t	*ethread;
614
615	if (hba->spawn_open == 0) {
616		return;
617	}
618
619	mutex_enter(&hba->spawn_lock);
620	hba->spawn_open = 0;
621
622	for (ethread = hba->spawn_thread_head; ethread;
623	    ethread = ethread->next) {
624		ethread->flags |= EMLXS_THREAD_KILLED;
625	}
626
627	/* Wait for all the spawned threads to complete */
628	while (hba->spawn_thread_head) {
629		mutex_exit(&hba->spawn_lock);
630		delay(drv_usectohz(10000));
631		mutex_enter(&hba->spawn_lock);
632	}
633
634	mutex_exit(&hba->spawn_lock);
635	mutex_destroy(&hba->spawn_lock);
636
637}
638