2 * Copyright (c) 1993-1995, 1999-2005 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 #include <mach/mach_types.h>
25 #include <mach/thread_act.h>
27 #include <kern/kern_types.h>
28 #include <kern/kalloc.h>
29 #include <kern/sched_prim.h>
30 #include <kern/clock.h>
31 #include <kern/task.h>
32 #include <kern/thread.h>
33 #include <kern/wait_queue.h>
35 #include <vm/vm_pageout.h>
37 #include <kern/thread_call.h>
38 #include <kern/call_entry.h>
40 #include <kern/timer_call.h>
42 #include <sys/kdebug.h>
44 #define internal_call_num 768
46 #define thread_call_thread_min 4
50 internal_call_storage
[internal_call_num
];
52 decl_simple_lock_data(static,thread_call_lock
)
56 thread_call_delaytimer
;
60 thread_call_xxx_queue
,
61 thread_call_pending_queue
, thread_call_delayed_queue
;
65 call_thread_waitqueue
;
69 activate_thread_awake
;
85 static __inline__ thread_call_t
86 _internal_call_allocate(void);
88 static __inline__
void
89 _internal_call_release(
93 static __inline__
void
94 _pending_call_enqueue(
97 _pending_call_dequeue(
100 _delayed_call_enqueue(
103 _delayed_call_dequeue(
107 static __inline__
void
108 _set_delayed_call_timer(
113 _remove_from_pending_queue(
114 thread_call_func_t func
,
115 thread_call_param_t param0
,
118 _remove_from_delayed_queue(
119 thread_call_func_t func
,
120 thread_call_param_t param0
,
124 static __inline__
void
125 _call_thread_wake(void);
129 _activate_thread(void);
133 timer_call_param_t p0
,
134 timer_call_param_t p1
137 #define qe(x) ((queue_entry_t)(x))
138 #define TC(x) ((thread_call_t)(x))
141 * Routine: thread_call_initialize [public]
143 * Description: Initialize this module, called
144 * early during system initialization.
146 * Preconditions: None.
148 * Postconditions: None.
152 thread_call_initialize(void)
154 kern_return_t result
;
159 simple_lock_init(&thread_call_lock
, 0);
162 simple_lock(&thread_call_lock
);
164 queue_init(&thread_call_pending_queue
);
165 queue_init(&thread_call_delayed_queue
);
167 queue_init(&thread_call_xxx_queue
);
169 call
= internal_call_storage
;
170 call
< &internal_call_storage
[internal_call_num
];
173 enqueue_tail(&thread_call_xxx_queue
, qe(call
));
176 timer_call_setup(&thread_call_delaytimer
, _delayed_call_timer
, NULL
);
178 wait_queue_init(&call_thread_waitqueue
, SYNC_POLICY_FIFO
);
179 thread_call_vars
.thread_lowat
= thread_call_thread_min
;
181 activate_thread_awake
= TRUE
;
183 simple_unlock(&thread_call_lock
);
186 result
= kernel_thread_start_priority((thread_continue_t
)_activate_thread
, NULL
, MAXPRI_KERNEL
- 2, &thread
);
187 if (result
!= KERN_SUCCESS
)
188 panic("thread_call_initialize");
190 thread_deallocate(thread
);
196 thread_call_func_t func
,
197 thread_call_param_t param0
200 call_entry_setup(call
, func
, param0
);
204 * Routine: _internal_call_allocate [private, inline]
206 * Purpose: Allocate an internal callout entry.
208 * Preconditions: thread_call_lock held.
210 * Postconditions: None.
213 static __inline__ thread_call_t
214 _internal_call_allocate(void)
218 if (queue_empty(&thread_call_xxx_queue
))
219 panic("_internal_call_allocate");
221 call
= TC(dequeue_head(&thread_call_xxx_queue
));
227 * Routine: _internal_call_release [private, inline]
229 * Purpose: Release an internal callout entry which
230 * is no longer pending (or delayed).
232 * Preconditions: thread_call_lock held.
234 * Postconditions: None.
239 _internal_call_release(
243 if ( call
>= internal_call_storage
&&
244 call
< &internal_call_storage
[internal_call_num
] )
245 enqueue_head(&thread_call_xxx_queue
, qe(call
));
249 * Routine: _pending_call_enqueue [private, inline]
251 * Purpose: Place an entry at the end of the
252 * pending queue, to be executed soon.
254 * Preconditions: thread_call_lock held.
256 * Postconditions: None.
261 _pending_call_enqueue(
265 enqueue_tail(&thread_call_pending_queue
, qe(call
));
266 if (++thread_call_vars
.pending_num
> thread_call_vars
.pending_hiwat
)
267 thread_call_vars
.pending_hiwat
= thread_call_vars
.pending_num
;
269 call
->state
= PENDING
;
273 * Routine: _pending_call_dequeue [private, inline]
275 * Purpose: Remove an entry from the pending queue,
276 * effectively unscheduling it.
278 * Preconditions: thread_call_lock held.
280 * Postconditions: None.
285 _pending_call_dequeue(
289 (void)remque(qe(call
));
290 thread_call_vars
.pending_num
--;
296 * Routine: _delayed_call_enqueue [private, inline]
298 * Purpose: Place an entry on the delayed queue,
299 * after existing entries with an earlier
300 * (or identical) deadline.
302 * Preconditions: thread_call_lock held.
304 * Postconditions: None.
309 _delayed_call_enqueue(
313 thread_call_t current
;
315 current
= TC(queue_first(&thread_call_delayed_queue
));
318 if ( queue_end(&thread_call_delayed_queue
, qe(current
)) ||
319 call
->deadline
< current
->deadline
) {
320 current
= TC(queue_prev(qe(current
)));
324 current
= TC(queue_next(qe(current
)));
327 insque(qe(call
), qe(current
));
328 if (++thread_call_vars
.delayed_num
> thread_call_vars
.delayed_hiwat
)
329 thread_call_vars
.delayed_hiwat
= thread_call_vars
.delayed_num
;
331 call
->state
= DELAYED
;
335 * Routine: _delayed_call_dequeue [private, inline]
337 * Purpose: Remove an entry from the delayed queue,
338 * effectively unscheduling it.
340 * Preconditions: thread_call_lock held.
342 * Postconditions: None.
347 _delayed_call_dequeue(
351 (void)remque(qe(call
));
352 thread_call_vars
.delayed_num
--;
358 * Routine: _set_delayed_call_timer [private]
360 * Purpose: Reset the timer so that it
361 * next expires when the entry is due.
363 * Preconditions: thread_call_lock held.
365 * Postconditions: None.
368 static __inline__
void
369 _set_delayed_call_timer(
373 timer_call_enter(&thread_call_delaytimer
, call
->deadline
);
377 * Routine: _remove_from_pending_queue [private]
379 * Purpose: Remove the first (or all) matching
380 * entries from the pending queue,
381 * effectively unscheduling them.
382 * Returns whether any matching entries
385 * Preconditions: thread_call_lock held.
387 * Postconditions: None.
392 _remove_from_pending_queue(
393 thread_call_func_t func
,
394 thread_call_param_t param0
,
398 boolean_t call_removed
= FALSE
;
401 call
= TC(queue_first(&thread_call_pending_queue
));
403 while (!queue_end(&thread_call_pending_queue
, qe(call
))) {
404 if ( call
->func
== func
&&
405 call
->param0
== param0
) {
406 thread_call_t next
= TC(queue_next(qe(call
)));
408 _pending_call_dequeue(call
);
410 _internal_call_release(call
);
419 call
= TC(queue_next(qe(call
)));
422 return (call_removed
);
426 * Routine: _remove_from_delayed_queue [private]
428 * Purpose: Remove the first (or all) matching
429 * entries from the delayed queue,
430 * effectively unscheduling them.
431 * Returns whether any matching entries
434 * Preconditions: thread_call_lock held.
436 * Postconditions: None.
441 _remove_from_delayed_queue(
442 thread_call_func_t func
,
443 thread_call_param_t param0
,
447 boolean_t call_removed
= FALSE
;
450 call
= TC(queue_first(&thread_call_delayed_queue
));
452 while (!queue_end(&thread_call_delayed_queue
, qe(call
))) {
453 if ( call
->func
== func
&&
454 call
->param0
== param0
) {
455 thread_call_t next
= TC(queue_next(qe(call
)));
457 _delayed_call_dequeue(call
);
459 _internal_call_release(call
);
468 call
= TC(queue_next(qe(call
)));
471 return (call_removed
);
475 * Routine: thread_call_func [public]
477 * Purpose: Schedule a function callout.
478 * Guarantees { function, argument }
479 * uniqueness if unique_call is TRUE.
481 * Preconditions: Callable from an interrupt context
484 * Postconditions: None.
489 thread_call_func_t func
,
490 thread_call_param_t param
,
491 boolean_t unique_call
498 simple_lock(&thread_call_lock
);
500 call
= TC(queue_first(&thread_call_pending_queue
));
502 while (unique_call
&& !queue_end(&thread_call_pending_queue
, qe(call
))) {
503 if ( call
->func
== func
&&
504 call
->param0
== param
) {
508 call
= TC(queue_next(qe(call
)));
511 if (!unique_call
|| queue_end(&thread_call_pending_queue
, qe(call
))) {
512 call
= _internal_call_allocate();
514 call
->param0
= param
;
517 _pending_call_enqueue(call
);
519 if (thread_call_vars
.active_num
<= 0)
523 simple_unlock(&thread_call_lock
);
528 * Routine: thread_call_func_delayed [public]
530 * Purpose: Schedule a function callout to
531 * occur at the stated time.
533 * Preconditions: Callable from an interrupt context
536 * Postconditions: None.
540 thread_call_func_delayed(
541 thread_call_func_t func
,
542 thread_call_param_t param
,
550 simple_lock(&thread_call_lock
);
552 call
= _internal_call_allocate();
554 call
->param0
= param
;
556 call
->deadline
= deadline
;
558 _delayed_call_enqueue(call
);
560 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
561 _set_delayed_call_timer(call
);
563 simple_unlock(&thread_call_lock
);
568 * Routine: thread_call_func_cancel [public]
570 * Purpose: Unschedule a function callout.
571 * Removes one (or all)
572 * { function, argument }
573 * instance(s) from either (or both)
574 * the pending and the delayed queue,
575 * in that order. Returns a boolean
576 * indicating whether any calls were
579 * Preconditions: Callable from an interrupt context
582 * Postconditions: None.
586 thread_call_func_cancel(
587 thread_call_func_t func
,
588 thread_call_param_t param
,
596 simple_lock(&thread_call_lock
);
599 result
= _remove_from_pending_queue(func
, param
, cancel_all
) |
600 _remove_from_delayed_queue(func
, param
, cancel_all
);
602 result
= _remove_from_pending_queue(func
, param
, cancel_all
) ||
603 _remove_from_delayed_queue(func
, param
, cancel_all
);
605 simple_unlock(&thread_call_lock
);
612 * Routine: thread_call_allocate [public]
614 * Purpose: Allocate an external callout
617 * Preconditions: None.
619 * Postconditions: None.
623 thread_call_allocate(
624 thread_call_func_t func
,
625 thread_call_param_t param0
628 thread_call_t call
= (void *)kalloc(sizeof (thread_call_data_t
));
631 call
->param0
= param0
;
638 * Routine: thread_call_free [public]
640 * Purpose: Free an external callout
643 * Preconditions: None.
645 * Postconditions: None.
656 simple_lock(&thread_call_lock
);
658 if (call
->state
!= IDLE
) {
659 simple_unlock(&thread_call_lock
);
665 simple_unlock(&thread_call_lock
);
668 kfree(call
, sizeof (thread_call_data_t
));
674 * Routine: thread_call_enter [public]
676 * Purpose: Schedule an external callout
677 * entry to occur "soon". Returns a
678 * boolean indicating whether the call
679 * had been already scheduled.
681 * Preconditions: Callable from an interrupt context
684 * Postconditions: None.
692 boolean_t result
= TRUE
;
696 simple_lock(&thread_call_lock
);
698 if (call
->state
!= PENDING
) {
699 if (call
->state
== DELAYED
)
700 _delayed_call_dequeue(call
);
701 else if (call
->state
== IDLE
)
704 _pending_call_enqueue(call
);
706 if (thread_call_vars
.active_num
<= 0)
712 simple_unlock(&thread_call_lock
);
721 thread_call_param_t param1
724 boolean_t result
= TRUE
;
728 simple_lock(&thread_call_lock
);
730 if (call
->state
!= PENDING
) {
731 if (call
->state
== DELAYED
)
732 _delayed_call_dequeue(call
);
733 else if (call
->state
== IDLE
)
736 _pending_call_enqueue(call
);
738 if (thread_call_vars
.active_num
<= 0)
742 call
->param1
= param1
;
744 simple_unlock(&thread_call_lock
);
751 * Routine: thread_call_enter_delayed [public]
753 * Purpose: Schedule an external callout
754 * entry to occur at the stated time.
755 * Returns a boolean indicating whether
756 * the call had been already scheduled.
758 * Preconditions: Callable from an interrupt context
761 * Postconditions: None.
765 thread_call_enter_delayed(
770 boolean_t result
= TRUE
;
774 simple_lock(&thread_call_lock
);
776 if (call
->state
== PENDING
)
777 _pending_call_dequeue(call
);
778 else if (call
->state
== DELAYED
)
779 _delayed_call_dequeue(call
);
780 else if (call
->state
== IDLE
)
784 call
->deadline
= deadline
;
786 _delayed_call_enqueue(call
);
788 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
789 _set_delayed_call_timer(call
);
791 simple_unlock(&thread_call_lock
);
798 thread_call_enter1_delayed(
800 thread_call_param_t param1
,
804 boolean_t result
= TRUE
;
808 simple_lock(&thread_call_lock
);
810 if (call
->state
== PENDING
)
811 _pending_call_dequeue(call
);
812 else if (call
->state
== DELAYED
)
813 _delayed_call_dequeue(call
);
814 else if (call
->state
== IDLE
)
817 call
->param1
= param1
;
818 call
->deadline
= deadline
;
820 _delayed_call_enqueue(call
);
822 if (queue_first(&thread_call_delayed_queue
) == qe(call
))
823 _set_delayed_call_timer(call
);
825 simple_unlock(&thread_call_lock
);
832 * Routine: thread_call_cancel [public]
834 * Purpose: Unschedule a callout entry.
835 * Returns a boolean indicating
836 * whether the call had actually
839 * Preconditions: Callable from an interrupt context
842 * Postconditions: None.
850 boolean_t result
= TRUE
;
854 simple_lock(&thread_call_lock
);
856 if (call
->state
== PENDING
)
857 _pending_call_dequeue(call
);
858 else if (call
->state
== DELAYED
)
859 _delayed_call_dequeue(call
);
863 simple_unlock(&thread_call_lock
);
870 * Routine: thread_call_is_delayed [public]
872 * Purpose: Returns a boolean indicating
873 * whether a call is currently scheduled
874 * to occur at a later time. Optionally
875 * returns the expiration time.
877 * Preconditions: Callable from an interrupt context
880 * Postconditions: None.
884 thread_call_is_delayed(
888 boolean_t result
= FALSE
;
892 simple_lock(&thread_call_lock
);
894 if (call
->state
== DELAYED
) {
895 if (deadline
!= NULL
)
896 *deadline
= call
->deadline
;
900 simple_unlock(&thread_call_lock
);
907 * Routine: _call_thread_wake [private, inline]
909 * Purpose: Wake a callout thread to service
910 * pending callout entries. May wake
911 * the activate thread in order to
912 * create additional callout threads.
914 * Preconditions: thread_call_lock held.
916 * Postconditions: None.
921 _call_thread_wake(void)
923 if (wait_queue_wakeup_one(&call_thread_waitqueue
, NULL
, THREAD_AWAKENED
) == KERN_SUCCESS
) {
924 thread_call_vars
.idle_thread_num
--;
926 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
927 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
930 if (!activate_thread_awake
) {
931 thread_wakeup_one(&activate_thread_awake
);
932 activate_thread_awake
= TRUE
;
937 * Routine: call_thread_block [private]
939 * Purpose: Hook via thread dispatch on
940 * the occasion of a callout blocking.
942 * Preconditions: splsched.
944 * Postconditions: None.
948 call_thread_block(void)
950 simple_lock(&thread_call_lock
);
952 if (--thread_call_vars
.active_num
< thread_call_vars
.active_lowat
)
953 thread_call_vars
.active_lowat
= thread_call_vars
.active_num
;
955 if ( thread_call_vars
.active_num
<= 0 &&
956 thread_call_vars
.pending_num
> 0 )
959 simple_unlock(&thread_call_lock
);
963 * Routine: call_thread_unblock [private]
965 * Purpose: Hook via thread wakeup on
966 * the occasion of a callout unblocking.
968 * Preconditions: splsched.
970 * Postconditions: None.
974 call_thread_unblock(void)
976 simple_lock(&thread_call_lock
);
978 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
979 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
981 simple_unlock(&thread_call_lock
);
985 * Routine: _call_thread [private]
987 * Purpose: Executed by a callout thread.
989 * Preconditions: None.
991 * Postconditions: None.
996 _call_thread_continue(void)
998 thread_t self
= current_thread();
1001 simple_lock(&thread_call_lock
);
1003 self
->options
|= TH_OPT_CALLOUT
;
1005 while (thread_call_vars
.pending_num
> 0) {
1007 thread_call_func_t func
;
1008 thread_call_param_t param0
, param1
;
1010 call
= TC(dequeue_head(&thread_call_pending_queue
));
1011 thread_call_vars
.pending_num
--;
1014 param0
= call
->param0
;
1015 param1
= call
->param1
;
1019 _internal_call_release(call
);
1021 simple_unlock(&thread_call_lock
);
1024 KERNEL_DEBUG_CONSTANT(
1025 MACHDBG_CODE(DBG_MACH_SCHED
,MACH_CALLOUT
) | DBG_FUNC_NONE
,
1026 (int)func
, (int)param0
, (int)param1
, 0, 0);
1028 (*func
)(param0
, param1
);
1030 (void)thread_funnel_set(self
->funnel_lock
, FALSE
);
1033 simple_lock(&thread_call_lock
);
1036 self
->options
&= ~TH_OPT_CALLOUT
;
1038 if (--thread_call_vars
.active_num
< thread_call_vars
.active_lowat
)
1039 thread_call_vars
.active_lowat
= thread_call_vars
.active_num
;
1041 if (thread_call_vars
.idle_thread_num
< thread_call_vars
.thread_lowat
) {
1042 thread_call_vars
.idle_thread_num
++;
1044 wait_queue_assert_wait(&call_thread_waitqueue
, NULL
, THREAD_UNINT
, 0);
1046 simple_unlock(&thread_call_lock
);
1049 thread_block((thread_continue_t
)_call_thread_continue
);
1053 thread_call_vars
.thread_num
--;
1055 simple_unlock(&thread_call_lock
);
1058 thread_terminate(self
);
1066 _call_thread_continue();
1071 * Routine: _activate_thread [private]
1073 * Purpose: Executed by the activate thread.
1075 * Preconditions: None.
1077 * Postconditions: Never terminates.
1082 _activate_thread_continue(void)
1084 kern_return_t result
;
1088 simple_lock(&thread_call_lock
);
1090 while ( thread_call_vars
.active_num
<= 0 &&
1091 thread_call_vars
.pending_num
> 0 ) {
1093 if (++thread_call_vars
.active_num
> thread_call_vars
.active_hiwat
)
1094 thread_call_vars
.active_hiwat
= thread_call_vars
.active_num
;
1096 if (++thread_call_vars
.thread_num
> thread_call_vars
.thread_hiwat
)
1097 thread_call_vars
.thread_hiwat
= thread_call_vars
.thread_num
;
1099 simple_unlock(&thread_call_lock
);
1102 result
= kernel_thread_start_priority((thread_continue_t
)_call_thread
, NULL
, MAXPRI_KERNEL
- 1, &thread
);
1103 if (result
!= KERN_SUCCESS
)
1104 panic("activate_thread");
1106 thread_deallocate(thread
);
1109 simple_lock(&thread_call_lock
);
1112 assert_wait(&activate_thread_awake
, THREAD_INTERRUPTIBLE
);
1113 activate_thread_awake
= FALSE
;
1115 simple_unlock(&thread_call_lock
);
1118 thread_block((thread_continue_t
)_activate_thread_continue
);
1124 _activate_thread(void)
1126 thread_t self
= current_thread();
1128 self
->options
|= TH_OPT_VMPRIV
;
1129 vm_page_free_reserve(2); /* XXX */
1131 _activate_thread_continue();
1137 _delayed_call_timer(
1138 __unused timer_call_param_t p0
,
1139 __unused timer_call_param_t p1
1144 boolean_t new_pending
= FALSE
;
1148 simple_lock(&thread_call_lock
);
1150 clock_get_uptime(×tamp
);
1152 call
= TC(queue_first(&thread_call_delayed_queue
));
1154 while (!queue_end(&thread_call_delayed_queue
, qe(call
))) {
1155 if (call
->deadline
<= timestamp
) {
1156 _delayed_call_dequeue(call
);
1158 _pending_call_enqueue(call
);
1164 call
= TC(queue_first(&thread_call_delayed_queue
));
1167 if (!queue_end(&thread_call_delayed_queue
, qe(call
)))
1168 _set_delayed_call_timer(call
);
1170 if (new_pending
&& thread_call_vars
.active_num
<= 0)
1171 _call_thread_wake();
1173 simple_unlock(&thread_call_lock
);