|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_FREE_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: * File: wait_queue.c (adapted from sched_prim.c)
54: * Author: Avadis Tevanian, Jr.
55: * Date: 1986
56: *
57: * Primitives for manipulating wait queues: either global
58: * ones from sched_prim.c, or private ones associated with
59: * particular structures(pots, semaphores, etc..).
60: */
61:
62: #include <kern/kern_types.h>
63: #include <kern/simple_lock.h>
64: #include <kern/queue.h>
65: #include <kern/spl.h>
66:
67: #include <mach/sync_policy.h>
68:
69: #include <kern/sched_prim.h>
70: #include <kern/wait_queue.h>
71:
72: void
73: wait_queue_init(
74: wait_queue_t wq,
75: int policy)
76: {
77: wq->wq_fifo = (policy == SYNC_POLICY_FIFO);
78: wq->wq_issub = FALSE;
79: queue_init(&wq->wq_queue);
80: hw_lock_init(&wq->wq_interlock);
81: }
82:
83: void
84: wait_queue_sub_init(
85: wait_queue_sub_t wqsub,
86: int policy)
87: {
88: wait_queue_init(&wqsub->wqs_wait_queue, policy);
89: wqsub->wqs_wait_queue.wq_issub = TRUE;
90: queue_init(&wqsub->wqs_sublinks);
91: }
92:
93: void
94: wait_queue_link_init(
95: wait_queue_link_t wql)
96: {
97: queue_init(&wql->wql_links);
98: queue_init(&wql->wql_sublinks);
99: wql->wql_queue = WAIT_QUEUE_NULL;
100: wql->wql_subqueue = WAIT_QUEUE_SUB_NULL;
101: wql->wql_event = NO_EVENT;
102: }
103:
104:
105: /*
106: * Routine: wait_queue_lock
107: * Purpose:
108: * Lock the wait queue.
109: * Conditions:
110: * the appropriate spl level (if any) is already raised.
111: */
112: void
113: wait_queue_lock(
114: wait_queue_t wq)
115: {
116: #ifdef __ppc__
117: vm_offset_t pc;
118:
119: pc = GET_RETURN_PC(&wq);
120: if (!hw_lock_to(&wq->wq_interlock, LockTimeOut)) {
121: panic("wait queue deadlock detection - wq=0x%x, cpu=%d, ret=0x%x\n", wq, cpu_number(), pc);
122: }
123: #else
124: hw_lock_lock(&wq->wq_interlock);
125: #endif
126: }
127:
128: /*
129: * Routine: wait_queue_lock_try
130: * Purpose:
131: * Try to lock the wait queue without waiting
132: * Conditions:
133: * the appropriate spl level (if any) is already raised.
134: * Returns:
135: * TRUE if the lock was acquired
136: * FALSE if we would have needed to wait
137: */
138: boolean_t
139: wait_queue_lock_try(
140: wait_queue_t wq)
141: {
142: return hw_lock_try(&wq->wq_interlock);
143: }
144:
145: /*
146: * Routine: wait_queue_unlock
147: * Purpose:
148: * unlock the wait queue
149: * Conditions:
150: * The wait queue is assumed locked.
151: * appropriate spl level is still maintained
152: */
153: void
154: wait_queue_unlock(
155: wait_queue_t wq)
156: {
157: assert(hw_lock_held(&wq->wq_interlock));
158:
159: hw_lock_unlock(&wq->wq_interlock);
160: }
161:
162: int _wait_queue_subordinate; /* phoney event for subordinate wait q elements */
163:
164:
165: /*
166: * Routine: wait_queue_member_locked
167: * Purpose:
168: * Indicate if this sub queue is a member of the queue
169: * Conditions:
170: * The wait queue is locked
171: * The sub queue is just that, a sub queue
172: */
173: boolean_t
174: wait_queue_member_locked(
175: wait_queue_t wq,
176: wait_queue_sub_t wq_sub)
177: {
178: wait_queue_element_t wq_element;
179: queue_t q;
180:
181: assert(wait_queue_held(wq));
182: assert(wait_queue_is_sub(wq_sub));
183:
184: q = &wq->wq_queue;
185:
186: wq_element = (wait_queue_element_t) queue_first(q);
187: while (!queue_end(q, (queue_entry_t)wq_element)) {
188:
189: if ((wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE)) {
190: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
191:
192: if (wql->wql_subqueue == wq_sub)
193: return TRUE;
194: }
195: wq_element = (wait_queue_element_t)
196: queue_next((queue_t) wq_element);
197: }
198: return FALSE;
199: }
200:
201:
202: /*
203: * Routine: wait_queue_member
204: * Purpose:
205: * Indicate if this sub queue is a member of the queue
206: * Conditions:
207: * The sub queue is just that, a sub queue
208: */
209: boolean_t
210: wait_queue_member(
211: wait_queue_t wq,
212: wait_queue_sub_t wq_sub)
213: {
214: boolean_t ret;
215:
216: assert(wait_queue_is_sub(wq_sub));
217:
218: wait_queue_lock(wq);
219: ret = wait_queue_member_locked(wq, wq_sub);
220: wait_queue_unlock(wq);
221: return ret;
222: }
223:
224: /*
225: * Routine: wait_queue_link
226: * Purpose:
227: * Insert a subordinate wait queue into a wait queue. This
228: * requires us to link the two together using a wait_queue_link
229: * structure that we allocate.
230: * Conditions:
231: * The wait queue being inserted must be inited as a sub queue
232: * The sub waitq is not already linked
233: *
234: */
235: kern_return_t
236: wait_queue_link(
237: wait_queue_t wq,
238: wait_queue_sub_t wq_sub)
239: {
240: wait_queue_link_t wql;
241:
242: assert(wait_queue_is_sub(wq_sub));
243: assert(!wait_queue_member(wq, wq_sub));
244:
245: wql = (wait_queue_link_t) kalloc(sizeof(struct wait_queue_link));
246: if (wql == WAIT_QUEUE_LINK_NULL)
247: return KERN_RESOURCE_SHORTAGE;
248:
249: wait_queue_link_init(wql);
250:
251: wait_queue_lock(wq);
252: wqs_lock(wq_sub);
253:
254: wql->wql_queue = wq;
255: wql->wql_subqueue = wq_sub;
256: wql->wql_event = WAIT_QUEUE_SUBORDINATE;
257: queue_enter(&wq->wq_queue, wql, wait_queue_link_t, wql_links);
258: queue_enter(&wq_sub->wqs_sublinks, wql, wait_queue_link_t, wql_sublinks);
259:
260: wqs_unlock(wq_sub);
261: wait_queue_unlock(wq);
262:
263: return KERN_SUCCESS;
264: }
265:
266: /*
267: * Routine: wait_queue_unlink
268: * Purpose:
269: * Remove the linkage between a wait queue and its subordinate.
270: * Conditions:
271: * The wait queue being must be a member sub queue
272: */
273: kern_return_t
274: wait_queue_unlink(
275: wait_queue_t wq,
276: wait_queue_sub_t wq_sub)
277: {
278: wait_queue_element_t wq_element;
279: queue_t q;
280:
281: assert(wait_queue_is_sub(wq_sub));
282: assert(wait_queue_member(wq, wq_sub));
283:
284: wait_queue_lock(wq);
285: wqs_lock(wq_sub);
286:
287: q = &wq->wq_queue;
288:
289: wq_element = (wait_queue_element_t) queue_first(q);
290: while (!queue_end(q, (queue_entry_t)wq_element)) {
291:
292: if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
293: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
294: queue_t sq;
295:
296: if (wql->wql_subqueue == wq_sub) {
297: sq = &wq_sub->wqs_sublinks;
298: queue_remove(q, wql, wait_queue_link_t, wql_links);
299: queue_remove(sq, wql, wait_queue_link_t, wql_sublinks);
300: wqs_unlock(wq_sub);
301: wait_queue_unlock(wq);
302: kfree((vm_offset_t)wql,sizeof(struct wait_queue_link));
303: return;
304: }
305: }
306:
307: wq_element = (wait_queue_element_t)
308: queue_next((queue_t) wq_element);
309: }
310: panic("wait_queue_unlink");
311: }
312:
313: /*
314: * Routine: wait_queue_unlink_one
315: * Purpose:
316: * Find and unlink one subordinate wait queue
317: * Conditions:
318: * Nothing of interest locked.
319: */
320: void
321: wait_queue_unlink_one(
322: wait_queue_t wq,
323: wait_queue_sub_t *wq_subp)
324: {
325: wait_queue_element_t wq_element;
326: queue_t q;
327:
328: wait_queue_lock(wq);
329:
330: q = &wq->wq_queue;
331:
332: wq_element = (wait_queue_element_t) queue_first(q);
333: while (!queue_end(q, (queue_entry_t)wq_element)) {
334:
335: if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
336: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
337: wait_queue_sub_t wq_sub = wql->wql_subqueue;
338: queue_t sq;
339:
340: wqs_lock(wq_sub);
341: sq = &wq_sub->wqs_sublinks;
342: queue_remove(q, wql, wait_queue_link_t, wql_links);
343: queue_remove(sq, wql, wait_queue_link_t, wql_sublinks);
344: wqs_unlock(wq_sub);
345: wait_queue_unlock(wq);
346: kfree((vm_offset_t)wql,sizeof(struct wait_queue_link));
347: *wq_subp = wq_sub;
348: return;
349: }
350:
351: wq_element = (wait_queue_element_t)
352: queue_next((queue_t) wq_element);
353: }
354: wait_queue_unlock(wq);
355: *wq_subp = WAIT_QUEUE_SUB_NULL;
356: }
357:
358: /*
359: * Routine: wait_queue_assert_wait_locked
360: * Purpose:
361: * Insert the current thread into the supplied wait queue
362: * waiting for a particular event to be posted to that queue.
363: *
364: * Conditions:
365: * The wait queue is assumed locked.
366: *
367: */
368: void
369: wait_queue_assert_wait_locked(
370: wait_queue_t wq,
371: event_t event,
372: int interruptible,
373: boolean_t unlock)
374: {
375: thread_t thread = current_thread();
376: spl_t s;
377:
378: s = splsched();
379: thread_lock(thread);
380:
381: /*
382: * This is the extent to which we currently take scheduling attributes
383: * into account. If the thread is vm priviledged, we stick it at
384: * the front of the queue. Later, these queues will honor the policy
385: * value set at wait_queue_init time.
386: */
387: if (thread->vm_privilege)
388: enqueue_head(&wq->wq_queue, (queue_entry_t) thread);
389: else
390: enqueue_tail(&wq->wq_queue, (queue_entry_t) thread);
391: thread->wait_event = event;
392: thread->wait_queue = wq;
393: thread_mark_wait_locked(thread, interruptible);
394: thread_unlock(thread);
395: splx(s);
396: if (unlock)
397: wait_queue_unlock(wq);
398: }
399:
400: /*
401: * Routine: wait_queue_assert_wait
402: * Purpose:
403: * Insert the current thread into the supplied wait queue
404: * waiting for a particular event to be posted to that queue.
405: *
406: * Conditions:
407: * nothing of interest locked.
408: */
409: void
410: wait_queue_assert_wait(
411: wait_queue_t wq,
412: event_t event,
413: int interruptible)
414: {
415: spl_t s;
416:
417: s = splsched();
418: wait_queue_lock(wq);
419: wait_queue_assert_wait_locked(wq, event, interruptible, TRUE);
420: /* wait queue unlocked */
421: splx(s);
422: }
423:
424:
425: /*
426: * Routine: wait_queue_select_all
427: * Purpose:
428: * Select all threads off a wait queue that meet the
429: * supplied criteria.
430: *
431: * Conditions:
432: * at splsched
433: * wait queue locked
434: * wake_queue initialized and ready for insertion
435: * possibly recursive
436: *
437: * Returns:
438: * a queue of locked threads
439: */
440: void
441: _wait_queue_select_all(
442: wait_queue_t wq,
443: event_t event,
444: queue_t wake_queue)
445: {
446: wait_queue_element_t wq_element;
447: wait_queue_element_t wqe_next;
448: queue_t q;
449:
450: q = &wq->wq_queue;
451:
452: wq_element = (wait_queue_element_t) queue_first(q);
453: while (!queue_end(q, (queue_entry_t)wq_element)) {
454: wqe_next = (wait_queue_element_t)
455: queue_next((queue_t) wq_element);
456:
457: /*
458: * We may have to recurse if this is a compound wait queue.
459: */
460: if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
461: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
462: wait_queue_t sub_queue;
463:
464: /*
465: * We have to check the subordinate wait queue.
466: */
467: sub_queue = (wait_queue_t)wql->wql_subqueue;
468: wait_queue_lock(sub_queue);
469: if (! wait_queue_empty(sub_queue))
470: _wait_queue_select_all(sub_queue, event, wake_queue);
471: wait_queue_unlock(sub_queue);
472: } else {
473:
474: /*
475: * Otherwise, its a thread. If it is waiting on
476: * the event we are posting to this queue, pull
477: * it off the queue and stick it in out wake_queue.
478: */
479: thread_t t = (thread_t)wq_element;
480:
481: if (t->wait_event == event) {
482: thread_lock(t);
483: remqueue(q, (queue_entry_t) t);
484: enqueue (wake_queue, (queue_entry_t) t);
485: t->wait_queue = WAIT_QUEUE_NULL;
486: t->wait_event = NO_EVENT;
487: t->at_safe_point = FALSE;
488: /* returned locked */
489: }
490: }
491: wq_element = wqe_next;
492: }
493: }
494:
495: /*
496: * Routine: wait_queue_wakeup_all_locked
497: * Purpose:
498: * Wakeup some number of threads that are in the specified
499: * wait queue and waiting on the specified event.
500: * Conditions:
501: * wait queue already locked (may be released).
502: * Returns:
503: * KERN_SUCCESS - Threads were woken up
504: * KERN_NOT_WAITING - No threads were waiting <wq,event> pair
505: */
506: kern_return_t
507: wait_queue_wakeup_all_locked(
508: wait_queue_t wq,
509: event_t event,
510: int result,
511: boolean_t unlock)
512: {
513: queue_head_t wake_queue_head;
514: queue_t q = &wake_queue_head;
515: kern_return_t ret = KERN_NOT_WAITING;
516: spl_t s;
517:
518: assert(wait_queue_held(wq));
519:
520: queue_init(q);
521:
522: /*
523: * Select the threads that we will wake up. The threads
524: * are returned to us locked and cleanly removed from the
525: * wait queue.
526: */
527: s = splsched();
528: _wait_queue_select_all(wq, event, q);
529: if (unlock)
530: wait_queue_unlock(wq);
531:
532: /*
533: * For each thread, set it running.
534: */
535: while (!queue_empty (q)) {
536: thread_t thread = (thread_t) dequeue(q);
537: thread_go_locked(thread, result);
538: thread_unlock(thread);
539: ret = KERN_SUCCESS;
540: }
541: splx(s);
542: return ret;
543: }
544:
545:
546: /*
547: * Routine: wait_queue_wakeup_all
548: * Purpose:
549: * Wakeup some number of threads that are in the specified
550: * wait queue and waiting on the specified event.
551: *
552: * Conditions:
553: * Nothing locked
554: *
555: * Returns:
556: * KERN_SUCCESS - Threads were woken up
557: * KERN_NOT_WAITING - No threads were waiting <wq,event> pair
558: */
559: kern_return_t
560: wait_queue_wakeup_all(
561: wait_queue_t wq,
562: event_t event,
563: int result)
564: {
565: kern_return_t ret;
566: spl_t s;
567:
568: s = splsched();
569: wait_queue_lock(wq);
570: ret = wait_queue_wakeup_all_locked(wq, event, result, TRUE);
571: /* lock released */
572: splx(s);
573:
574: return ret;
575: }
576:
577: /*
578: * Routine: wait_queue_select_one
579: * Purpose:
580: * Select the best thread off a wait queue that meet the
581: * supplied criteria.
582: * Conditions:
583: * at splsched
584: * wait queue locked
585: * possibly recursive
586: * Returns:
587: * a locked thread - if one found
588: * Note:
589: * This is where the sync policy of the wait queue comes
590: * into effect. For now, we just assume FIFO.
591: */
592: thread_t
593: _wait_queue_select_one(
594: wait_queue_t wq,
595: event_t event)
596: {
597: wait_queue_element_t wq_element;
598: wait_queue_element_t wqe_next;
599: thread_t t = THREAD_NULL;
600: queue_t q;
601:
602: assert(wq->wq_fifo);
603:
604: q = &wq->wq_queue;
605:
606: wq_element = (wait_queue_element_t) queue_first(q);
607: while (!queue_end(q, (queue_entry_t)wq_element)) {
608: wqe_next = (wait_queue_element_t)
609: queue_next((queue_t) wq_element);
610:
611: /*
612: * We may have to recurse if this is a compound wait queue.
613: */
614: if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
615: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
616: wait_queue_t sub_queue;
617:
618: /*
619: * We have to check the subordinate wait queue.
620: */
621: sub_queue = (wait_queue_t)wql->wql_subqueue;
622: wait_queue_lock(sub_queue);
623: if (! wait_queue_empty(sub_queue)) {
624: t = _wait_queue_select_one(sub_queue, event);
625: }
626: wait_queue_unlock(sub_queue);
627: if (t != THREAD_NULL)
628: return t;
629: } else {
630:
631: /*
632: * Otherwise, its a thread. If it is waiting on
633: * the event we are posting to this queue, pull
634: * it off the queue and stick it in out wake_queue.
635: */
636: thread_t t = (thread_t)wq_element;
637:
638: if (t->wait_event == event) {
639: thread_lock(t);
640: remqueue(q, (queue_entry_t) t);
641: t->wait_queue = WAIT_QUEUE_NULL;
642: t->wait_event = NO_EVENT;
643: t->at_safe_point = FALSE;
644: return t; /* still locked */
645: }
646: }
647: wq_element = wqe_next;
648: }
649: return THREAD_NULL;
650: }
651:
652: /*
653: * Routine: wait_queue_peek_locked
654: * Purpose:
655: * Select the best thread from a wait queue that meet the
656: * supplied criteria, but leave it on the queue you it was
657: * found on. The thread, and the actual wait_queue the
658: * thread was found on are identified.
659: * Conditions:
660: * at splsched
661: * wait queue locked
662: * possibly recursive
663: * Returns:
664: * a locked thread - if one found
665: * a locked waitq - the one the thread was found on
666: * Note:
667: * Only the waitq the thread was actually found on is locked
668: * after this.
669: */
670: void
671: wait_queue_peek_locked(
672: wait_queue_t wq,
673: event_t event,
674: thread_t *tp,
675: wait_queue_t *wqp)
676: {
677: wait_queue_element_t wq_element;
678: wait_queue_element_t wqe_next;
679: thread_t t;
680: queue_t q;
681:
682: assert(wq->wq_fifo);
683:
684: *tp = THREAD_NULL;
685:
686: q = &wq->wq_queue;
687:
688: wq_element = (wait_queue_element_t) queue_first(q);
689: while (!queue_end(q, (queue_entry_t)wq_element)) {
690: wqe_next = (wait_queue_element_t)
691: queue_next((queue_t) wq_element);
692:
693: /*
694: * We may have to recurse if this is a compound wait queue.
695: */
696: if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
697: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
698: wait_queue_t sub_queue;
699:
700: /*
701: * We have to check the subordinate wait queue.
702: */
703: sub_queue = (wait_queue_t)wql->wql_subqueue;
704: wait_queue_lock(sub_queue);
705: if (! wait_queue_empty(sub_queue)) {
706: wait_queue_peek_locked(sub_queue, event, tp, wqp);
707: }
708: if (*tp != THREAD_NULL)
709: return; /* thread and its waitq locked */
710:
711: wait_queue_unlock(sub_queue);
712: } else {
713:
714: /*
715: * Otherwise, its a thread. If it is waiting on
716: * the event we are posting to this queue, return
717: * it locked, but leave it on the queue.
718: */
719: thread_t t = (thread_t)wq_element;
720:
721: if (t->wait_event == event) {
722: thread_lock(t);
723: *tp = t;
724: *wqp = wq;
725: return;
726: }
727: }
728: wq_element = wqe_next;
729: }
730: }
731:
732: /*
733: * Routine: wait_queue_pull_thread_locked
734: * Purpose:
735: * Pull a thread that was previously "peeked" off the wait
736: * queue and (possibly) unlock the waitq.
737: * Conditions:
738: * at splsched
739: * wait queue locked
740: * thread locked
741: * Returns:
742: * with the thread still locked.
743: */
744: void
745: wait_queue_pull_thread_locked(
746: wait_queue_t waitq,
747: thread_t thread,
748: boolean_t unlock)
749: {
750:
751: assert(thread->wait_queue == waitq);
752:
753: remqueue(&waitq->wq_queue, (queue_entry_t)thread );
754: thread->wait_queue = WAIT_QUEUE_NULL;
755: thread->wait_event = NO_EVENT;
756: thread->at_safe_point = FALSE;
757: if (unlock)
758: wait_queue_unlock(waitq);
759: }
760:
761:
762: /*
763: * Routine: wait_queue_select_thread
764: * Purpose:
765: * Look for a thread and remove it from the queues, if
766: * (and only if) the thread is waiting on the supplied
767: * <wait_queue, event> pair.
768: * Conditions:
769: * at splsched
770: * wait queue locked
771: * possibly recursive
772: * Returns:
773: * KERN_NOT_WAITING: Thread is not waiting here.
774: * KERN_SUCCESS: It was, and is now removed (returned locked)
775: */
776: kern_return_t
777: _wait_queue_select_thread(
778: wait_queue_t wq,
779: event_t event,
780: thread_t thread)
781: {
782: wait_queue_element_t wq_element;
783: wait_queue_element_t wqe_next;
784: kern_return_t res = KERN_NOT_WAITING;
785: queue_t q = &wq->wq_queue;
786:
787: assert(wq->wq_fifo);
788:
789: thread_lock(thread);
790: if ((thread->wait_queue == wq) && (thread->wait_event == event)) {
791: remqueue(q, (queue_entry_t) thread);
792: thread->at_safe_point = FALSE;
793: thread->wait_event = NO_EVENT;
794: thread->wait_queue = WAIT_QUEUE_NULL;
795: /* thread still locked */
796: return KERN_SUCCESS;
797: }
798: thread_unlock(thread);
799:
800: /*
801: * The wait_queue associated with the thread may be one of this
802: * wait queue's subordinates. Go see. If so, removing it from
803: * there is like removing it from here.
804: */
805: wq_element = (wait_queue_element_t) queue_first(q);
806: while (!queue_end(q, (queue_entry_t)wq_element)) {
807: wqe_next = (wait_queue_element_t)
808: queue_next((queue_t) wq_element);
809:
810: if (wq_element->wqe_event == WAIT_QUEUE_SUBORDINATE) {
811: wait_queue_link_t wql = (wait_queue_link_t)wq_element;
812: wait_queue_t sub_queue;
813:
814: sub_queue = (wait_queue_t)wql->wql_subqueue;
815: wait_queue_lock(sub_queue);
816: if (! wait_queue_empty(sub_queue)) {
817: res = _wait_queue_select_thread(sub_queue,
818: event,
819: thread);
820: }
821: wait_queue_unlock(sub_queue);
822: if (res == KERN_SUCCESS)
823: return KERN_SUCCESS;
824: }
825: wq_element = wqe_next;
826: }
827: return res;
828: }
829:
830:
831: /*
832: * Routine: wait_queue_wakeup_identity_locked
833: * Purpose:
834: * Select a single thread that is most-eligible to run and set
835: * set it running. But return the thread locked.
836: *
837: * Conditions:
838: * at splsched
839: * wait queue locked
840: * possibly recursive
841: * Returns:
842: * a pointer to the locked thread that was awoken
843: */
844: thread_t
845: wait_queue_wakeup_identity_locked(
846: wait_queue_t wq,
847: event_t event,
848: int result,
849: boolean_t unlock)
850: {
851: thread_t thread;
852: spl_t s;
853:
854: assert(wait_queue_held(wq));
855:
856: s = splsched();
857: thread = _wait_queue_select_one(wq, event);
858: if (unlock)
859: wait_queue_unlock(wq);
860:
861: if (thread) {
862: thread_go_locked(thread, result);
863: splx(s);
864: return thread; /* still locked */
865: }
866: splx(s);
867: return THREAD_NULL;
868: }
869:
870:
871: /*
872: * Routine: wait_queue_wakeup_one_locked
873: * Purpose:
874: * Select a single thread that is most-eligible to run and set
875: * set it runnings.
876: *
877: * Conditions:
878: * at splsched
879: * wait queue locked
880: * possibly recursive
881: * Returns:
882: * KERN_SUCCESS: It was, and is, now removed.
883: * KERN_NOT_WAITING - No thread was waiting <wq,event> pair
884: */
885: kern_return_t
886: wait_queue_wakeup_one_locked(
887: wait_queue_t wq,
888: event_t event,
889: int result,
890: boolean_t unlock)
891: {
892: thread_t thread;
893: spl_t s;
894:
895: assert(wait_queue_held(wq));
896:
897: s = splsched();
898: thread = _wait_queue_select_one(wq, event);
899: if (unlock)
900: wait_queue_unlock(wq);
901:
902: if (thread) {
903: thread_go_locked(thread, result);
904: thread_unlock(thread);
905: splx(s);
906: return KERN_SUCCESS;
907: }
908:
909: splx(s);
910: return KERN_NOT_WAITING;
911: }
912:
913: /*
914: * Routine: wait_queue_wakeup_one
915: * Purpose:
916: * Wakeup the most appropriate thread that is in the specified
917: * wait queue for the specified event.
918: *
919: * Conditions:
920: * Nothing locked
921: *
922: * Returns:
923: * KERN_SUCCESS - Thread was woken up
924: * KERN_NOT_WAITING - No thread was waiting <wq,event> pair
925: */
926: kern_return_t
927: wait_queue_wakeup_one(
928: wait_queue_t wq,
929: event_t event,
930: int result)
931: {
932: thread_t thread;
933: spl_t s;
934:
935: s = splsched();
936: wait_queue_lock(wq);
937: thread = _wait_queue_select_one(wq, event);
938: wait_queue_unlock(wq);
939:
940: if (thread) {
941: thread_go_locked(thread, result);
942: thread_unlock(thread);
943: splx(s);
944: return KERN_SUCCESS;
945: }
946:
947: splx(s);
948: return KERN_NOT_WAITING;
949: }
950:
951:
952:
953: /*
954: * Routine: wait_queue_wakeup_thread_locked
955: * Purpose:
956: * Wakeup the particular thread that was specified if and only
957: * it was in this wait queue (or one of it's subordinate queues)
958: * and waiting on the specified event.
959: *
960: * This is much safer than just removing the thread from
961: * whatever wait queue it happens to be on. For instance, it
962: * may have already been awoken from the wait you intended to
963: * interrupt and waited on something else (like another
964: * semaphore).
965: * Conditions:
966: * wait queue already locked (may be released).
967: * Returns:
968: * KERN_SUCCESS - the thread was found waiting and awakened
969: * KERN_NOT_WAITING - the thread was not waiting here
970: */
971: kern_return_t
972: wait_queue_wakeup_thread_locked(
973: wait_queue_t wq,
974: event_t event,
975: thread_t thread,
976: int result,
977: boolean_t unlock)
978: {
979: kern_return_t res;
980: spl_t s;
981:
982: assert(wait_queue_held(wq));
983:
984: /*
985: * See if the thread was still waiting there. If so, it got
986: * dequeued and returned locked.
987: */
988: s = splsched();
989: res = _wait_queue_select_thread(wq, event, thread);
990: if (unlock)
991: wait_queue_unlock(wq);
992:
993: if (res != KERN_SUCCESS) {
994: splx(s);
995: return KERN_NOT_WAITING;
996: }
997:
998: thread_go_locked(thread, result);
999: thread_unlock(thread);
1000: splx(s);
1001: return KERN_SUCCESS;
1002: }
1003:
1004: /*
1005: * Routine: wait_queue_wakeup_thread
1006: * Purpose:
1007: * Wakeup the particular thread that was specified if and only
1008: * it was in this wait queue (or one of it's subordinate queues)
1009: * and waiting on the specified event.
1010: *
1011: * This is much safer than just removing the thread from
1012: * whatever wait queue it happens to be on. For instance, it
1013: * may have already been awoken from the wait you intended to
1014: * interrupt and waited on something else (like another
1015: * semaphore).
1016: * Conditions:
1017: * nothing of interest locked
1018: * we need to assume spl needs to be raised
1019: * Returns:
1020: * KERN_SUCCESS - the thread was found waiting and awakened
1021: * KERN_NOT_WAITING - the thread was not waiting here
1022: */
1023: kern_return_t
1024: wait_queue_wakeup_thread(
1025: wait_queue_t wq,
1026: event_t event,
1027: thread_t thread,
1028: int result)
1029: {
1030: kern_return_t res;
1031: spl_t s;
1032:
1033: s = splsched();
1034: wait_queue_lock(wq);
1035: res = _wait_queue_select_thread(wq, event, thread);
1036: wait_queue_unlock(wq);
1037:
1038: if (res == KERN_SUCCESS) {
1039: thread_go_locked(thread, result);
1040: thread_unlock(thread);
1041: splx(s);
1042: return KERN_SUCCESS;
1043: }
1044: splx(s);
1045: return KERN_NOT_WAITING;
1046: }
1047:
1048:
1049: /*
1050: * Routine: wait_queue_remove
1051: * Purpose:
1052: * Normal removal operations from wait queues drive from the
1053: * wait queue to select a thread. However, if a thread is
1054: * interrupted out of a wait, this routine is called to
1055: * remove it from whatever wait queue it may be in.
1056: *
1057: * Conditions:
1058: * splsched
1059: * thread locked on entry and exit, but may be dropped.
1060: *
1061: * Returns:
1062: * KERN_SUCCESS - if thread was in a wait queue
1063: * KERN_NOT_WAITING - it was not
1064: */
1065: kern_return_t
1066: wait_queue_remove(
1067: thread_t thread)
1068: {
1069: wait_queue_t wq = thread->wait_queue;
1070:
1071: if (wq == WAIT_QUEUE_NULL)
1072: return KERN_NOT_WAITING;
1073:
1074: /*
1075: * have to get the locks again in the right order.
1076: */
1077: thread_unlock(thread);
1078: wait_queue_lock(wq);
1079: thread_lock(thread);
1080:
1081: if (thread->wait_queue == wq) {
1082: remqueue(&wq->wq_queue, (queue_entry_t)thread);
1083: thread->wait_queue = WAIT_QUEUE_NULL;
1084: thread->wait_event = NO_EVENT;
1085: thread->at_safe_point = FALSE;
1086: wait_queue_unlock(wq);
1087: return KERN_SUCCESS;
1088: } else {
1089: wait_queue_unlock(wq);
1090: return KERN_NOT_WAITING; /* anymore */
1091: }
1092: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.