2 * Copyright (c) 1993-1995, 1999-2005 Apple Computer, Inc.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #include <mach/mach_types.h>
26 #include <mach/thread_act.h>
28 #include <kern/kern_types.h>
29 #include <kern/kalloc.h>
30 #include <kern/sched_prim.h>
31 #include <kern/clock.h>
32 #include <kern/task.h>
33 #include <kern/thread.h>
34 #include <kern/wait_queue.h>
36 #include <vm/vm_pageout.h>
38 #include <kern/thread_call.h>
39 #include <kern/call_entry.h>
41 #include <kern/timer_call.h>
43 #include <sys/kdebug.h>
45 #define internal_call_num 768
47 #define thread_call_thread_min 4
51 internal_call_storage
[internal_call_num
];
53 decl_simple_lock_data(static,thread_call_lock
)
57 thread_call_delaytimer
;
61 thread_call_xxx_queue
,
62 thread_call_pending_queue
, thread_call_delayed_queue
;
66 call_thread_waitqueue
;
70 activate_thread_awake
;
86 static __inline__ thread_call_t
87 _internal_call_allocate(void);
89 static __inline__
void
90 _internal_call_release(
94 static __inline__
void
95 _pending_call_enqueue(
98 _pending_call_dequeue(
101 _delayed_call_enqueue(
104 _delayed_call_dequeue(
108 static __inline__
void
109 _set_delayed_call_timer(
114 _remove_from_pending_queue(
115 thread_call_func_t func
,
116 thread_call_param_t param0
,
119 _remove_from_delayed_queue(
120 thread_call_func_t func
,
121 thread_call_param_t param0
,
125 static __inline__
void
126 _call_thread_wake(void);
130 _activate_thread(void);
134 timer_call_param_t p0
,
135 timer_call_param_t p1
138 #define qe(x) ((queue_entry_t)(x))
139 #define TC(x) ((thread_call_t)(x))
142 * Routine: thread_call_initialize [public]
144 * Description: Initialize this module, called
145 * early during system initialization.
147 * Preconditions: None.
149 * Postconditions: None.
153 thread_call_initialize(void)
155 kern_return_t result
;
160 simple_lock_init(&thread_call_lock
, 0);
163 simple_lock(&thread_call_lock
);
165 queue_init(&thread_call_pending_queue
);
166 queue_init(&thread_call_delayed_queue
);
168 queue_init(&thread_call_xxx_queue
);
170 call
= internal_call_storage
;
171 call
< &internal_call_storage
[internal_call_num
];
174 enqueue_tail(&thread_call_xxx_queue
, qe(call
));
177 timer_call_setup(&thread_call_delaytimer
, _delayed_call_timer
, NULL
);
179 wait_queue_init(&call_thread_waitqueue
, SYNC_POLICY_FIFO
);
180 thread_call_vars
.thread_lowat
= thread_call_thread_min
;
182 activate_thread_awake
= TRUE
;
184 simple_unlock(&thread_call_lock
);
187 result
= kernel_thread_start_priority((thread_continue_t
)_activate_thread
, NULL
, MAXPRI_KERNEL
- 2, &thread
);
188 if (result
!= KERN_SUCCESS
)
189 panic("thread_call_initialize");
191 thread_deallocate(thread
);
197 thread_call_func_t func
,
198 thread_call_param_t param0
201 call_entry_setup(call
, func
, param0
);
205 * Routine: _internal_call_allocate [private, inline]
207 * Purpose: Allocate an internal callout entry.
209 * Preconditions: thread_call_lock held.
211 * Postconditions: None.
214 static __inline__ thread_call_t
215 _internal_call_allocate(void)
219 if (queue_empty(&thread_call_xxx_queue
))
220 panic("_internal_call_allocate");
222 call
= TC(dequeue_head(&thread_call_xxx_queue
));
228 * Routine: _internal_call_release [private, inline]
230 * Purpose: Release an internal callout entry which
231 * is no longer pending (or delayed).
233 * Preconditions: thread_call_lock held.
235 * Postconditions: None.
240 _internal_call_release(
244 if ( call
>= internal_call_storage
&&
245 call
< &internal_call_storage
[internal_call_num
] )
246 enqueue_head(&thread_call_xxx_queue
, qe(call
));
250 * Routine: _pending_call_enqueue [private, inline]
252 * Purpose: Place an entry at the end of the
253 * pending queue, to be executed soon.
255 * Preconditions: thread_call_lock held.
257 * Postconditions: None.
262 _pending_call_enqueue(
266 enqueue_tail(&thread_call_pending_queue
, qe(call
));
267 if (++thread_call_vars
.pending_num
> thread_call_vars
.pending_hiwat
)
268 thread_call_vars
.pending_hiwat
= thread_call_vars
.pending_num
;
270 call
->state
= PENDING
;
274 * Routine: _pending_call_dequeue [private, inline]
276 * Purpose: Remove an entry from the pending queue,
277 * effectively unscheduling it.
279 * Preconditions: thread_call_lock held.
281 * Postconditions: None.
286 _pending_call_dequeue(
290 (void)remque(qe(call
));
291 thread_call_vars
.pending_num
--;
297 * Routine: _delayed_call_enqueue [private, inline]
299 * Purpose: Place an entry on the delayed queue,
300 * after existing entries with an earlier
301 * (or identical) deadline.
303 * Preconditions: thread_call_lock held.
305 * Postconditions: None.
310 _delayed_call_enqueue(
314 thread_call_t current
;
316 current
= TC(queue_first(&thread_call_delayed_queue
));
319 if ( queue_end(&thread_call_delayed_queue
, qe(current
)) ||
320 call
->deadline
< current
->deadline
) {
321 current
= TC(queue_prev(qe(current
)));
325 current
= TC(queue_next(qe(current
)));
328 insque(qe(call
), qe(current
));
329 if (++thread_call_vars
.delayed_num
> thread_call_vars
.delayed_hiwat
)
330 thread_call_vars
.delayed_hiwat
= thread_call_vars
.delayed_num
;
332 call
->state
= DELAYED
;
336 * Routine: _delayed_call_dequeue [private, inline]
338 * Purpose: Remove an entry from the delayed queue,
339 * effectively unscheduling it.
341 * Preconditions: thread_call_lock held.
343 * Postconditions: None.
348 _delayed_call_dequeue(
352 (void)remque(qe(call
));
353 thread_call_vars
.delayed_num
--;
359 * Routine: _set_delayed_call_timer [private]
361 * Purpose: Reset the timer so that it
362 * next expires when the entry is due.
364 * Preconditions: thread_call_lock held.
366 * Postconditions: None.
369 static __inline__
void
370 _set_delayed_call_timer(
374 timer_call_enter(&thread_call_delaytimer
, call
->deadline
);
378 * Routine: _remove_from_pending_queue [private]
380 * Purpose: Remove the first (or all) matching
381 * entries from the pending queue,
382 * effectively unscheduling them.
383 * Returns whether any matching entries
386 * Preconditions: thread_call_lock held.
388 * Postconditions: None.
393 _remove_from_pending_queue(
394 thread_call_func_t func
,
395 thread_call_param_t param0
,
399 boolean_t call_removed
= FALSE
;
402 call
= TC(queue_first(&thread_call_pending_queue
));
404 while (!queue_end(&thread_call_pending_queue
, qe(call
))) {
405 if ( call
->func
== func
&&
406 call
->param0
== param0
) {
407 thread_call_t next
= TC(queue_next(qe(call
)));
409 _pending_call_dequeue(call
);
411 _internal_call_release(call
);
420 call
= TC(queue_next(qe(call
)));
423 return (call_removed
);
427 * Routine: _remove_from_delayed_queue [private]
429 * Purpose: Remove the first (or all) matching
430 * entries from the delayed queue,
431 * effectively unscheduling them.
432 * Returns whether any matching entries
435 * Preconditions: thread_call_lock held.
437 * Postconditions: None.
442 _remove_from_delayed_queue(
443 thread_call_func_t func
,
444 thread_call_param_t param0
,
448 boolean_t call_removed
= FALSE
;
451 call
= TC(queue_first(&thread_call_delayed_queue
));
453 while (!queue_end(&thread_call_delayed_queue
, qe(call
))) {
454 if ( call
->func
== func
&&
455 call
->param0
== param0
) {
456 thread_call_t next
= TC(queue_next(qe(call
)));
458 _delayed_call_dequeue(call
);
460 _internal_call_release(call
);
469 call
= TC(queue_next(qe(call
)));
472 return (call_removed
);
476 * Routine: thread_call_func [public]
478 * Purpose: Schedule a function callout.
479 * Guarantees { function, argument }
480 * uniqueness if unique_call is TRUE.
482 * Preconditions: Callable from an interrupt context
485 * Postconditions: None.
490 thread_call_func_t func
,
491 thread_call_param_t param
,
492 boolean_t unique_call
499 simple_lock(&thread_call_lock
);
501 call
= TC(queue_first(&thread_call_pending_queue
));
503 while (unique_call
&& !queue_end(&thread_call_pending_queue
, qe(call
))) {
504 if ( call
->func
== func
&&
505 call
->param0
== param
) {
509 call
= TC(queue_next(qe(call
)));
512 if (!unique_call
|| queue_end(&thread_call_pending_queue
, qe(call
))) {
513 call
= _internal_call_allocate();
515 call
->param0
= param
;
518 _pending_call_enqueue(call
);
520 if (thread_call_vars
.active_num
<= 0)
524 simple_unlock(&thread_call_lock
);
529 * Routine: thread_call_func_delayed [public]
531 * Purpose: Schedule a function callout to
532 * occur at the stated time.
534 * Preconditions: Callable from an interrupt context
537 * Postconditions: None.
541 thread_call_func_delayed(
542 thread_call_func_t func
,
543 thread_call_param_t param
,
551 simple_lock(&thread_call_lock
);
553 call
= _internal_call_allocate();
555 call
->param0
= param
;
557 call
->deadline
= deadline
;
559 _delayed_call_enqueue(call
);
561 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
562 _set_delayed_call_timer(call
);
564 simple_unlock(&thread_call_lock
);
569 * Routine: thread_call_func_cancel [public]
571 * Purpose: Unschedule a function callout.
572 * Removes one (or all)
573 * { function, argument }
574 * instance(s) from either (or both)
575 * the pending and the delayed queue,
576 * in that order. Returns a boolean
577 * indicating whether any calls were
580 * Preconditions: Callable from an interrupt context
583 * Postconditions: None.
587 thread_call_func_cancel(
588 thread_call_func_t func
,
589 thread_call_param_t param
,
597 simple_lock(&thread_call_lock
);
600 result
= _remove_from_pending_queue(func
, param
, cancel_all
) |
601 _remove_from_delayed_queue(func
, param
, cancel_all
);
603 result
= _remove_from_pending_queue(func
, param
, cancel_all
) ||
604 _remove_from_delayed_queue(func
, param
, cancel_all
);
606 simple_unlock(&thread_call_lock
);
613 * Routine: thread_call_allocate [public]
615 * Purpose: Allocate an external callout
618 * Preconditions: None.
620 * Postconditions: None.
624 thread_call_allocate(
625 thread_call_func_t func
,
626 thread_call_param_t param0
629 thread_call_t call
= (void *)kalloc(sizeof (thread_call_data_t
));
632 call
->param0
= param0
;
639 * Routine: thread_call_free [public]
641 * Purpose: Free an external callout
644 * Preconditions: None.
646 * Postconditions: None.
657 simple_lock(&thread_call_lock
);
659 if (call
->state
!= IDLE
) {
660 simple_unlock(&thread_call_lock
);
666 simple_unlock(&thread_call_lock
);
669 kfree(call
, sizeof (thread_call_data_t
));
675 * Routine: thread_call_enter [public]
677 * Purpose: Schedule an external callout
678 * entry to occur "soon". Returns a
679 * boolean indicating whether the call
680 * had been already scheduled.
682 * Preconditions: Callable from an interrupt context
685 * Postconditions: None.
693 boolean_t result
= TRUE
;
697 simple_lock(&thread_call_lock
);
699 if (call
->state
!= PENDING
) {
700 if (call
->state
== DELAYED
)
701 _delayed_call_dequeue(call
);
702 else if (call
->state
== IDLE
)
705 _pending_call_enqueue(call
);
707 if (thread_call_vars
.active_num
<= 0)
713 simple_unlock(&thread_call_lock
);
722 thread_call_param_t param1
725 boolean_t result
= TRUE
;
729 simple_lock(&thread_call_lock
);
731 if (call
->state
!= PENDING
) {
732 if (call
->state
== DELAYED
)
733 _delayed_call_dequeue(call
);
734 else if (call
->state
== IDLE
)
737 _pending_call_enqueue(call
);
739 if (thread_call_vars
.active_num
<= 0)
743 call
->param1
= param1
;
745 simple_unlock(&thread_call_lock
);
752 * Routine: thread_call_enter_delayed [public]
754 * Purpose: Schedule an external callout
755 * entry to occur at the stated time.
756 * Returns a boolean indicating whether
757 * the call had been already scheduled.
759 * Preconditions: Callable from an interrupt context
762 * Postconditions: None.
766 thread_call_enter_delayed(
771 boolean_t result
= TRUE
;
775 simple_lock(&thread_call_lock
);
777 if (call
->state
== PENDING
)
778 _pending_call_dequeue(call
);
779 else if (call
->state
== DELAYED
)
780 _delayed_call_dequeue(call
);
781 else if (call
->state
== IDLE
)
785 call
->deadline
= deadline
;
787 _delayed_call_enqueue(call
);
789 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
790 _set_delayed_call_timer(call
);
792 simple_unlock(&thread_call_lock
);
799 thread_call_enter1_delayed(
801 thread_call_param_t param1
,
805 boolean_t result
= TRUE
;
809 simple_lock(&thread_call_lock
);
811 if (call
->state
== PENDING
)
812 _pending_call_dequeue(call
);
813 else if (call
->state
== DELAYED
)
814 _delayed_call_dequeue(call
);
815 else if (call
->state
== IDLE
)
818 call
->param1
= param1
;
819 call
->deadline
= deadline
;
821 _delayed_call_enqueue(call
);
823 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
824 _set_delayed_call_timer(call
);
826 simple_unlock(&thread_call_lock
);
833 * Routine: thread_call_cancel [public]
835 * Purpose: Unschedule a callout entry.
836 * Returns a boolean indicating
837 * whether the call had actually
840 * Preconditions: Callable from an interrupt context
843 * Postconditions: None.
851 boolean_t result
= TRUE
;
855 simple_lock(&thread_call_lock
);
857 if (call
->state
== PENDING
)
858 _pending_call_dequeue(call
);
859 else if (call
->state
== DELAYED
)
860 _delayed_call_dequeue(call
);
864 simple_unlock(&thread_call_lock
);
871 * Routine: thread_call_is_delayed [public]
873 * Purpose: Returns a boolean indicating
874 * whether a call is currently scheduled
875 * to occur at a later time. Optionally
876 * returns the expiration time.
878 * Preconditions: Callable from an interrupt context
881 * Postconditions: None.
885 thread_call_is_delayed(
889 boolean_t result
= FALSE
;
893 simple_lock(&thread_call_lock
);
895 if (call
->state
== DELAYED
) {
896 if (deadline
!= NULL
)
897 *deadline
= call
->deadline
;
901 simple_unlock(&thread_call_lock
);
908 * Routine: _call_thread_wake [private, inline]
910 * Purpose: Wake a callout thread to service
911 * pending callout entries. May wake
912 * the activate thread in order to
913 * create additional callout threads.
915 * Preconditions: thread_call_lock held.
917 * Postconditions: None.
922 _call_thread_wake(void)
924 if (wait_queue_wakeup_one(&call_thread_waitqueue
, NULL
, THREAD_AWAKENED
) == KERN_SUCCESS
) {
925 thread_call_vars
.idle_thread_num
--;
927 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
928 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
931 if (!activate_thread_awake
) {
932 thread_wakeup_one(&activate_thread_awake
);
933 activate_thread_awake
= TRUE
;
938 * Routine: call_thread_block [private]
940 * Purpose: Hook via thread dispatch on
941 * the occasion of a callout blocking.
943 * Preconditions: splsched.
945 * Postconditions: None.
949 call_thread_block(void)
951 simple_lock(&thread_call_lock
);
953 if (--thread_call_vars
.active_num
< thread_call_vars
.active_lowat
)
954 thread_call_vars
.active_lowat
= thread_call_vars
.active_num
;
956 if ( thread_call_vars
.active_num
<= 0 &&
957 thread_call_vars
.pending_num
> 0 )
960 simple_unlock(&thread_call_lock
);
964 * Routine: call_thread_unblock [private]
966 * Purpose: Hook via thread wakeup on
967 * the occasion of a callout unblocking.
969 * Preconditions: splsched.
971 * Postconditions: None.
975 call_thread_unblock(void)
977 simple_lock(&thread_call_lock
);
979 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
980 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
982 simple_unlock(&thread_call_lock
);
986 * Routine: _call_thread [private]
988 * Purpose: Executed by a callout thread.
990 * Preconditions: None.
992 * Postconditions: None.
997 _call_thread_continue(void)
999 thread_t self
= current_thread();
1002 simple_lock(&thread_call_lock
);
1004 self
->options
|= TH_OPT_CALLOUT
;
1006 while (thread_call_vars
.pending_num
> 0) {
1008 thread_call_func_t func
;
1009 thread_call_param_t param0
, param1
;
1011 call
= TC(dequeue_head(&thread_call_pending_queue
));
1012 thread_call_vars
.pending_num
--;
1015 param0
= call
->param0
;
1016 param1
= call
->param1
;
1020 _internal_call_release(call
);
1022 simple_unlock(&thread_call_lock
);
1025 KERNEL_DEBUG_CONSTANT(
1026 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_CALLOUT
) | DBG_FUNC_NONE
,
1027 (int)func
, (int)param0
, (int)param1
, 0, 0);
1029 (*func
)(param0
, param1
);
1031 (void)thread_funnel_set(self
->funnel_lock
, FALSE
);
1034 simple_lock(&thread_call_lock
);
1037 self
->options
&= ~TH_OPT_CALLOUT
;
1039 if (--thread_call_vars
.active_num
< thread_call_vars
.active_lowat
)
1040 thread_call_vars
.active_lowat
= thread_call_vars
.active_num
;
1042 if (thread_call_vars
.idle_thread_num
< thread_call_vars
.thread_lowat
) {
1043 thread_call_vars
.idle_thread_num
++;
1045 wait_queue_assert_wait(&call_thread_waitqueue
, NULL
, THREAD_UNINT
, 0);
1047 simple_unlock(&thread_call_lock
);
1050 thread_block((thread_continue_t
)_call_thread_continue
);
1054 thread_call_vars
.thread_num
--;
1056 simple_unlock(&thread_call_lock
);
1059 thread_terminate(self
);
1067 _call_thread_continue();
1072 * Routine: _activate_thread [private]
1074 * Purpose: Executed by the activate thread.
1076 * Preconditions: None.
1078 * Postconditions: Never terminates.
1083 _activate_thread_continue(void)
1085 kern_return_t result
;
1089 simple_lock(&thread_call_lock
);
1091 while ( thread_call_vars
.active_num
<= 0 &&
1092 thread_call_vars
.pending_num
> 0 ) {
1094 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
1095 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
1097 if (++thread_call_vars
.thread_num
> thread_call_vars
.thread_hiwat
)
1098 thread_call_vars
.thread_hiwat
= thread_call_vars
.thread_num
;
1100 simple_unlock(&thread_call_lock
);
1103 result
= kernel_thread_start_priority((thread_continue_t
)_call_thread
, NULL
, MAXPRI_KERNEL
- 1, &thread
);
1104 if (result
!= KERN_SUCCESS
)
1105 panic("activate_thread");
1107 thread_deallocate(thread
);
1110 simple_lock(&thread_call_lock
);
1113 assert_wait(&activate_thread_awake
, THREAD_INTERRUPTIBLE
);
1114 activate_thread_awake
= FALSE
;
1116 simple_unlock(&thread_call_lock
);
1119 thread_block((thread_continue_t
)_activate_thread_continue
);
1125 _activate_thread(void)
1127 thread_t self
= current_thread();
1129 self
->options
|= TH_OPT_VMPRIV
;
1130 vm_page_free_reserve(2); /* XXX */
1132 _activate_thread_continue();
1138 _delayed_call_timer(
1139 __unused timer_call_param_t p0
,
1140 __unused timer_call_param_t p1
1145 boolean_t new_pending
= FALSE
;
1149 simple_lock(&thread_call_lock
);
1151 clock_get_uptime(×tamp
);
1153 call
= TC(queue_first(&thread_call_delayed_queue
));
1155 while (!queue_end(&thread_call_delayed_queue
, qe(call
))) {
1156 if (call
->deadline
<= timestamp
) {
1157 _delayed_call_dequeue(call
);
1159 _pending_call_enqueue(call
);
1165 call
= TC(queue_first(&thread_call_delayed_queue
));
1168 if (!queue_end(&thread_call_delayed_queue
, qe(call
)))
1169 _set_delayed_call_timer(call
);
1171 if (new_pending
&& thread_call_vars
.active_num
<= 0)
1172 _call_thread_wake();
1174 simple_unlock(&thread_call_lock
);