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