2 * Copyright (c) 1993-1995, 1999-2000 Apple Computer, Inc.
5 * @APPLE_LICENSE_HEADER_START@
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.
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
21 * @APPLE_LICENSE_HEADER_END@
24 * Thread-based callout module.
29 * Pulled into Mac OS X (microkernel).
35 #include <mach/mach_types.h>
37 #include <kern/sched_prim.h>
38 #include <kern/clock.h>
39 #include <kern/task.h>
40 #include <kern/thread.h>
42 #include <kern/thread_call.h>
43 #include <kern/call_entry.h>
45 #include <kern/timer_call.h>
47 #define internal_call_num 768
49 #define thread_call_thread_min 4
53 internal_call_storage
[internal_call_num
];
55 decl_simple_lock_data(static,thread_call_lock
)
59 thread_call_delayed_timer
;
63 internal_call_free_queue
,
64 pending_call_queue
, delayed_call_queue
;
68 call_thread_idle_queue
;
76 activate_thread_awake
;
93 thread_call_initialized
= FALSE
;
95 static __inline__ thread_call_t
96 _internal_call_allocate(void);
98 static __inline__
void
99 _internal_call_release(
103 static __inline__
void
104 _pending_call_enqueue(
107 _pending_call_dequeue(
110 _delayed_call_enqueue(
113 _delayed_call_dequeue(
117 static void __inline__
118 _set_delayed_call_timer(
123 _remove_from_pending_queue(
124 thread_call_func_t func
,
125 thread_call_param_t param0
,
128 _remove_from_delayed_queue(
129 thread_call_func_t func
,
130 thread_call_param_t param0
,
134 static __inline__
void
135 _call_thread_wake(void);
139 _activate_thread(void);
143 timer_call_param_t p0
,
144 timer_call_param_t p1
147 #define qe(x) ((queue_entry_t)(x))
148 #define TC(x) ((thread_call_t)(x))
151 * Routine: thread_call_initialize [public]
153 * Description: Initialize this module, called
154 * early during system initialization.
156 * Preconditions: None.
158 * Postconditions: None.
162 thread_call_initialize(void)
167 if (thread_call_initialized
)
168 panic("thread_call_initialize");
170 simple_lock_init(&thread_call_lock
, ETAP_MISC_TIMER
);
173 simple_lock(&thread_call_lock
);
175 queue_init(&pending_call_queue
);
176 queue_init(&delayed_call_queue
);
178 queue_init(&internal_call_free_queue
);
180 call
= internal_call_storage
;
181 call
< &internal_call_storage
[internal_call_num
];
184 enqueue_tail(&internal_call_free_queue
, qe(call
));
187 timer_call_setup(&thread_call_delayed_timer
, _delayed_call_timer
, NULL
);
189 wait_queue_init(&call_thread_idle_queue
, SYNC_POLICY_FIFO
);
190 thread_calls
.thread_lowat
= thread_call_thread_min
;
192 activate_thread_awake
= TRUE
;
193 thread_call_initialized
= TRUE
;
195 simple_unlock(&thread_call_lock
);
198 activate_thread
= kernel_thread_with_priority(
199 kernel_task
, MAXPRI_KERNEL
- 2,
200 _activate_thread
, TRUE
, TRUE
);
206 thread_call_func_t func
,
207 thread_call_param_t param0
210 call_entry_setup(call
, func
, param0
);
214 * Routine: _internal_call_allocate [private, inline]
216 * Purpose: Allocate an internal callout entry.
218 * Preconditions: thread_call_lock held.
220 * Postconditions: None.
223 static __inline__ thread_call_t
224 _internal_call_allocate(void)
228 if (queue_empty(&internal_call_free_queue
))
229 panic("_internal_call_allocate");
231 call
= TC(dequeue_head(&internal_call_free_queue
));
237 * Routine: _internal_call_release [private, inline]
239 * Purpose: Release an internal callout entry which
240 * is no longer pending (or delayed).
242 * Preconditions: thread_call_lock held.
244 * Postconditions: None.
249 _internal_call_release(
253 if ( call
>= internal_call_storage
&&
254 call
< &internal_call_storage
[internal_call_num
] )
255 enqueue_tail(&internal_call_free_queue
, qe(call
));
259 * Routine: _pending_call_enqueue [private, inline]
261 * Purpose: Place an entry at the end of the
262 * pending queue, to be executed soon.
264 * Preconditions: thread_call_lock held.
266 * Postconditions: None.
271 _pending_call_enqueue(
275 enqueue_tail(&pending_call_queue
, qe(call
));
276 if (++thread_calls
.pending_num
> thread_calls
.pending_hiwat
)
277 thread_calls
.pending_hiwat
= thread_calls
.pending_num
;
279 call
->state
= PENDING
;
283 * Routine: _pending_call_dequeue [private, inline]
285 * Purpose: Remove an entry from the pending queue,
286 * effectively unscheduling it.
288 * Preconditions: thread_call_lock held.
290 * Postconditions: None.
295 _pending_call_dequeue(
299 (void)remque(qe(call
));
300 thread_calls
.pending_num
--;
306 * Routine: _delayed_call_enqueue [private, inline]
308 * Purpose: Place an entry on the delayed queue,
309 * after existing entries with an earlier
310 * (or identical) deadline.
312 * Preconditions: thread_call_lock held.
314 * Postconditions: None.
319 _delayed_call_enqueue(
323 thread_call_t current
;
325 current
= TC(queue_first(&delayed_call_queue
));
328 if ( queue_end(&delayed_call_queue
, qe(current
)) ||
329 call
->deadline
< current
->deadline
) {
330 current
= TC(queue_prev(qe(current
)));
334 current
= TC(queue_next(qe(current
)));
337 insque(qe(call
), qe(current
));
338 if (++thread_calls
.delayed_num
> thread_calls
.delayed_hiwat
)
339 thread_calls
.delayed_hiwat
= thread_calls
.delayed_num
;
341 call
->state
= DELAYED
;
345 * Routine: _delayed_call_dequeue [private, inline]
347 * Purpose: Remove an entry from the delayed queue,
348 * effectively unscheduling it.
350 * Preconditions: thread_call_lock held.
352 * Postconditions: None.
357 _delayed_call_dequeue(
361 (void)remque(qe(call
));
362 thread_calls
.delayed_num
--;
368 * Routine: _set_delayed_call_timer [private]
370 * Purpose: Reset the timer so that it
371 * next expires when the entry is due.
373 * Preconditions: thread_call_lock held.
375 * Postconditions: None.
378 static __inline__
void
379 _set_delayed_call_timer(
383 timer_call_enter(&thread_call_delayed_timer
, call
->deadline
);
387 * Routine: _remove_from_pending_queue [private]
389 * Purpose: Remove the first (or all) matching
390 * entries from the pending queue,
391 * effectively unscheduling them.
392 * Returns whether any matching entries
395 * Preconditions: thread_call_lock held.
397 * Postconditions: None.
402 _remove_from_pending_queue(
403 thread_call_func_t func
,
404 thread_call_param_t param0
,
408 boolean_t call_removed
= FALSE
;
411 call
= TC(queue_first(&pending_call_queue
));
413 while (!queue_end(&pending_call_queue
, qe(call
))) {
414 if ( call
->func
== func
&&
415 call
->param0
== param0
) {
416 thread_call_t next
= TC(queue_next(qe(call
)));
418 _pending_call_dequeue(call
);
420 _internal_call_release(call
);
429 call
= TC(queue_next(qe(call
)));
432 return (call_removed
);
436 * Routine: _remove_from_delayed_queue [private]
438 * Purpose: Remove the first (or all) matching
439 * entries from the delayed queue,
440 * effectively unscheduling them.
441 * Returns whether any matching entries
444 * Preconditions: thread_call_lock held.
446 * Postconditions: None.
451 _remove_from_delayed_queue(
452 thread_call_func_t func
,
453 thread_call_param_t param0
,
457 boolean_t call_removed
= FALSE
;
460 call
= TC(queue_first(&delayed_call_queue
));
462 while (!queue_end(&delayed_call_queue
, qe(call
))) {
463 if ( call
->func
== func
&&
464 call
->param0
== param0
) {
465 thread_call_t next
= TC(queue_next(qe(call
)));
467 _delayed_call_dequeue(call
);
469 _internal_call_release(call
);
478 call
= TC(queue_next(qe(call
)));
481 return (call_removed
);
485 * Routine: thread_call_func [public]
487 * Purpose: Schedule a function callout.
488 * Guarantees { function, argument }
489 * uniqueness if unique_call is TRUE.
491 * Preconditions: Callable from an interrupt context
494 * Postconditions: None.
499 thread_call_func_t func
,
500 thread_call_param_t param
,
501 boolean_t unique_call
507 if (!thread_call_initialized
)
508 panic("thread_call_func");
511 simple_lock(&thread_call_lock
);
513 call
= TC(queue_first(&pending_call_queue
));
515 while (unique_call
&& !queue_end(&pending_call_queue
, qe(call
))) {
516 if ( call
->func
== func
&&
517 call
->param0
== param
) {
521 call
= TC(queue_next(qe(call
)));
524 if (!unique_call
|| queue_end(&pending_call_queue
, qe(call
))) {
525 call
= _internal_call_allocate();
527 call
->param0
= param
;
530 _pending_call_enqueue(call
);
532 if (thread_calls
.active_num
<= 0)
536 simple_unlock(&thread_call_lock
);
541 * Routine: thread_call_func_delayed [public]
543 * Purpose: Schedule a function callout to
544 * occur at the stated time.
546 * Preconditions: Callable from an interrupt context
549 * Postconditions: None.
553 thread_call_func_delayed(
554 thread_call_func_t func
,
555 thread_call_param_t param
,
562 if (!thread_call_initialized
)
563 panic("thread_call_func_delayed");
566 simple_lock(&thread_call_lock
);
568 call
= _internal_call_allocate();
570 call
->param0
= param
;
572 call
->deadline
= deadline
;
574 _delayed_call_enqueue(call
);
576 if (queue_first(&delayed_call_queue
) == qe(call
))
577 _set_delayed_call_timer(call
);
579 simple_unlock(&thread_call_lock
);
584 * Routine: thread_call_func_cancel [public]
586 * Purpose: Unschedule a function callout.
587 * Removes one (or all)
588 * { function, argument }
589 * instance(s) from either (or both)
590 * the pending and the delayed queue,
591 * in that order. Returns a boolean
592 * indicating whether any calls were
595 * Preconditions: Callable from an interrupt context
598 * Postconditions: None.
602 thread_call_func_cancel(
603 thread_call_func_t func
,
604 thread_call_param_t param
,
612 simple_lock(&thread_call_lock
);
615 result
= _remove_from_pending_queue(func
, param
, cancel_all
) |
616 _remove_from_delayed_queue(func
, param
, cancel_all
);
618 result
= _remove_from_pending_queue(func
, param
, cancel_all
) ||
619 _remove_from_delayed_queue(func
, param
, cancel_all
);
621 simple_unlock(&thread_call_lock
);
628 * Routine: thread_call_allocate [public]
630 * Purpose: Allocate an external callout
633 * Preconditions: None.
635 * Postconditions: None.
639 thread_call_allocate(
640 thread_call_func_t func
,
641 thread_call_param_t param0
644 thread_call_t call
= (void *)kalloc(sizeof (thread_call_data_t
));
647 call
->param0
= param0
;
654 * Routine: thread_call_free [public]
656 * Purpose: Free an external callout
659 * Preconditions: None.
661 * Postconditions: None.
672 simple_lock(&thread_call_lock
);
674 if (call
->state
!= IDLE
) {
675 simple_unlock(&thread_call_lock
);
681 simple_unlock(&thread_call_lock
);
684 kfree((vm_offset_t
)call
, sizeof (thread_call_data_t
));
690 * Routine: thread_call_enter [public]
692 * Purpose: Schedule an external callout
693 * entry to occur "soon". Returns a
694 * boolean indicating whether the call
695 * had been already scheduled.
697 * Preconditions: Callable from an interrupt context
700 * Postconditions: None.
708 boolean_t result
= TRUE
;
712 simple_lock(&thread_call_lock
);
714 if (call
->state
!= PENDING
) {
715 if (call
->state
== DELAYED
)
716 _delayed_call_dequeue(call
);
717 else if (call
->state
== IDLE
)
720 _pending_call_enqueue(call
);
722 if (thread_calls
.active_num
<= 0)
728 simple_unlock(&thread_call_lock
);
737 thread_call_param_t param1
740 boolean_t result
= TRUE
;
744 simple_lock(&thread_call_lock
);
746 if (call
->state
!= PENDING
) {
747 if (call
->state
== DELAYED
)
748 _delayed_call_dequeue(call
);
749 else if (call
->state
== IDLE
)
752 _pending_call_enqueue(call
);
754 if (thread_calls
.active_num
<= 0)
758 call
->param1
= param1
;
760 simple_unlock(&thread_call_lock
);
767 * Routine: thread_call_enter_delayed [public]
769 * Purpose: Schedule an external callout
770 * entry to occur at the stated time.
771 * Returns a boolean indicating whether
772 * the call had been already scheduled.
774 * Preconditions: Callable from an interrupt context
777 * Postconditions: None.
781 thread_call_enter_delayed(
786 boolean_t result
= TRUE
;
790 simple_lock(&thread_call_lock
);
792 if (call
->state
== PENDING
)
793 _pending_call_dequeue(call
);
794 else if (call
->state
== DELAYED
)
795 _delayed_call_dequeue(call
);
796 else if (call
->state
== IDLE
)
800 call
->deadline
= deadline
;
802 _delayed_call_enqueue(call
);
804 if (queue_first(&delayed_call_queue
) == qe(call
))
805 _set_delayed_call_timer(call
);
807 simple_unlock(&thread_call_lock
);
814 thread_call_enter1_delayed(
816 thread_call_param_t param1
,
820 boolean_t result
= TRUE
;
824 simple_lock(&thread_call_lock
);
826 if (call
->state
== PENDING
)
827 _pending_call_dequeue(call
);
828 else if (call
->state
== DELAYED
)
829 _delayed_call_dequeue(call
);
830 else if (call
->state
== IDLE
)
833 call
->param1
= param1
;
834 call
->deadline
= deadline
;
836 _delayed_call_enqueue(call
);
838 if (queue_first(&delayed_call_queue
) == qe(call
))
839 _set_delayed_call_timer(call
);
841 simple_unlock(&thread_call_lock
);
848 * Routine: thread_call_cancel [public]
850 * Purpose: Unschedule a callout entry.
851 * Returns a boolean indicating
852 * whether the call had actually
855 * Preconditions: Callable from an interrupt context
858 * Postconditions: None.
866 boolean_t result
= TRUE
;
870 simple_lock(&thread_call_lock
);
872 if (call
->state
== PENDING
)
873 _pending_call_dequeue(call
);
874 else if (call
->state
== DELAYED
)
875 _delayed_call_dequeue(call
);
879 simple_unlock(&thread_call_lock
);
886 * Routine: thread_call_is_delayed [public]
888 * Purpose: Returns a boolean indicating
889 * whether a call is currently scheduled
890 * to occur at a later time. Optionally
891 * returns the expiration time.
893 * Preconditions: Callable from an interrupt context
896 * Postconditions: None.
900 thread_call_is_delayed(
904 boolean_t result
= FALSE
;
908 simple_lock(&thread_call_lock
);
910 if (call
->state
== DELAYED
) {
911 if (deadline
!= NULL
)
912 *deadline
= call
->deadline
;
916 simple_unlock(&thread_call_lock
);
923 * Routine: _call_thread_wake [private, inline]
925 * Purpose: Wake a callout thread to service
926 * pending callout entries. May wake
927 * the activate thread in order to
928 * create additional callout threads.
930 * Preconditions: thread_call_lock held.
932 * Postconditions: None.
937 _call_thread_wake(void)
939 if (wait_queue_wakeup_one(
940 &call_thread_idle_queue
, &call_thread_idle_queue
,
941 THREAD_AWAKENED
) == KERN_SUCCESS
) {
942 thread_calls
.idle_thread_num
--;
944 if (++thread_calls
.active_num
> thread_calls
.active_hiwat
)
945 thread_calls
.active_hiwat
= thread_calls
.active_num
;
948 if (!activate_thread_awake
) {
949 clear_wait(activate_thread
, THREAD_AWAKENED
);
950 activate_thread_awake
= TRUE
;
955 * Routine: call_thread_block [private]
957 * Purpose: Hook via thread dispatch on
958 * the occasion of a callout blocking.
960 * Preconditions: splsched.
962 * Postconditions: None.
966 call_thread_block(void)
968 simple_lock(&thread_call_lock
);
970 if (--thread_calls
.active_num
< thread_calls
.active_lowat
)
971 thread_calls
.active_lowat
= thread_calls
.active_num
;
973 if ( thread_calls
.active_num
<= 0 &&
974 thread_calls
.pending_num
> 0 )
977 simple_unlock(&thread_call_lock
);
981 * Routine: call_thread_unblock [private]
983 * Purpose: Hook via thread wakeup on
984 * the occasion of a callout unblocking.
986 * Preconditions: splsched.
988 * Postconditions: None.
992 call_thread_unblock(void)
994 simple_lock(&thread_call_lock
);
996 if (++thread_calls
.active_num
> thread_calls
.active_hiwat
)
997 thread_calls
.active_hiwat
= thread_calls
.active_num
;
999 simple_unlock(&thread_call_lock
);
1003 * Routine: _call_thread [private]
1005 * Purpose: Executed by a callout thread.
1007 * Preconditions: None.
1009 * Postconditions: None.
1014 _call_thread_continue(void)
1016 thread_t self
= current_thread();
1019 simple_lock(&thread_call_lock
);
1021 self
->active_callout
= TRUE
;
1023 while (thread_calls
.pending_num
> 0) {
1025 thread_call_func_t func
;
1026 thread_call_param_t param0
, param1
;
1028 call
= TC(dequeue_head(&pending_call_queue
));
1029 thread_calls
.pending_num
--;
1032 param0
= call
->param0
;
1033 param1
= call
->param1
;
1037 _internal_call_release(call
);
1039 simple_unlock(&thread_call_lock
);
1042 (*func
)(param0
, param1
);
1044 (void)thread_funnel_set(self
->funnel_lock
, FALSE
);
1047 simple_lock(&thread_call_lock
);
1050 self
->active_callout
= FALSE
;
1052 if (--thread_calls
.active_num
< thread_calls
.active_lowat
)
1053 thread_calls
.active_lowat
= thread_calls
.active_num
;
1055 if (thread_calls
.idle_thread_num
< thread_calls
.thread_lowat
) {
1056 thread_calls
.idle_thread_num
++;
1058 wait_queue_assert_wait(
1059 &call_thread_idle_queue
, &call_thread_idle_queue
,
1060 THREAD_INTERRUPTIBLE
);
1062 simple_unlock(&thread_call_lock
);
1065 thread_block(_call_thread_continue
);
1069 thread_calls
.thread_num
--;
1071 simple_unlock(&thread_call_lock
);
1074 (void) thread_terminate(self
->top_act
);
1082 thread_t self
= current_thread();
1084 stack_privilege(self
);
1086 _call_thread_continue();
1091 * Routine: _activate_thread [private]
1093 * Purpose: Executed by the activate thread.
1095 * Preconditions: None.
1097 * Postconditions: Never terminates.
1102 _activate_thread_continue(void)
1105 simple_lock(&thread_call_lock
);
1107 while ( thread_calls
.active_num
<= 0 &&
1108 thread_calls
.pending_num
> 0 ) {
1110 if (++thread_calls
.active_num
> thread_calls
.active_hiwat
)
1111 thread_calls
.active_hiwat
= thread_calls
.active_num
;
1113 if (++thread_calls
.thread_num
> thread_calls
.thread_hiwat
)
1114 thread_calls
.thread_hiwat
= thread_calls
.thread_num
;
1116 simple_unlock(&thread_call_lock
);
1119 (void) kernel_thread_with_priority(
1120 kernel_task
, MAXPRI_KERNEL
- 1,
1121 _call_thread
, TRUE
, TRUE
);
1123 simple_lock(&thread_call_lock
);
1126 assert_wait(&activate_thread_awake
, THREAD_INTERRUPTIBLE
);
1127 activate_thread_awake
= FALSE
;
1129 simple_unlock(&thread_call_lock
);
1132 thread_block(_activate_thread_continue
);
1138 _activate_thread(void)
1140 thread_t self
= current_thread();
1142 self
->vm_privilege
= TRUE
;
1143 vm_page_free_reserve(2); /* XXX */
1144 stack_privilege(self
);
1146 _activate_thread_continue();
1152 _delayed_call_timer(
1153 timer_call_param_t p0
,
1154 timer_call_param_t p1
1159 boolean_t new_pending
= FALSE
;
1163 simple_lock(&thread_call_lock
);
1165 clock_get_uptime(×tamp
);
1167 call
= TC(queue_first(&delayed_call_queue
));
1169 while (!queue_end(&delayed_call_queue
, qe(call
))) {
1170 if (call
->deadline
<= timestamp
) {
1171 _delayed_call_dequeue(call
);
1173 _pending_call_enqueue(call
);
1179 call
= TC(queue_first(&delayed_call_queue
));
1182 if (!queue_end(&delayed_call_queue
, qe(call
)))
1183 _set_delayed_call_timer(call
);
1185 if (new_pending
&& thread_calls
.active_num
<= 0)
1186 _call_thread_wake();
1188 simple_unlock(&thread_call_lock
);