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