emlxs_thread.c revision 8815:41895c0fc44c
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	void (*func) ();
271	void *arg1;
272	void *arg2;
273
274	/*
275	 * If the thread lock can be acquired,
276	 * it is in one of these states:
277	 * 1. Thread not started.
278	 * 2. Thread asleep.
279	 * 3. Thread busy.
280	 * 4. Thread ended.
281	 */
282	mutex_enter(&ethread->lock);
283	ethread->flags |= EMLXS_THREAD_STARTED;
284
285	while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
286		if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
287			ethread->flags |= EMLXS_THREAD_ASLEEP;
288			cv_wait(&ethread->cv_flag, &ethread->lock);
289		}
290
291		ethread->flags &=
292		    ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
293
294		if (ethread->func) {
295			func = ethread->func;
296			arg1 = ethread->arg1;
297			arg2 = ethread->arg2;
298			ethread->func = NULL;
299			ethread->arg1 = NULL;
300			ethread->arg2 = NULL;
301
302			ethread->flags |= EMLXS_THREAD_BUSY;
303			mutex_exit(&ethread->lock);
304
305			func(ethread->hba, arg1, arg2);
306
307			mutex_enter(&ethread->lock);
308			ethread->flags &= ~EMLXS_THREAD_BUSY;
309		}
310	}
311
312	ethread->flags |= EMLXS_THREAD_ENDED;
313	mutex_exit(&ethread->lock);
314
315	thread_exit();
316
317	return;
318
319}  /* emlxs_thread() */
320
321
322void
323emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
324{
325	char buf[64];
326
327	if (ethread->flags & EMLXS_THREAD_INITD) {
328		return;
329	}
330
331	bzero(ethread, sizeof (emlxs_thread_t));
332
333	(void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME, hba->ddiinst,
334	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
335	mutex_init(&ethread->lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
336
337	/* mutex_enter(&ethread->lock); */
338
339	(void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst,
340	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
341	cv_init(&ethread->cv_flag, buf, CV_DRIVER, NULL);
342
343	ethread->hba = hba;
344	ethread->flags |= EMLXS_THREAD_INITD;
345
346	/* mutex_exit(&ethread->lock); */
347
348	ethread->thread =
349	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
350	    TS_RUN, v.v_maxsyspri - 2);
351
352	return;
353
354}  /* emlxs_thread_create() */
355
356
357void
358emlxs_thread_destroy(emlxs_thread_t *ethread)
359{
360	/*
361	 * If the thread lock can be acquired,
362	 * it is in one of these states:
363	 * 1. Thread not started.
364	 * 2. Thread asleep.
365	 * 3. Thread busy.
366	 * 4. Thread ended.
367	 */
368	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
369		return;
370	}
371
372	mutex_enter(&ethread->lock);
373
374	if (ethread->flags & EMLXS_THREAD_ENDED) {
375		return;
376	}
377
378	ethread->flags &= ~EMLXS_THREAD_INITD;
379	ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
380	ethread->func = NULL;
381	ethread->arg1 = NULL;
382	ethread->arg2 = NULL;
383	cv_signal(&ethread->cv_flag);
384
385	/* Wait for thread to end */
386	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
387		mutex_exit(&ethread->lock);
388		delay(drv_usectohz(10000));
389		mutex_enter(&ethread->lock);
390	}
391
392	mutex_exit(&ethread->lock);
393
394	cv_destroy(&ethread->cv_flag);
395	mutex_destroy(&ethread->lock);
396
397	return;
398
399}  /* emlxs_thread_destroy() */
400
401
402void
403emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
404{
405
406	/*
407	 * If the thread lock can be acquired,
408	 * it is in one of these states:
409	 * 1. Thread not started.
410	 * 2. Thread asleep.
411	 * 3. Thread busy.
412	 * 4. Thread ended.
413	 */
414	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
415		return;
416	}
417
418	mutex_enter(&ethread->lock);
419
420	if (ethread->flags & EMLXS_THREAD_ENDED) {
421		return;
422	}
423
424	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
425		mutex_exit(&ethread->lock);
426		delay(drv_usectohz(10000));
427		mutex_enter(&ethread->lock);
428
429		if (ethread->flags & EMLXS_THREAD_ENDED) {
430			return;
431		}
432	}
433
434	ethread->flags |= EMLXS_THREAD_TRIGGERED;
435	ethread->func = func;
436	ethread->arg1 = NULL;
437	ethread->arg2 = NULL;
438
439	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
440		cv_signal(&ethread->cv_flag);
441	}
442
443	mutex_exit(&ethread->lock);
444
445	return;
446
447}  /* emlxs_thread_trigger1() */
448
449
450void
451emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), RING *rp)
452{
453
454	/*
455	 * If the thread lock can be acquired,
456	 * it is in one of these states:
457	 * 1. Thread not started.
458	 * 2. Thread asleep.
459	 * 3. Thread busy.
460	 * 4. Thread ended.
461	 */
462	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
463		return;
464	}
465
466	mutex_enter(&ethread->lock);
467
468	if (ethread->flags & EMLXS_THREAD_ENDED) {
469		return;
470	}
471
472	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
473		mutex_exit(&ethread->lock);
474		delay(drv_usectohz(10000));
475		mutex_enter(&ethread->lock);
476
477		if (ethread->flags & EMLXS_THREAD_ENDED) {
478			return;
479		}
480	}
481
482	ethread->flags |= EMLXS_THREAD_TRIGGERED;
483	ethread->func = func;
484	ethread->arg1 = (void *)rp;
485	ethread->arg2 = NULL;
486
487	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
488		cv_signal(&ethread->cv_flag);
489	}
490
491	mutex_exit(&ethread->lock);
492
493	return;
494
495}  /* emlxs_thread_trigger2() */
496