2 * Copyright (c) 1993-1995, 1999-2005 Apple Computer, Inc.
5 * @APPLE_LICENSE_OSREFERENCE_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. The rights granted to you under the
11 * License may not be used to create, or enable the creation or
12 * redistribution of, unlawful or unlicensed copies of an Apple operating
13 * system, or to circumvent, violate, or enable the circumvention or
14 * violation of, any terms of an Apple operating system software license
17 * Please obtain a copy of the License at
18 * http://www.opensource.apple.com/apsl/ and read it before using this
21 * The Original Code and all software distributed under the License are
22 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
23 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
24 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
26 * Please see the License for the specific language governing rights and
27 * limitations under the License.
29 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
32 #include <mach/mach_types.h>
33 #include <mach/thread_act.h>
35 #include <kern/kern_types.h>
36 #include <kern/kalloc.h>
37 #include <kern/sched_prim.h>
38 #include <kern/clock.h>
39 #include <kern/task.h>
40 #include <kern/thread.h>
41 #include <kern/wait_queue.h>
43 #include <vm/vm_pageout.h>
45 #include <kern/thread_call.h>
46 #include <kern/call_entry.h>
48 #include <kern/timer_call.h>
50 #include <sys/kdebug.h>
52 #define internal_call_num 768
54 #define thread_call_thread_min 4
58 internal_call_storage
[internal_call_num
];
60 decl_simple_lock_data(static,thread_call_lock
)
64 thread_call_delaytimer
;
68 thread_call_xxx_queue
,
69 thread_call_pending_queue
, thread_call_delayed_queue
;
73 call_thread_waitqueue
;
77 activate_thread_awake
;
93 static __inline__ thread_call_t
94 _internal_call_allocate(void);
96 static __inline__
void
97 _internal_call_release(
101 static __inline__
void
102 _pending_call_enqueue(
105 _pending_call_dequeue(
108 _delayed_call_enqueue(
111 _delayed_call_dequeue(
115 static __inline__
void
116 _set_delayed_call_timer(
121 _remove_from_pending_queue(
122 thread_call_func_t func
,
123 thread_call_param_t param0
,
126 _remove_from_delayed_queue(
127 thread_call_func_t func
,
128 thread_call_param_t param0
,
132 static __inline__
void
133 _call_thread_wake(void);
137 _activate_thread(void);
141 timer_call_param_t p0
,
142 timer_call_param_t p1
145 #define qe(x) ((queue_entry_t)(x))
146 #define TC(x) ((thread_call_t)(x))
149 * Routine: thread_call_initialize [public]
151 * Description: Initialize this module, called
152 * early during system initialization.
154 * Preconditions: None.
156 * Postconditions: None.
160 thread_call_initialize(void)
162 kern_return_t result
;
167 simple_lock_init(&thread_call_lock
, 0);
170 simple_lock(&thread_call_lock
);
172 queue_init(&thread_call_pending_queue
);
173 queue_init(&thread_call_delayed_queue
);
175 queue_init(&thread_call_xxx_queue
);
177 call
= internal_call_storage
;
178 call
< &internal_call_storage
[internal_call_num
];
181 enqueue_tail(&thread_call_xxx_queue
, qe(call
));
184 timer_call_setup(&thread_call_delaytimer
, _delayed_call_timer
, NULL
);
186 wait_queue_init(&call_thread_waitqueue
, SYNC_POLICY_FIFO
);
187 thread_call_vars
.thread_lowat
= thread_call_thread_min
;
189 activate_thread_awake
= TRUE
;
191 simple_unlock(&thread_call_lock
);
194 result
= kernel_thread_start_priority((thread_continue_t
)_activate_thread
, NULL
, MAXPRI_KERNEL
- 2, &thread
);
195 if (result
!= KERN_SUCCESS
)
196 panic("thread_call_initialize");
198 thread_deallocate(thread
);
204 thread_call_func_t func
,
205 thread_call_param_t param0
208 call_entry_setup(call
, func
, param0
);
212 * Routine: _internal_call_allocate [private, inline]
214 * Purpose: Allocate an internal callout entry.
216 * Preconditions: thread_call_lock held.
218 * Postconditions: None.
221 static __inline__ thread_call_t
222 _internal_call_allocate(void)
226 if (queue_empty(&thread_call_xxx_queue
))
227 panic("_internal_call_allocate");
229 call
= TC(dequeue_head(&thread_call_xxx_queue
));
235 * Routine: _internal_call_release [private, inline]
237 * Purpose: Release an internal callout entry which
238 * is no longer pending (or delayed).
240 * Preconditions: thread_call_lock held.
242 * Postconditions: None.
247 _internal_call_release(
251 if ( call
>= internal_call_storage
&&
252 call
< &internal_call_storage
[internal_call_num
] )
253 enqueue_head(&thread_call_xxx_queue
, qe(call
));
257 * Routine: _pending_call_enqueue [private, inline]
259 * Purpose: Place an entry at the end of the
260 * pending queue, to be executed soon.
262 * Preconditions: thread_call_lock held.
264 * Postconditions: None.
269 _pending_call_enqueue(
273 enqueue_tail(&thread_call_pending_queue
, qe(call
));
274 if (++thread_call_vars
.pending_num
> thread_call_vars
.pending_hiwat
)
275 thread_call_vars
.pending_hiwat
= thread_call_vars
.pending_num
;
277 call
->state
= PENDING
;
281 * Routine: _pending_call_dequeue [private, inline]
283 * Purpose: Remove an entry from the pending queue,
284 * effectively unscheduling it.
286 * Preconditions: thread_call_lock held.
288 * Postconditions: None.
293 _pending_call_dequeue(
297 (void)remque(qe(call
));
298 thread_call_vars
.pending_num
--;
304 * Routine: _delayed_call_enqueue [private, inline]
306 * Purpose: Place an entry on the delayed queue,
307 * after existing entries with an earlier
308 * (or identical) deadline.
310 * Preconditions: thread_call_lock held.
312 * Postconditions: None.
317 _delayed_call_enqueue(
321 thread_call_t current
;
323 current
= TC(queue_first(&thread_call_delayed_queue
));
326 if ( queue_end(&thread_call_delayed_queue
, qe(current
)) ||
327 call
->deadline
< current
->deadline
) {
328 current
= TC(queue_prev(qe(current
)));
332 current
= TC(queue_next(qe(current
)));
335 insque(qe(call
), qe(current
));
336 if (++thread_call_vars
.delayed_num
> thread_call_vars
.delayed_hiwat
)
337 thread_call_vars
.delayed_hiwat
= thread_call_vars
.delayed_num
;
339 call
->state
= DELAYED
;
343 * Routine: _delayed_call_dequeue [private, inline]
345 * Purpose: Remove an entry from the delayed queue,
346 * effectively unscheduling it.
348 * Preconditions: thread_call_lock held.
350 * Postconditions: None.
355 _delayed_call_dequeue(
359 (void)remque(qe(call
));
360 thread_call_vars
.delayed_num
--;
366 * Routine: _set_delayed_call_timer [private]
368 * Purpose: Reset the timer so that it
369 * next expires when the entry is due.
371 * Preconditions: thread_call_lock held.
373 * Postconditions: None.
376 static __inline__
void
377 _set_delayed_call_timer(
381 timer_call_enter(&thread_call_delaytimer
, call
->deadline
);
385 * Routine: _remove_from_pending_queue [private]
387 * Purpose: Remove the first (or all) matching
388 * entries from the pending queue,
389 * effectively unscheduling them.
390 * Returns whether any matching entries
393 * Preconditions: thread_call_lock held.
395 * Postconditions: None.
400 _remove_from_pending_queue(
401 thread_call_func_t func
,
402 thread_call_param_t param0
,
406 boolean_t call_removed
= FALSE
;
409 call
= TC(queue_first(&thread_call_pending_queue
));
411 while (!queue_end(&thread_call_pending_queue
, qe(call
))) {
412 if ( call
->func
== func
&&
413 call
->param0
== param0
) {
414 thread_call_t next
= TC(queue_next(qe(call
)));
416 _pending_call_dequeue(call
);
418 _internal_call_release(call
);
427 call
= TC(queue_next(qe(call
)));
430 return (call_removed
);
434 * Routine: _remove_from_delayed_queue [private]
436 * Purpose: Remove the first (or all) matching
437 * entries from the delayed queue,
438 * effectively unscheduling them.
439 * Returns whether any matching entries
442 * Preconditions: thread_call_lock held.
444 * Postconditions: None.
449 _remove_from_delayed_queue(
450 thread_call_func_t func
,
451 thread_call_param_t param0
,
455 boolean_t call_removed
= FALSE
;
458 call
= TC(queue_first(&thread_call_delayed_queue
));
460 while (!queue_end(&thread_call_delayed_queue
, qe(call
))) {
461 if ( call
->func
== func
&&
462 call
->param0
== param0
) {
463 thread_call_t next
= TC(queue_next(qe(call
)));
465 _delayed_call_dequeue(call
);
467 _internal_call_release(call
);
476 call
= TC(queue_next(qe(call
)));
479 return (call_removed
);
483 * Routine: thread_call_func [public]
485 * Purpose: Schedule a function callout.
486 * Guarantees { function, argument }
487 * uniqueness if unique_call is TRUE.
489 * Preconditions: Callable from an interrupt context
492 * Postconditions: None.
497 thread_call_func_t func
,
498 thread_call_param_t param
,
499 boolean_t unique_call
506 simple_lock(&thread_call_lock
);
508 call
= TC(queue_first(&thread_call_pending_queue
));
510 while (unique_call
&& !queue_end(&thread_call_pending_queue
, qe(call
))) {
511 if ( call
->func
== func
&&
512 call
->param0
== param
) {
516 call
= TC(queue_next(qe(call
)));
519 if (!unique_call
|| queue_end(&thread_call_pending_queue
, qe(call
))) {
520 call
= _internal_call_allocate();
522 call
->param0
= param
;
525 _pending_call_enqueue(call
);
527 if (thread_call_vars
.active_num
<= 0)
531 simple_unlock(&thread_call_lock
);
536 * Routine: thread_call_func_delayed [public]
538 * Purpose: Schedule a function callout to
539 * occur at the stated time.
541 * Preconditions: Callable from an interrupt context
544 * Postconditions: None.
548 thread_call_func_delayed(
549 thread_call_func_t func
,
550 thread_call_param_t param
,
558 simple_lock(&thread_call_lock
);
560 call
= _internal_call_allocate();
562 call
->param0
= param
;
564 call
->deadline
= deadline
;
566 _delayed_call_enqueue(call
);
568 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
569 _set_delayed_call_timer(call
);
571 simple_unlock(&thread_call_lock
);
576 * Routine: thread_call_func_cancel [public]
578 * Purpose: Unschedule a function callout.
579 * Removes one (or all)
580 * { function, argument }
581 * instance(s) from either (or both)
582 * the pending and the delayed queue,
583 * in that order. Returns a boolean
584 * indicating whether any calls were
587 * Preconditions: Callable from an interrupt context
590 * Postconditions: None.
594 thread_call_func_cancel(
595 thread_call_func_t func
,
596 thread_call_param_t param
,
604 simple_lock(&thread_call_lock
);
607 result
= _remove_from_pending_queue(func
, param
, cancel_all
) |
608 _remove_from_delayed_queue(func
, param
, cancel_all
);
610 result
= _remove_from_pending_queue(func
, param
, cancel_all
) ||
611 _remove_from_delayed_queue(func
, param
, cancel_all
);
613 simple_unlock(&thread_call_lock
);
620 * Routine: thread_call_allocate [public]
622 * Purpose: Allocate an external callout
625 * Preconditions: None.
627 * Postconditions: None.
631 thread_call_allocate(
632 thread_call_func_t func
,
633 thread_call_param_t param0
636 thread_call_t call
= (void *)kalloc(sizeof (thread_call_data_t
));
639 call
->param0
= param0
;
646 * Routine: thread_call_free [public]
648 * Purpose: Free an external callout
651 * Preconditions: None.
653 * Postconditions: None.
664 simple_lock(&thread_call_lock
);
666 if (call
->state
!= IDLE
) {
667 simple_unlock(&thread_call_lock
);
673 simple_unlock(&thread_call_lock
);
676 kfree(call
, sizeof (thread_call_data_t
));
682 * Routine: thread_call_enter [public]
684 * Purpose: Schedule an external callout
685 * entry to occur "soon". Returns a
686 * boolean indicating whether the call
687 * had been already scheduled.
689 * Preconditions: Callable from an interrupt context
692 * Postconditions: None.
700 boolean_t result
= TRUE
;
704 simple_lock(&thread_call_lock
);
706 if (call
->state
!= PENDING
) {
707 if (call
->state
== DELAYED
)
708 _delayed_call_dequeue(call
);
709 else if (call
->state
== IDLE
)
712 _pending_call_enqueue(call
);
714 if (thread_call_vars
.active_num
<= 0)
720 simple_unlock(&thread_call_lock
);
729 thread_call_param_t param1
732 boolean_t result
= TRUE
;
736 simple_lock(&thread_call_lock
);
738 if (call
->state
!= PENDING
) {
739 if (call
->state
== DELAYED
)
740 _delayed_call_dequeue(call
);
741 else if (call
->state
== IDLE
)
744 _pending_call_enqueue(call
);
746 if (thread_call_vars
.active_num
<= 0)
750 call
->param1
= param1
;
752 simple_unlock(&thread_call_lock
);
759 * Routine: thread_call_enter_delayed [public]
761 * Purpose: Schedule an external callout
762 * entry to occur at the stated time.
763 * Returns a boolean indicating whether
764 * the call had been already scheduled.
766 * Preconditions: Callable from an interrupt context
769 * Postconditions: None.
773 thread_call_enter_delayed(
778 boolean_t result
= TRUE
;
782 simple_lock(&thread_call_lock
);
784 if (call
->state
== PENDING
)
785 _pending_call_dequeue(call
);
786 else if (call
->state
== DELAYED
)
787 _delayed_call_dequeue(call
);
788 else if (call
->state
== IDLE
)
792 call
->deadline
= deadline
;
794 _delayed_call_enqueue(call
);
796 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
797 _set_delayed_call_timer(call
);
799 simple_unlock(&thread_call_lock
);
806 thread_call_enter1_delayed(
808 thread_call_param_t param1
,
812 boolean_t result
= TRUE
;
816 simple_lock(&thread_call_lock
);
818 if (call
->state
== PENDING
)
819 _pending_call_dequeue(call
);
820 else if (call
->state
== DELAYED
)
821 _delayed_call_dequeue(call
);
822 else if (call
->state
== IDLE
)
825 call
->param1
= param1
;
826 call
->deadline
= deadline
;
828 _delayed_call_enqueue(call
);
830 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
831 _set_delayed_call_timer(call
);
833 simple_unlock(&thread_call_lock
);
840 * Routine: thread_call_cancel [public]
842 * Purpose: Unschedule a callout entry.
843 * Returns a boolean indicating
844 * whether the call had actually
847 * Preconditions: Callable from an interrupt context
850 * Postconditions: None.
858 boolean_t result
= TRUE
;
862 simple_lock(&thread_call_lock
);
864 if (call
->state
== PENDING
)
865 _pending_call_dequeue(call
);
866 else if (call
->state
== DELAYED
)
867 _delayed_call_dequeue(call
);
871 simple_unlock(&thread_call_lock
);
878 * Routine: thread_call_is_delayed [public]
880 * Purpose: Returns a boolean indicating
881 * whether a call is currently scheduled
882 * to occur at a later time. Optionally
883 * returns the expiration time.
885 * Preconditions: Callable from an interrupt context
888 * Postconditions: None.
892 thread_call_is_delayed(
896 boolean_t result
= FALSE
;
900 simple_lock(&thread_call_lock
);
902 if (call
->state
== DELAYED
) {
903 if (deadline
!= NULL
)
904 *deadline
= call
->deadline
;
908 simple_unlock(&thread_call_lock
);
915 * Routine: _call_thread_wake [private, inline]
917 * Purpose: Wake a callout thread to service
918 * pending callout entries. May wake
919 * the activate thread in order to
920 * create additional callout threads.
922 * Preconditions: thread_call_lock held.
924 * Postconditions: None.
929 _call_thread_wake(void)
931 if (wait_queue_wakeup_one(&call_thread_waitqueue
, NULL
, THREAD_AWAKENED
) == KERN_SUCCESS
) {
932 thread_call_vars
.idle_thread_num
--;
934 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
935 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
938 if (!activate_thread_awake
) {
939 thread_wakeup_one(&activate_thread_awake
);
940 activate_thread_awake
= TRUE
;
945 * Routine: call_thread_block [private]
947 * Purpose: Hook via thread dispatch on
948 * the occasion of a callout blocking.
950 * Preconditions: splsched.
952 * Postconditions: None.
956 call_thread_block(void)
958 simple_lock(&thread_call_lock
);
960 if (--thread_call_vars
.active_num
< thread_call_vars
.active_lowat
)
961 thread_call_vars
.active_lowat
= thread_call_vars
.active_num
;
963 if ( thread_call_vars
.active_num
<= 0 &&
964 thread_call_vars
.pending_num
> 0 )
967 simple_unlock(&thread_call_lock
);
971 * Routine: call_thread_unblock [private]
973 * Purpose: Hook via thread wakeup on
974 * the occasion of a callout unblocking.
976 * Preconditions: splsched.
978 * Postconditions: None.
982 call_thread_unblock(void)
984 simple_lock(&thread_call_lock
);
986 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
987 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
989 simple_unlock(&thread_call_lock
);
993 * Routine: _call_thread [private]
995 * Purpose: Executed by a callout thread.
997 * Preconditions: None.
999 * Postconditions: None.
1004 _call_thread_continue(void)
1006 thread_t self
= current_thread();
1009 simple_lock(&thread_call_lock
);
1011 self
->options
|= TH_OPT_CALLOUT
;
1013 while (thread_call_vars
.pending_num
> 0) {
1015 thread_call_func_t func
;
1016 thread_call_param_t param0
, param1
;
1018 call
= TC(dequeue_head(&thread_call_pending_queue
));
1019 thread_call_vars
.pending_num
--;
1022 param0
= call
->param0
;
1023 param1
= call
->param1
;
1027 _internal_call_release(call
);
1029 simple_unlock(&thread_call_lock
);
1032 KERNEL_DEBUG_CONSTANT(
1033 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_CALLOUT
) | DBG_FUNC_NONE
,
1034 (int)func
, (int)param0
, (int)param1
, 0, 0);
1036 (*func
)(param0
, param1
);
1038 (void)thread_funnel_set(self
->funnel_lock
, FALSE
);
1041 simple_lock(&thread_call_lock
);
1044 self
->options
&= ~TH_OPT_CALLOUT
;
1046 if (--thread_call_vars
.active_num
< thread_call_vars
.active_lowat
)
1047 thread_call_vars
.active_lowat
= thread_call_vars
.active_num
;
1049 if (thread_call_vars
.idle_thread_num
< thread_call_vars
.thread_lowat
) {
1050 thread_call_vars
.idle_thread_num
++;
1052 wait_queue_assert_wait(&call_thread_waitqueue
, NULL
, THREAD_UNINT
, 0);
1054 simple_unlock(&thread_call_lock
);
1057 thread_block((thread_continue_t
)_call_thread_continue
);
1061 thread_call_vars
.thread_num
--;
1063 simple_unlock(&thread_call_lock
);
1066 thread_terminate(self
);
1074 _call_thread_continue();
1079 * Routine: _activate_thread [private]
1081 * Purpose: Executed by the activate thread.
1083 * Preconditions: None.
1085 * Postconditions: Never terminates.
1090 _activate_thread_continue(void)
1092 kern_return_t result
;
1096 simple_lock(&thread_call_lock
);
1098 while ( thread_call_vars
.active_num
<= 0 &&
1099 thread_call_vars
.pending_num
> 0 ) {
1101 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
1102 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
1104 if (++thread_call_vars
.thread_num
> thread_call_vars
.thread_hiwat
)
1105 thread_call_vars
.thread_hiwat
= thread_call_vars
.thread_num
;
1107 simple_unlock(&thread_call_lock
);
1110 result
= kernel_thread_start_priority((thread_continue_t
)_call_thread
, NULL
, MAXPRI_KERNEL
- 1, &thread
);
1111 if (result
!= KERN_SUCCESS
)
1112 panic("activate_thread");
1114 thread_deallocate(thread
);
1117 simple_lock(&thread_call_lock
);
1120 assert_wait(&activate_thread_awake
, THREAD_INTERRUPTIBLE
);
1121 activate_thread_awake
= FALSE
;
1123 simple_unlock(&thread_call_lock
);
1126 thread_block((thread_continue_t
)_activate_thread_continue
);
1132 _activate_thread(void)
1134 thread_t self
= current_thread();
1136 self
->options
|= TH_OPT_VMPRIV
;
1137 vm_page_free_reserve(2); /* XXX */
1139 _activate_thread_continue();
1145 _delayed_call_timer(
1146 __unused timer_call_param_t p0
,
1147 __unused timer_call_param_t p1
1152 boolean_t new_pending
= FALSE
;
1156 simple_lock(&thread_call_lock
);
1158 clock_get_uptime(×tamp
);
1160 call
= TC(queue_first(&thread_call_delayed_queue
));
1162 while (!queue_end(&thread_call_delayed_queue
, qe(call
))) {
1163 if (call
->deadline
<= timestamp
) {
1164 _delayed_call_dequeue(call
);
1166 _pending_call_enqueue(call
);
1172 call
= TC(queue_first(&thread_call_delayed_queue
));
1175 if (!queue_end(&thread_call_delayed_queue
, qe(call
)))
1176 _set_delayed_call_timer(call
);
1178 if (new_pending
&& thread_call_vars
.active_num
<= 0)
1179 _call_thread_wake();
1181 simple_unlock(&thread_call_lock
);