|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1993, 1994, 1995 NeXT Computer, Inc.
27: *
28: * Thread-based callout module.
29: *
30: * 3 July 1993 ? at NeXT
31: * Created.
32: */
33:
34: #import <mach/mach_types.h>
35:
36: #import <kern/sched_prim.h>
37: #import <kern/clock.h>
38:
39: #import <kern/thread_call.h>
40: #import <kern/thread_call_private.h>
41:
42: #include <kern/kdebug.h>
43:
44: #define internal_call_num 768
45:
46: static
47: struct _thread_call
48: internal_call_storage[internal_call_num];
49:
50: static
51: simple_lock_data_t
52: thread_call_lock;
53:
54: static
55: queue_head_t
56: internal_call_free_queue,
57: pending_call_queue, delayed_call_queue;
58:
59: static int
60: pending_call_num, active_call_num,
61: call_thread_num;
62:
63: #define call_thread_min 4
64:
65: static boolean_t
66: thread_call_initialized = FALSE;
67:
68: static __inline__ _thread_call_t
69: _internal_call_allocate(void);
70:
71: static __inline__ _thread_call_t
72: thread_call_release(
73: _thread_call_t call
74: );
75:
76: static __inline__ void
77: _pending_call_enqueue(
78: _thread_call_t call
79: ),
80: _pending_call_dequeue(
81: _thread_call_t call
82: ),
83: _delayed_call_enqueue(
84: _thread_call_t call
85: ),
86: _delayed_call_dequeue(
87: _thread_call_t call
88: );
89:
90: static void __inline__
91: _set_delayed_call_timer(
92: _thread_call_t call
93: );
94:
95: static boolean_t
96: _remove_from_pending_queue(
97: thread_call_func_t func,
98: thread_call_spec_t spec,
99: boolean_t remove_all
100: ),
101: _remove_from_delayed_queue(
102: thread_call_func_t func,
103: thread_call_spec_t spec,
104: boolean_t remove_all
105: );
106:
107: static __inline__ void
108: _call_thread_wake(void);
109:
110: static void
111: _call_thread(void),
112: _call_activate_thread(void);
113:
114: static void
115: _delayed_call_interrupt(
116: tvalspec_t timestamp
117: );
118:
119: #define qe(x) ((queue_entry_t)(x))
120: #define TC(x) ((_thread_call_t)(x))
121:
122: /*
123: * Routine: thread_call_initialized [public]
124: *
125: * Description: Initialize this module, called
126: * early during system initialization.
127: *
128: * Preconditions: None.
129: *
130: * Postconditions: None.
131: */
132:
133: void
134: thread_call_init(void)
135: {
136: _thread_call_t call;
137:
138: if (thread_call_initialized)
139: panic("thread_call_init");
140:
141: simple_lock_init(&thread_call_lock);
142:
143: queue_init(&pending_call_queue);
144: queue_init(&delayed_call_queue);
145:
146: queue_init(&internal_call_free_queue);
147: for (
148: call = internal_call_storage;
149: call < &internal_call_storage[internal_call_num];
150: call++) {
151:
152: enqueue_tail(&internal_call_free_queue, qe(call));
153: }
154:
155: (void) kernel_thread(kernel_task, _call_activate_thread, (void *)0);
156:
157: timer_set_expire_func(SystemWide, (timer_func_t)_delayed_call_interrupt);
158:
159: thread_call_initialized = TRUE;
160: }
161:
162: /*
163: * Routine: _internal_call_allocate [private, inline]
164: *
165: * Purpose: Allocate an internal callout entry.
166: *
167: * Preconditions: thread_call_lock held.
168: *
169: * Postconditions: None.
170: */
171:
172: static __inline__ _thread_call_t
173: _internal_call_allocate(void)
174: {
175: _thread_call_t call;
176:
177: if (queue_empty(&internal_call_free_queue))
178: panic("_internal_call_allocate");
179:
180: call = TC(dequeue_head(&internal_call_free_queue));
181:
182: return (call);
183: }
184:
185: /*
186: * Routine: thread_call_release [private, inline]
187: *
188: * Purpose: Release a callout entry which is no
189: * longer pending (or delayed). Returns
190: * its argument for external entries, zero
191: * otherwise.
192: *
193: * Preconditions: thread_call_lock held.
194: *
195: * Postconditions: None.
196: */
197:
198: static __inline__
199: _thread_call_t
200: thread_call_release(
201: _thread_call_t call
202: )
203: {
204: if (
205: call >= internal_call_storage
206: &&
207: call < &internal_call_storage[internal_call_num]) {
208:
209: enqueue_tail(&internal_call_free_queue, qe(call)); call = 0;
210: }
211:
212: return (call);
213: }
214:
215: /*
216: * Routine: _pending_call_enqueue [private, inline]
217: *
218: * Purpose: Place an entry at the end of the
219: * pending queue, to be executed soon.
220: *
221: * Preconditions: thread_call_lock held.
222: *
223: * Postconditions: None.
224: */
225:
226: static __inline__
227: void
228: _pending_call_enqueue(
229: _thread_call_t call
230: )
231: {
232: enqueue_tail(&pending_call_queue, qe(call)); pending_call_num++;
233:
234: call->status = PENDING;
235: }
236:
237: /*
238: * Routine: _pending_call_dequeue [private, inline]
239: *
240: * Purpose: Remove an entry from the pending queue,
241: * effectively unscheduling it.
242: *
243: * Preconditions: thread_call_lock held.
244: *
245: * Postconditions: None.
246: */
247:
248: static __inline__
249: void
250: _pending_call_dequeue(
251: _thread_call_t call
252: )
253: {
254: remqueue(&pending_call_queue, qe(call)); pending_call_num--;
255:
256: call->status = IDLE;
257: }
258:
259: /*
260: * Routine: _delayed_call_enqueue [private, inline]
261: *
262: * Purpose: Place an entry on the delayed queue,
263: * after existing entries with an earlier
264: * (or identical) deadline.
265: *
266: * Preconditions: thread_call_lock held.
267: *
268: * Postconditions: None.
269: */
270:
271: static __inline__
272: void
273: _delayed_call_enqueue(
274: _thread_call_t call
275: )
276: {
277: _thread_call_t current;
278: int deadline_cmp;
279:
280: current = TC(queue_first(&delayed_call_queue));
281:
282: while (TRUE) {
283: if (
284: queue_end(&delayed_call_queue, qe(current))
285: ||
286: (deadline_cmp = CMP_TVALSPEC(&call->deadline,
287: ¤t->deadline)) < 0) {
288: current = TC(queue_prev(qe(current)));
289: break;
290: }
291: else if (deadline_cmp == 0)
292: break;
293:
294: current = TC(queue_next(qe(current)));
295: }
296:
297: insque(qe(call), qe(current));
298:
299: call->status = DELAYED;
300: }
301:
302: /*
303: * Routine: _delayed_call_dequeue [private, inline]
304: *
305: * Purpose: Remove an entry from the delayed queue,
306: * effectively unscheduling it.
307: *
308: * Preconditions: thread_call_lock held.
309: *
310: * Postconditions: None.
311: */
312:
313: static __inline__
314: void
315: _delayed_call_dequeue(
316: _thread_call_t call
317: )
318: {
319: remqueue(&delayed_call_queue, qe(call));
320:
321: call->status = IDLE;
322: }
323:
324: /*
325: * Routine: _set_delayed_call_timer [private]
326: *
327: * Purpose: Reset the timer so that it
328: * next expires when the entry is due.
329: *
330: * Preconditions: thread_call_lock held.
331: *
332: * Postconditions: None.
333: */
334:
335: static __inline__ void
336: _set_delayed_call_timer(
337: _thread_call_t call
338: )
339: {
340: timer_set_deadline(SystemWide, call->deadline);
341: }
342:
343: /*
344: * Routine: _remove_from_pending_queue [private]
345: *
346: * Purpose: Remove the first (or all) matching
347: * entries from the pending queue,
348: * effectively unscheduling them.
349: * Returns whether any matching entries
350: * were found for the !removeAll case,
351: * FALSE otherwise.
352: *
353: * Preconditions: thread_call_lock held.
354: *
355: * Postconditions: None.
356: */
357:
358: static
359: boolean_t
360: _remove_from_pending_queue(
361: thread_call_func_t func,
362: thread_call_spec_t spec,
363: boolean_t remove_all
364: )
365: {
366: boolean_t call_removed = FALSE;
367: _thread_call_t call;
368:
369: call = TC(queue_first(&pending_call_queue));
370:
371: while (!queue_end(&pending_call_queue, qe(call))) {
372: if (
373: call->func == func
374: &&
375: call->spec == spec) {
376: _thread_call_t next = TC(queue_next(qe(call)));
377:
378: _pending_call_dequeue(call);
379:
380: thread_call_release(call);
381:
382: call_removed = TRUE;
383: if (!remove_all)
384: break;
385:
386: call = next;
387: }
388: else
389: call = TC(queue_next(qe(call)));
390: }
391:
392: return (!remove_all? call_removed : FALSE);
393: }
394:
395: /*
396: * Routine: _remove_from_delayed_queue [private]
397: *
398: * Purpose: Remove the first (or all) matching
399: * entries from the delayed queue,
400: * effectively unscheduling them.
401: * Returns whether any matching entries
402: * were found for the !removeAll case,
403: * FALSE otherwise.
404: *
405: * Preconditions: thread_call_lock held.
406: *
407: * Postconditions: None.
408: */
409:
410: static
411: boolean_t
412: _remove_from_delayed_queue(
413: thread_call_func_t func,
414: thread_call_spec_t spec,
415: boolean_t remove_all
416: )
417: {
418: boolean_t call_removed = FALSE;
419: _thread_call_t call;
420:
421: call = TC(queue_first(&delayed_call_queue));
422:
423: while (!queue_end(&delayed_call_queue, qe(call))) {
424: if (
425: call->func == func
426: &&
427: call->spec == spec) {
428: _thread_call_t next = TC(queue_next(qe(call)));
429:
430: _delayed_call_dequeue(call);
431:
432: thread_call_release(call);
433:
434: call_removed = TRUE;
435: if (!remove_all)
436: break;
437:
438: call = next;
439: }
440: else
441: call = TC(queue_next(qe(call)));
442: }
443:
444: return (!remove_all? call_removed : FALSE);
445: }
446:
447: tvalspec_t
448: deadline_from_interval(
449: tvalspec_t interval
450: )
451: {
452: tvalspec_t result = clock_get_counter(System);
453:
454: ADD_TVALSPEC(&result, &interval);
455:
456: return (result);
457: }
458:
459: /*
460: * Routine: thread_call_func [public]
461: *
462: * Purpose: Schedule a function callout.
463: * Guarantees { function, argument }
464: * uniqueness if unique_call is TRUE.
465: *
466: * Preconditions: Callable from an interrupt context
467: * below splsched.
468: *
469: * Postconditions: None.
470: */
471:
472: void
473: thread_call_func(
474: thread_call_func_t func,
475: thread_call_spec_t spec,
476: boolean_t unique_call
477: )
478: {
479: _thread_call_t call;
480: int s;
481:
482: if (!thread_call_initialized)
483: panic("thread_call_func_unique");
484:
485: s = splsched();
486:
487: simple_lock(&thread_call_lock);
488:
489: call = TC(queue_first(&pending_call_queue));
490:
491: if (unique_call) while (!queue_end(&pending_call_queue, qe(call))) {
492: if (
493: call->func == func
494: &&
495: call->spec == spec) {
496:
497: break;
498: }
499:
500: call = TC(queue_next(qe(call)));
501: }
502:
503: if (!unique_call || queue_end(&pending_call_queue, qe(call))) {
504:
505: call = _internal_call_allocate();
506:
507: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT),
508: 0, call->func, call->spec,
509: 0, 0);
510: call->func = func;
511: call->spec = spec;
512: call->spec_proto = 0;
513:
514: _pending_call_enqueue(call);
515:
516: _call_thread_wake();
517: }
518: else
519: simple_unlock(&thread_call_lock);
520:
521: splx(s);
522: }
523:
524: /*
525: * Routine: thread_call_func_delayed [public]
526: *
527: * Purpose: Schedule a function callout to
528: * occur at the stated time.
529: *
530: * Preconditions: Callable from an interrupt context
531: * below splsched.
532: *
533: * Postconditions: None.
534: */
535:
536: void
537: thread_call_func_delayed(
538: thread_call_func_t func,
539: thread_call_spec_t spec,
540: tvalspec_t deadline
541: )
542: {
543: _thread_call_t call;
544: int s;
545:
546: if (!thread_call_initialized)
547: panic("thread_call_func_delayed");
548:
549: if (BAD_TVALSPEC(&deadline))
550: deadline = TVALSPEC_ZERO;
551:
552: s = splsched();
553:
554: simple_lock(&thread_call_lock);
555:
556: call = _internal_call_allocate();
557:
558: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT),
559: 1, func, spec,
560: deadline.tv_sec, deadline.tv_nsec);
561: call->func = func;
562: call->spec = spec;
563: call->spec_proto = 0;
564: call->deadline = deadline;
565:
566: _delayed_call_enqueue(call);
567:
568: if (queue_first(&delayed_call_queue) == qe(call))
569: _set_delayed_call_timer(call);
570:
571: simple_unlock(&thread_call_lock);
572:
573: splx(s);
574: }
575:
576: /*
577: * Routine: thread_call_func_cancel [public]
578: *
579: * Purpose: Unschedule a function callout.
580: * Removes one (or all)
581: * { function, argument }
582: * instance(s) from either (or both)
583: * the pending and the delayed queue,
584: * in that order.
585: *
586: * Preconditions: Callable from an interrupt context
587: * below splsched.
588: *
589: * Postconditions: None.
590: */
591:
592: void
593: thread_call_func_cancel(
594: thread_call_func_t func,
595: thread_call_spec_t spec,
596: boolean_t cancel_all
597: )
598: {
599: int s;
600:
601: s = splsched();
602:
603: simple_lock(&thread_call_lock);
604:
605: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT),
606: 2, func, spec,
607: cancel_all, 0);
608: _remove_from_pending_queue(func, spec, cancel_all) ||
609: _remove_from_delayed_queue(func, spec, cancel_all);
610:
611: simple_unlock(&thread_call_lock);
612:
613: splx(s);
614: }
615:
616: /*
617: * Routine: thread_call_allocate [public]
618: *
619: * Purpose: Allocate an external callout
620: * entry.
621: *
622: * Preconditions: None.
623: *
624: * Postconditions: None.
625: */
626:
627: thread_call_t
628: thread_call_allocate(
629: thread_call_func_t func,
630: thread_call_spec_t spec
631: )
632: {
633: _thread_call_t call = (void *)kalloc(sizeof (struct _thread_call));
634:
635: call->func = func;
636: call->spec = 0;
637: call->spec_proto = spec;
638: call->deadline = TVALSPEC_ZERO;
639: call->status = IDLE;
640:
641: return (call);
642: }
643:
644: /*
645: * Routine: thread_call_free [public]
646: *
647: * Purpose: Free an external callout
648: * entry.
649: *
650: * Preconditions: None.
651: *
652: * Postconditions: None.
653: */
654:
655: void
656: thread_call_free(
657: thread_call_t _call
658: )
659: {
660: _thread_call_t call = _call;
661: int s;
662:
663: s = splsched();
664:
665: simple_lock(&thread_call_lock);
666:
667: if (call->status != IDLE) {
668: simple_unlock(&thread_call_lock);
669: panic("thread_call_free");
670: }
671:
672: simple_unlock(&thread_call_lock);
673:
674: splx(s);
675:
676: kfree((void *)call, sizeof (struct _thread_call));
677: }
678:
679: /*
680: * Routine: thread_call_enter [public]
681: *
682: * Purpose: Schedule an external callout
683: * entry. There is no effect if
684: * the entry is not idle.
685: *
686: * Preconditions: Callable from an interrupt context
687: * below splsched.
688: *
689: * Postconditions: None.
690: */
691:
692: void
693: thread_call_enter(
694: thread_call_t _call
695: )
696: {
697: _thread_call_t call = _call;
698: int s;
699:
700: s = splsched();
701:
702: simple_lock(&thread_call_lock);
703:
704: if (call->status == IDLE) {
705: call->spec = call->spec_proto;
706:
707: _pending_call_enqueue(call);
708:
709: _call_thread_wake();
710: }
711: else
712: simple_unlock(&thread_call_lock);
713:
714: splx(s);
715: }
716:
717: void
718: thread_call_enter_spec(
719: thread_call_t _call,
720: thread_call_spec_t spec
721: )
722: {
723: _thread_call_t call = _call;
724: int s;
725:
726: s = splsched();
727:
728: simple_lock(&thread_call_lock);
729:
730: if (call->status == IDLE) {
731: call->spec = spec;
732:
733: _pending_call_enqueue(call);
734:
735: _call_thread_wake();
736: }
737: else
738: simple_unlock(&thread_call_lock);
739:
740: splx(s);
741: }
742:
743: /*
744: * Routine: thread_call_enter_delayed [public]
745: *
746: * Purpose: Schedule an external callout
747: * entry to occur at the stated time.
748: * There is no effect if the entry
749: * is not idle.
750: *
751: * Preconditions: Callable from an interrupt context
752: * below splsched.
753: *
754: * Postconditions: None.
755: */
756:
757: void
758: thread_call_enter_delayed(
759: thread_call_t _call,
760: tvalspec_t deadline
761: )
762: {
763: _thread_call_t call = _call;
764: int s;
765:
766: if (BAD_TVALSPEC(&deadline))
767: deadline = TVALSPEC_ZERO;
768:
769: s = splsched();
770:
771: simple_lock(&thread_call_lock);
772:
773: if (call->status == IDLE) {
774: call->spec = call->spec_proto;
775: call->deadline = deadline;
776:
777: _delayed_call_enqueue(call);
778:
779: if (queue_first(&delayed_call_queue) == qe(call))
780: _set_delayed_call_timer(call);
781: }
782:
783: simple_unlock(&thread_call_lock);
784:
785: splx(s);
786: }
787:
788: void
789: thread_call_enter_spec_delayed(
790: thread_call_t _call,
791: thread_call_spec_t spec,
792: tvalspec_t deadline
793: )
794: {
795: _thread_call_t call = _call;
796: int s;
797:
798: if (BAD_TVALSPEC(&deadline))
799: deadline = TVALSPEC_ZERO;
800:
801: s = splsched();
802:
803: simple_lock(&thread_call_lock);
804:
805: if (call->status == IDLE) {
806: call->spec = spec;
807: call->deadline = deadline;
808:
809: _delayed_call_enqueue(call);
810:
811: if (queue_first(&delayed_call_queue) == qe(call))
812: _set_delayed_call_timer(call);
813: }
814:
815: simple_unlock(&thread_call_lock);
816:
817: splx(s);
818: }
819:
820: /*
821: * Routine: thread_call_cancel [public]
822: *
823: * Purpose: Unschedule a callout entry.
824: * There is no effect if the
825: * entry is already idle.
826: *
827: * Preconditions: Callable from an interrupt context
828: * below splsched.
829: *
830: * Postconditions: None.
831: */
832:
833: void
834: thread_call_cancel(
835: thread_call_t _call
836: )
837: {
838: _thread_call_t call = _call;
839: int s;
840:
841: s = splsched();
842:
843: simple_lock(&thread_call_lock);
844:
845: if (call->status == PENDING) {
846: _pending_call_dequeue(call);
847:
848: thread_call_release(call);
849: }
850: else if (call->status == DELAYED) {
851: _delayed_call_dequeue(call);
852:
853: thread_call_release(call);
854: }
855: else
856: /* do nothing */;
857:
858: simple_unlock(&thread_call_lock);
859:
860: splx(s);
861: }
862:
863: /*
864: * Routine: _call_thread_wake [private]
865: *
866: * Purpose: Wakeup one callout thread to handle
867: * a new callout entry. May wakeup
868: * the callout activate thread to
869: * create a new callout thread.
870: *
871: * Preconditions: thread_call_lock held.
872: *
873: * Postconditions: thread_call_lock released.
874: */
875:
876: static __inline__
877: void
878: _call_thread_wake(void)
879: {
880: boolean_t wake_activate_thread = FALSE;
881:
882: if (call_thread_num < (active_call_num + pending_call_num))
883: wake_activate_thread = TRUE;
884:
885: simple_unlock(&thread_call_lock);
886:
887: thread_wakeup_one(&pending_call_num);
888:
889: if (wake_activate_thread)
890: thread_wakeup_one(&call_thread_num);
891: }
892:
893: /*
894: * Routine: _call_thread [private]
895: *
896: * Purpose: Executed by a callout thread.
897: *
898: * Preconditions: None.
899: *
900: * Postconditions: None.
901: */
902:
903: static
904: void
905: _call_thread_continue(void)
906: {
907: thread_t self = current_thread();
908:
909: (void) splsched();
910:
911: simple_lock(&thread_call_lock);
912:
913: while (pending_call_num > 0) {
914: _thread_call_t call;
915: thread_call_func_t func;
916: thread_call_spec_t spec;
917:
918: call = TC(dequeue_head(&pending_call_queue)); pending_call_num--;
919:
920: func = call->func;
921: spec = call->spec;
922:
923: call->status = IDLE;
924:
925: call = thread_call_release(call);
926:
927: active_call_num++; simple_unlock(&thread_call_lock);
928:
929: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT) | DBG_FUNC_START,
930: 3, self, func,
931: spec, 0);
932:
933: (void) spl0(); (*func)(spec, call); (void) splsched();
934:
935: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_CALLOUT) | DBG_FUNC_END,
936: 4, self,
937: func, spec,
938: 0);
939:
940: simple_lock(&thread_call_lock); active_call_num--;
941: }
942:
943: if ((call_thread_num - active_call_num) <= call_thread_min) {
944:
945: assert_wait(&pending_call_num, FALSE);
946:
947: simple_unlock(&thread_call_lock);
948:
949: thread_block_with_continuation(_call_thread_continue);
950: /* NOTREACHED */
951: }
952:
953: call_thread_num--;
954:
955: simple_unlock(&thread_call_lock);
956:
957: (void) spl0();
958:
959: (void) thread_terminate(self); thread_halt_self();
960: }
961:
962: static
963: void
964: _call_thread(void)
965: {
966: stack_privilege(current_thread());
967:
968: _call_thread_continue();
969: /* NOTREACHED */
970: }
971:
972: /*
973: * Routine: _call_activate_thread [private]
974: *
975: * Purpose: Executed by the callout activate thread.
976: *
977: * Preconditions: None.
978: *
979: * Postconditions: Never terminates.
980: */
981:
982: static
983: void
984: _call_activate_thread_continue(void)
985: {
986: thread_t self = current_thread();
987:
988: (void) splsched();
989:
990: simple_lock(&thread_call_lock);
991:
992: if (call_thread_num < (active_call_num + pending_call_num)) {
993:
994: call_thread_num++; simple_unlock(&thread_call_lock);
995:
996: (void) kernel_thread(self->task, _call_thread, (void *)0);
997:
998: thread_block_with_continuation(_call_activate_thread_continue);
999: /* NOTREACHED */
1000: }
1001:
1002: assert_wait(&call_thread_num, FALSE);
1003:
1004: simple_unlock(&thread_call_lock);
1005:
1006: thread_block_with_continuation(_call_activate_thread_continue);
1007: /* NOTREACHED */
1008: }
1009:
1010: static
1011: void
1012: _call_activate_thread(void)
1013: {
1014: stack_privilege(current_thread());
1015:
1016: _call_activate_thread_continue();
1017: /* NOTREACHED */
1018: }
1019:
1020: static
1021: void
1022: _delayed_call_interrupt(
1023: tvalspec_t timestamp
1024: )
1025: {
1026: _thread_call_t call;
1027: queue_head_t intransit_call_queue;
1028: int s;
1029:
1030: queue_init(&intransit_call_queue);
1031:
1032: s = splsched();
1033:
1034: simple_lock(&thread_call_lock);
1035:
1036: call = TC(queue_first(&delayed_call_queue));
1037:
1038: while (!queue_end(&delayed_call_queue, qe(call))) {
1039: if (CMP_TVALSPEC(&call->deadline, ×tamp) <= 0) {
1040: _delayed_call_dequeue(call);
1041:
1042: enqueue_tail(&intransit_call_queue, qe(call));
1043: }
1044: else
1045: break;
1046:
1047: call = TC(queue_first(&delayed_call_queue));
1048: }
1049:
1050: if (!queue_end(&delayed_call_queue, qe(call)))
1051: _set_delayed_call_timer(call);
1052:
1053: while (call = TC(dequeue_head(&intransit_call_queue))) {
1054: _pending_call_enqueue(call);
1055:
1056: _call_thread_wake();
1057:
1058: simple_lock(&thread_call_lock);
1059: }
1060:
1061: simple_unlock(&thread_call_lock);
1062:
1063: splx(s);
1064: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.