2 * Copyright (c) 1993-1995, 1999-2000 Apple Computer, Inc.
5 * @APPLE_LICENSE_HEADER_START@
7 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
9 * This file contains Original Code and/or Modifications of Original Code
10 * as defined in and that are subject to the Apple Public Source License
11 * Version 2.0 (the 'License'). You may not use this file except in
12 * compliance with the License. Please obtain a copy of the License at
13 * http://www.opensource.apple.com/apsl/ and read it before using this
16 * The Original Code and all software distributed under the License are
17 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
18 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
19 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
21 * Please see the License for the specific language governing rights and
22 * limitations under the License.
24 * @APPLE_LICENSE_HEADER_END@
27 * Thread-based callout module.
32 * Pulled into Mac OS X (microkernel).
38 #include <mach/mach_types.h>
40 #include <kern/sched_prim.h>
41 #include <kern/clock.h>
42 #include <kern/task.h>
43 #include <kern/thread.h>
45 #include <kern/thread_call.h>
46 #include <kern/call_entry.h>
48 #include <kern/timer_call.h>
50 #define internal_call_num 768
52 #define thread_call_thread_min 4
56 internal_call_storage
[internal_call_num
];
58 decl_simple_lock_data(static,thread_call_lock
)
62 thread_call_delayed_timer
;
66 internal_call_free_queue
,
67 pending_call_queue
, delayed_call_queue
;
71 call_thread_idle_queue
;
79 activate_thread_awake
;
96 thread_call_initialized
= FALSE
;
98 static __inline__ thread_call_t
99 _internal_call_allocate(void);
101 static __inline__
void
102 _internal_call_release(
106 static __inline__
void
107 _pending_call_enqueue(
110 _pending_call_dequeue(
113 _delayed_call_enqueue(
116 _delayed_call_dequeue(
120 static void __inline__
121 _set_delayed_call_timer(
126 _remove_from_pending_queue(
127 thread_call_func_t func
,
128 thread_call_param_t param0
,
131 _remove_from_delayed_queue(
132 thread_call_func_t func
,
133 thread_call_param_t param0
,
137 static __inline__
void
138 _call_thread_wake(void);
142 _activate_thread(void);
146 timer_call_param_t p0
,
147 timer_call_param_t p1
150 #define qe(x) ((queue_entry_t)(x))
151 #define TC(x) ((thread_call_t)(x))
154 * Routine: thread_call_initialize [public]
156 * Description: Initialize this module, called
157 * early during system initialization.
159 * Preconditions: None.
161 * Postconditions: None.
165 thread_call_initialize(void)
170 if (thread_call_initialized
)
171 panic("thread_call_initialize");
173 simple_lock_init(&thread_call_lock
, ETAP_MISC_TIMER
);
176 simple_lock(&thread_call_lock
);
178 queue_init(&pending_call_queue
);
179 queue_init(&delayed_call_queue
);
181 queue_init(&internal_call_free_queue
);
183 call
= internal_call_storage
;
184 call
< &internal_call_storage
[internal_call_num
];
187 enqueue_tail(&internal_call_free_queue
, qe(call
));
190 timer_call_setup(&thread_call_delayed_timer
, _delayed_call_timer
, NULL
);
192 wait_queue_init(&call_thread_idle_queue
, SYNC_POLICY_FIFO
);
193 thread_calls
.thread_lowat
= thread_call_thread_min
;
195 activate_thread_awake
= TRUE
;
196 thread_call_initialized
= TRUE
;
198 simple_unlock(&thread_call_lock
);
201 activate_thread
= kernel_thread_with_priority(
202 kernel_task
, MAXPRI_KERNEL
- 2,
203 _activate_thread
, TRUE
, TRUE
);
209 thread_call_func_t func
,
210 thread_call_param_t param0
213 call_entry_setup(call
, func
, param0
);
217 * Routine: _internal_call_allocate [private, inline]
219 * Purpose: Allocate an internal callout entry.
221 * Preconditions: thread_call_lock held.
223 * Postconditions: None.
226 static __inline__ thread_call_t
227 _internal_call_allocate(void)
231 if (queue_empty(&internal_call_free_queue
))
232 panic("_internal_call_allocate");
234 call
= TC(dequeue_head(&internal_call_free_queue
));
240 * Routine: _internal_call_release [private, inline]
242 * Purpose: Release an internal callout entry which
243 * is no longer pending (or delayed).
245 * Preconditions: thread_call_lock held.
247 * Postconditions: None.
252 _internal_call_release(
256 if ( call
>= internal_call_storage
&&
257 call
< &internal_call_storage
[internal_call_num
] )
258 enqueue_tail(&internal_call_free_queue
, qe(call
));
262 * Routine: _pending_call_enqueue [private, inline]
264 * Purpose: Place an entry at the end of the
265 * pending queue, to be executed soon.
267 * Preconditions: thread_call_lock held.
269 * Postconditions: None.
274 _pending_call_enqueue(
278 enqueue_tail(&pending_call_queue
, qe(call
));
279 if (++thread_calls
.pending_num
> thread_calls
.pending_hiwat
)
280 thread_calls
.pending_hiwat
= thread_calls
.pending_num
;
282 call
->state
= PENDING
;
286 * Routine: _pending_call_dequeue [private, inline]
288 * Purpose: Remove an entry from the pending queue,
289 * effectively unscheduling it.
291 * Preconditions: thread_call_lock held.
293 * Postconditions: None.
298 _pending_call_dequeue(
302 (void)remque(qe(call
));
303 thread_calls
.pending_num
--;
309 * Routine: _delayed_call_enqueue [private, inline]
311 * Purpose: Place an entry on the delayed queue,
312 * after existing entries with an earlier
313 * (or identical) deadline.
315 * Preconditions: thread_call_lock held.
317 * Postconditions: None.
322 _delayed_call_enqueue(
326 thread_call_t current
;
328 current
= TC(queue_first(&delayed_call_queue
));
331 if ( queue_end(&delayed_call_queue
, qe(current
)) ||
332 call
->deadline
< current
->deadline
) {
333 current
= TC(queue_prev(qe(current
)));
337 current
= TC(queue_next(qe(current
)));
340 insque(qe(call
), qe(current
));
341 if (++thread_calls
.delayed_num
> thread_calls
.delayed_hiwat
)
342 thread_calls
.delayed_hiwat
= thread_calls
.delayed_num
;
344 call
->state
= DELAYED
;
348 * Routine: _delayed_call_dequeue [private, inline]
350 * Purpose: Remove an entry from the delayed queue,
351 * effectively unscheduling it.
353 * Preconditions: thread_call_lock held.
355 * Postconditions: None.
360 _delayed_call_dequeue(
364 (void)remque(qe(call
));
365 thread_calls
.delayed_num
--;
371 * Routine: _set_delayed_call_timer [private]
373 * Purpose: Reset the timer so that it
374 * next expires when the entry is due.
376 * Preconditions: thread_call_lock held.
378 * Postconditions: None.
381 static __inline__
void
382 _set_delayed_call_timer(
386 timer_call_enter(&thread_call_delayed_timer
, call
->deadline
);
390 * Routine: _remove_from_pending_queue [private]
392 * Purpose: Remove the first (or all) matching
393 * entries from the pending queue,
394 * effectively unscheduling them.
395 * Returns whether any matching entries
398 * Preconditions: thread_call_lock held.
400 * Postconditions: None.
405 _remove_from_pending_queue(
406 thread_call_func_t func
,
407 thread_call_param_t param0
,
411 boolean_t call_removed
= FALSE
;
414 call
= TC(queue_first(&pending_call_queue
));
416 while (!queue_end(&pending_call_queue
, qe(call
))) {
417 if ( call
->func
== func
&&
418 call
->param0
== param0
) {
419 thread_call_t next
= TC(queue_next(qe(call
)));
421 _pending_call_dequeue(call
);
423 _internal_call_release(call
);
432 call
= TC(queue_next(qe(call
)));
435 return (call_removed
);
439 * Routine: _remove_from_delayed_queue [private]
441 * Purpose: Remove the first (or all) matching
442 * entries from the delayed queue,
443 * effectively unscheduling them.
444 * Returns whether any matching entries
447 * Preconditions: thread_call_lock held.
449 * Postconditions: None.
454 _remove_from_delayed_queue(
455 thread_call_func_t func
,
456 thread_call_param_t param0
,
460 boolean_t call_removed
= FALSE
;
463 call
= TC(queue_first(&delayed_call_queue
));
465 while (!queue_end(&delayed_call_queue
, qe(call
))) {
466 if ( call
->func
== func
&&
467 call
->param0
== param0
) {
468 thread_call_t next
= TC(queue_next(qe(call
)));
470 _delayed_call_dequeue(call
);
472 _internal_call_release(call
);
481 call
= TC(queue_next(qe(call
)));
484 return (call_removed
);
488 * Routine: thread_call_func [public]
490 * Purpose: Schedule a function callout.
491 * Guarantees { function, argument }
492 * uniqueness if unique_call is TRUE.
494 * Preconditions: Callable from an interrupt context
497 * Postconditions: None.
502 thread_call_func_t func
,
503 thread_call_param_t param
,
504 boolean_t unique_call
510 if (!thread_call_initialized
)
511 panic("thread_call_func");
514 simple_lock(&thread_call_lock
);
516 call
= TC(queue_first(&pending_call_queue
));
518 while (unique_call
&& !queue_end(&pending_call_queue
, qe(call
))) {
519 if ( call
->func
== func
&&
520 call
->param0
== param
) {
524 call
= TC(queue_next(qe(call
)));
527 if (!unique_call
|| queue_end(&pending_call_queue
, qe(call
))) {
528 call
= _internal_call_allocate();
530 call
->param0
= param
;
533 _pending_call_enqueue(call
);
535 if (thread_calls
.active_num
<= 0)
539 simple_unlock(&thread_call_lock
);
544 * Routine: thread_call_func_delayed [public]
546 * Purpose: Schedule a function callout to
547 * occur at the stated time.
549 * Preconditions: Callable from an interrupt context
552 * Postconditions: None.
556 thread_call_func_delayed(
557 thread_call_func_t func
,
558 thread_call_param_t param
,
565 if (!thread_call_initialized
)
566 panic("thread_call_func_delayed");
569 simple_lock(&thread_call_lock
);
571 call
= _internal_call_allocate();
573 call
->param0
= param
;
575 call
->deadline
= deadline
;
577 _delayed_call_enqueue(call
);
579 if (queue_first(&delayed_call_queue
) == qe(call
))
580 _set_delayed_call_timer(call
);
582 simple_unlock(&thread_call_lock
);
587 * Routine: thread_call_func_cancel [public]
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
598 * Preconditions: Callable from an interrupt context
601 * Postconditions: None.
605 thread_call_func_cancel(
606 thread_call_func_t func
,
607 thread_call_param_t param
,
615 simple_lock(&thread_call_lock
);
618 result
= _remove_from_pending_queue(func
, param
, cancel_all
) |
619 _remove_from_delayed_queue(func
, param
, cancel_all
);
621 result
= _remove_from_pending_queue(func
, param
, cancel_all
) ||
622 _remove_from_delayed_queue(func
, param
, cancel_all
);
624 simple_unlock(&thread_call_lock
);
631 * Routine: thread_call_allocate [public]
633 * Purpose: Allocate an external callout
636 * Preconditions: None.
638 * Postconditions: None.
642 thread_call_allocate(
643 thread_call_func_t func
,
644 thread_call_param_t param0
647 thread_call_t call
= (void *)kalloc(sizeof (thread_call_data_t
));
650 call
->param0
= param0
;
657 * Routine: thread_call_free [public]
659 * Purpose: Free an external callout
662 * Preconditions: None.
664 * Postconditions: None.
675 simple_lock(&thread_call_lock
);
677 if (call
->state
!= IDLE
) {
678 simple_unlock(&thread_call_lock
);
684 simple_unlock(&thread_call_lock
);
687 kfree((vm_offset_t
)call
, sizeof (thread_call_data_t
));
693 * Routine: thread_call_enter [public]
695 * Purpose: Schedule an external callout
696 * entry to occur "soon". Returns a
697 * boolean indicating whether the call
698 * had been already scheduled.
700 * Preconditions: Callable from an interrupt context
703 * Postconditions: None.
711 boolean_t result
= TRUE
;
715 simple_lock(&thread_call_lock
);
717 if (call
->state
!= PENDING
) {
718 if (call
->state
== DELAYED
)
719 _delayed_call_dequeue(call
);
720 else if (call
->state
== IDLE
)
723 _pending_call_enqueue(call
);
725 if (thread_calls
.active_num
<= 0)
731 simple_unlock(&thread_call_lock
);
740 thread_call_param_t param1
743 boolean_t result
= TRUE
;
747 simple_lock(&thread_call_lock
);
749 if (call
->state
!= PENDING
) {
750 if (call
->state
== DELAYED
)
751 _delayed_call_dequeue(call
);
752 else if (call
->state
== IDLE
)
755 _pending_call_enqueue(call
);
757 if (thread_calls
.active_num
<= 0)
761 call
->param1
= param1
;
763 simple_unlock(&thread_call_lock
);
770 * Routine: thread_call_enter_delayed [public]
772 * Purpose: Schedule an external callout
773 * entry to occur at the stated time.
774 * Returns a boolean indicating whether
775 * the call had been already scheduled.
777 * Preconditions: Callable from an interrupt context
780 * Postconditions: None.
784 thread_call_enter_delayed(
789 boolean_t result
= TRUE
;
793 simple_lock(&thread_call_lock
);
795 if (call
->state
== PENDING
)
796 _pending_call_dequeue(call
);
797 else if (call
->state
== DELAYED
)
798 _delayed_call_dequeue(call
);
799 else if (call
->state
== IDLE
)
803 call
->deadline
= deadline
;
805 _delayed_call_enqueue(call
);
807 if (queue_first(&delayed_call_queue
) == qe(call
))
808 _set_delayed_call_timer(call
);
810 simple_unlock(&thread_call_lock
);
817 thread_call_enter1_delayed(
819 thread_call_param_t param1
,
823 boolean_t result
= TRUE
;
827 simple_lock(&thread_call_lock
);
829 if (call
->state
== PENDING
)
830 _pending_call_dequeue(call
);
831 else if (call
->state
== DELAYED
)
832 _delayed_call_dequeue(call
);
833 else if (call
->state
== IDLE
)
836 call
->param1
= param1
;
837 call
->deadline
= deadline
;
839 _delayed_call_enqueue(call
);
841 if (queue_first(&delayed_call_queue
) == qe(call
))
842 _set_delayed_call_timer(call
);
844 simple_unlock(&thread_call_lock
);
851 * Routine: thread_call_cancel [public]
853 * Purpose: Unschedule a callout entry.
854 * Returns a boolean indicating
855 * whether the call had actually
858 * Preconditions: Callable from an interrupt context
861 * Postconditions: None.
869 boolean_t result
= TRUE
;
873 simple_lock(&thread_call_lock
);
875 if (call
->state
== PENDING
)
876 _pending_call_dequeue(call
);
877 else if (call
->state
== DELAYED
)
878 _delayed_call_dequeue(call
);
882 simple_unlock(&thread_call_lock
);
889 * Routine: thread_call_is_delayed [public]
891 * Purpose: Returns a boolean indicating
892 * whether a call is currently scheduled
893 * to occur at a later time. Optionally
894 * returns the expiration time.
896 * Preconditions: Callable from an interrupt context
899 * Postconditions: None.
903 thread_call_is_delayed(
907 boolean_t result
= FALSE
;
911 simple_lock(&thread_call_lock
);
913 if (call
->state
== DELAYED
) {
914 if (deadline
!= NULL
)
915 *deadline
= call
->deadline
;
919 simple_unlock(&thread_call_lock
);
926 * Routine: _call_thread_wake [private, inline]
928 * Purpose: Wake a callout thread to service
929 * pending callout entries. May wake
930 * the activate thread in order to
931 * create additional callout threads.
933 * Preconditions: thread_call_lock held.
935 * Postconditions: None.
940 _call_thread_wake(void)
942 if (wait_queue_wakeup_one(
943 &call_thread_idle_queue
, &call_thread_idle_queue
,
944 THREAD_AWAKENED
) == KERN_SUCCESS
) {
945 thread_calls
.idle_thread_num
--;
947 if (++thread_calls
.active_num
> thread_calls
.active_hiwat
)
948 thread_calls
.active_hiwat
= thread_calls
.active_num
;
951 if (!activate_thread_awake
) {
952 clear_wait(activate_thread
, THREAD_AWAKENED
);
953 activate_thread_awake
= TRUE
;
958 * Routine: call_thread_block [private]
960 * Purpose: Hook via thread dispatch on
961 * the occasion of a callout blocking.
963 * Preconditions: splsched.
965 * Postconditions: None.
969 call_thread_block(void)
971 simple_lock(&thread_call_lock
);
973 if (--thread_calls
.active_num
< thread_calls
.active_lowat
)
974 thread_calls
.active_lowat
= thread_calls
.active_num
;
976 if ( thread_calls
.active_num
<= 0 &&
977 thread_calls
.pending_num
> 0 )
980 simple_unlock(&thread_call_lock
);
984 * Routine: call_thread_unblock [private]
986 * Purpose: Hook via thread wakeup on
987 * the occasion of a callout unblocking.
989 * Preconditions: splsched.
991 * Postconditions: None.
995 call_thread_unblock(void)
997 simple_lock(&thread_call_lock
);
999 if (++thread_calls
.active_num
> thread_calls
.active_hiwat
)
1000 thread_calls
.active_hiwat
= thread_calls
.active_num
;
1002 simple_unlock(&thread_call_lock
);
1006 * Routine: _call_thread [private]
1008 * Purpose: Executed by a callout thread.
1010 * Preconditions: None.
1012 * Postconditions: None.
1017 _call_thread_continue(void)
1019 thread_t self
= current_thread();
1022 simple_lock(&thread_call_lock
);
1024 self
->active_callout
= TRUE
;
1026 while (thread_calls
.pending_num
> 0) {
1028 thread_call_func_t func
;
1029 thread_call_param_t param0
, param1
;
1031 call
= TC(dequeue_head(&pending_call_queue
));
1032 thread_calls
.pending_num
--;
1035 param0
= call
->param0
;
1036 param1
= call
->param1
;
1040 _internal_call_release(call
);
1042 simple_unlock(&thread_call_lock
);
1045 (*func
)(param0
, param1
);
1047 (void)thread_funnel_set(self
->funnel_lock
, FALSE
);
1050 simple_lock(&thread_call_lock
);
1053 self
->active_callout
= FALSE
;
1055 if (--thread_calls
.active_num
< thread_calls
.active_lowat
)
1056 thread_calls
.active_lowat
= thread_calls
.active_num
;
1058 if (thread_calls
.idle_thread_num
< thread_calls
.thread_lowat
) {
1059 thread_calls
.idle_thread_num
++;
1061 wait_queue_assert_wait(
1062 &call_thread_idle_queue
, &call_thread_idle_queue
,
1063 THREAD_INTERRUPTIBLE
);
1065 simple_unlock(&thread_call_lock
);
1068 thread_block(_call_thread_continue
);
1072 thread_calls
.thread_num
--;
1074 simple_unlock(&thread_call_lock
);
1077 (void) thread_terminate(self
->top_act
);
1085 thread_t self
= current_thread();
1087 stack_privilege(self
);
1089 _call_thread_continue();
1094 * Routine: _activate_thread [private]
1096 * Purpose: Executed by the activate thread.
1098 * Preconditions: None.
1100 * Postconditions: Never terminates.
1105 _activate_thread_continue(void)
1108 simple_lock(&thread_call_lock
);
1110 while ( thread_calls
.active_num
<= 0 &&
1111 thread_calls
.pending_num
> 0 ) {
1113 if (++thread_calls
.active_num
> thread_calls
.active_hiwat
)
1114 thread_calls
.active_hiwat
= thread_calls
.active_num
;
1116 if (++thread_calls
.thread_num
> thread_calls
.thread_hiwat
)
1117 thread_calls
.thread_hiwat
= thread_calls
.thread_num
;
1119 simple_unlock(&thread_call_lock
);
1122 (void) kernel_thread_with_priority(
1123 kernel_task
, MAXPRI_KERNEL
- 1,
1124 _call_thread
, TRUE
, TRUE
);
1126 simple_lock(&thread_call_lock
);
1129 assert_wait(&activate_thread_awake
, THREAD_INTERRUPTIBLE
);
1130 activate_thread_awake
= FALSE
;
1132 simple_unlock(&thread_call_lock
);
1135 thread_block(_activate_thread_continue
);
1141 _activate_thread(void)
1143 thread_t self
= current_thread();
1145 self
->vm_privilege
= TRUE
;
1146 vm_page_free_reserve(2); /* XXX */
1147 stack_privilege(self
);
1149 _activate_thread_continue();
1155 _delayed_call_timer(
1156 timer_call_param_t p0
,
1157 timer_call_param_t p1
1162 boolean_t new_pending
= FALSE
;
1166 simple_lock(&thread_call_lock
);
1168 clock_get_uptime(×tamp
);
1170 call
= TC(queue_first(&delayed_call_queue
));
1172 while (!queue_end(&delayed_call_queue
, qe(call
))) {
1173 if (call
->deadline
<= timestamp
) {
1174 _delayed_call_dequeue(call
);
1176 _pending_call_enqueue(call
);
1182 call
= TC(queue_first(&delayed_call_queue
));
1185 if (!queue_end(&delayed_call_queue
, qe(call
)))
1186 _set_delayed_call_timer(call
);
1188 if (new_pending
&& thread_calls
.active_num
<= 0)
1189 _call_thread_wake();
1191 simple_unlock(&thread_call_lock
);