2 * Copyright (c) 1993-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Timer interrupt callout module.
32 #include <mach/mach_types.h>
34 #include <kern/clock.h>
35 #include <kern/processor.h>
36 #include <kern/etimer.h>
37 #include <kern/timer_call.h>
38 #include <kern/timer_queue.h>
39 #include <kern/call_entry.h>
41 #include <sys/kdebug.h>
49 #define TIMER_ASSERT 1
52 //#define TIMER_ASSERT 1
56 #define DBG(x...) kprintf("DBG: " x);
61 lck_grp_t timer_call_lck_grp
;
62 lck_attr_t timer_call_lck_attr
;
63 lck_grp_attr_t timer_call_lck_grp_attr
;
66 #define timer_call_lock_spin(queue) \
67 lck_mtx_lock_spin_always(&queue->lock_data)
69 #define timer_call_unlock(queue) \
70 lck_mtx_unlock_always(&queue->lock_data)
73 #define QUEUE(x) ((queue_t)(x))
74 #define MPQUEUE(x) ((mpqueue_head_t *)(x))
75 #define TIMER_CALL(x) ((timer_call_t)(x))
78 uint64_t past_deadline_timers
;
79 uint64_t past_deadline_deltas
;
80 uint64_t past_deadline_longest
;
81 uint64_t past_deadline_shortest
= ~0ULL;
82 enum {PAST_DEADLINE_TIMER_ADJUSTMENT_NS
= 10 * 1000};
84 uint64_t past_deadline_timer_adjustment
;
86 static boolean_t
timer_call_enter_internal(timer_call_t call
, timer_call_param_t param1
, uint64_t deadline
, uint32_t flags
);
87 boolean_t mach_timer_coalescing_enabled
= TRUE
;
89 mpqueue_head_t
*timer_call_enqueue_deadline_unlocked(
91 mpqueue_head_t
*queue
,
94 mpqueue_head_t
*timer_call_dequeue_unlocked(
99 timer_call_initialize(void)
101 lck_attr_setdefault(&timer_call_lck_attr
);
102 lck_grp_attr_setdefault(&timer_call_lck_grp_attr
);
103 lck_grp_init(&timer_call_lck_grp
, "timer_call", &timer_call_lck_grp_attr
);
104 nanotime_to_absolutetime(0, PAST_DEADLINE_TIMER_ADJUSTMENT_NS
, &past_deadline_timer_adjustment
);
109 timer_call_initialize_queue(mpqueue_head_t
*queue
)
111 DBG("timer_call_initialize_queue(%p)\n", queue
);
112 mpqueue_init(queue
, &timer_call_lck_grp
, &timer_call_lck_attr
);
119 timer_call_func_t func
,
120 timer_call_param_t param0
)
122 DBG("timer_call_setup(%p,%p,%p)\n", call
, func
, param0
);
123 call_entry_setup(CE(call
), func
, param0
);
124 simple_lock_init(&(call
)->lock
, 0);
125 call
->async_dequeue
= FALSE
;
129 * Timer call entry locking model
130 * ==============================
132 * Timer call entries are linked on per-cpu timer queues which are protected
133 * by the queue lock and the call entry lock. The locking protocol is:
135 * 0) The canonical locking order is timer call entry followed by queue.
137 * 1) With only the entry lock held, entry.queue is valid:
138 * 1a) NULL: the entry is not queued, or
139 * 1b) non-NULL: this queue must be locked before the entry is modified.
140 * After locking the queue, the call.async_dequeue flag must be checked:
141 * 1c) TRUE: the entry was removed from the queue by another thread
142 * and we must NULL the entry.queue and reset this flag, or
143 * 1d) FALSE: (ie. queued), the entry can be manipulated.
145 * 2) If a queue lock is obtained first, the queue is stable:
146 * 2a) If a try-lock of a queued entry succeeds, the call can be operated on
148 * 2b) If a try-lock fails, it indicates that another thread is attempting
149 * to change the entry and move it to a different position in this queue
150 * or to different queue. The entry can be dequeued but it should not be
151 * operated upon since it is being changed. Furthermore, we don't null
152 * the entry.queue pointer (protected by the entry lock we don't own).
153 * Instead, we set the async_dequeue flag -- see (1c).
157 * Inlines timer_call_entry_dequeue() and timer_call_entry_enqueue_deadline()
158 * cast between pointer types (mpqueue_head_t *) and (queue_t) so that
159 * we can use the call_entry_dequeue() and call_entry_enqueue_deadline()
160 * methods to operate on timer_call structs as if they are call_entry structs.
161 * These structures are identical except for their queue head pointer fields.
163 * In the debug case, we assert that the timer call locking protocol
167 static __inline__ mpqueue_head_t
*
168 timer_call_entry_dequeue(
171 mpqueue_head_t
*old_queue
= MPQUEUE(CE(entry
)->queue
);
173 if (!hw_lock_held((hw_lock_t
)&entry
->lock
))
174 panic("_call_entry_dequeue() "
175 "entry %p is not locked\n", entry
);
177 * XXX The queue lock is actually a mutex in spin mode
178 * but there's no way to test for it being held
179 * so we pretend it's a spinlock!
181 if (!hw_lock_held((hw_lock_t
)&old_queue
->lock_data
))
182 panic("_call_entry_dequeue() "
183 "queue %p is not locked\n", old_queue
);
185 call_entry_dequeue(CE(entry
));
190 static __inline__ mpqueue_head_t
*
191 timer_call_entry_enqueue_deadline(
193 mpqueue_head_t
*queue
,
196 mpqueue_head_t
*old_queue
= MPQUEUE(CE(entry
)->queue
);
198 if (!hw_lock_held((hw_lock_t
)&entry
->lock
))
199 panic("_call_entry_enqueue_deadline() "
200 "entry %p is not locked\n", entry
);
201 /* XXX More lock pretense: */
202 if (!hw_lock_held((hw_lock_t
)&queue
->lock_data
))
203 panic("_call_entry_enqueue_deadline() "
204 "queue %p is not locked\n", queue
);
205 if (old_queue
!= NULL
&& old_queue
!= queue
)
206 panic("_call_entry_enqueue_deadline() "
207 "old_queue %p != queue", old_queue
);
209 call_entry_enqueue_deadline(CE(entry
), QUEUE(queue
), deadline
);
216 static __inline__ mpqueue_head_t
*
217 timer_call_entry_dequeue(
220 return MPQUEUE(call_entry_dequeue(CE(entry
)));
223 static __inline__ mpqueue_head_t
*
224 timer_call_entry_enqueue_deadline(
226 mpqueue_head_t
*queue
,
229 return MPQUEUE(call_entry_enqueue_deadline(CE(entry
),
230 QUEUE(queue
), deadline
));
236 unsigned timer_call_enqueue_deadline_unlocked_async1
;
237 unsigned timer_call_enqueue_deadline_unlocked_async2
;
240 * Assumes call_entry and queues unlocked, interrupts disabled.
242 __inline__ mpqueue_head_t
*
243 timer_call_enqueue_deadline_unlocked(
245 mpqueue_head_t
*queue
,
248 call_entry_t entry
= CE(call
);
249 mpqueue_head_t
*old_queue
;
251 DBG("timer_call_enqueue_deadline_unlocked(%p,%p,)\n", call
, queue
);
253 simple_lock(&call
->lock
);
254 old_queue
= MPQUEUE(entry
->queue
);
255 if (old_queue
!= NULL
) {
256 timer_call_lock_spin(old_queue
);
257 if (call
->async_dequeue
) {
258 /* collision (1c): null queue pointer and reset flag */
259 call
->async_dequeue
= FALSE
;
262 timer_call_enqueue_deadline_unlocked_async1
++;
264 } else if (old_queue
!= queue
) {
265 (void)remque(qe(entry
));
268 timer_call_enqueue_deadline_unlocked_async2
++;
271 if (old_queue
!= queue
) {
272 timer_call_unlock(old_queue
);
273 timer_call_lock_spin(queue
);
276 timer_call_lock_spin(queue
);
279 timer_call_entry_enqueue_deadline(call
, queue
, deadline
);
280 timer_call_unlock(queue
);
281 simple_unlock(&call
->lock
);
287 unsigned timer_call_dequeue_unlocked_async1
;
288 unsigned timer_call_dequeue_unlocked_async2
;
291 timer_call_dequeue_unlocked(
294 call_entry_t entry
= CE(call
);
295 mpqueue_head_t
*old_queue
;
297 DBG("timer_call_dequeue_unlocked(%p)\n", call
);
299 simple_lock(&call
->lock
);
300 old_queue
= MPQUEUE(entry
->queue
);
301 if (old_queue
!= NULL
) {
302 timer_call_lock_spin(old_queue
);
303 if (call
->async_dequeue
) {
304 /* collision (1c): null queue pointer and reset flag */
305 call
->async_dequeue
= FALSE
;
307 timer_call_dequeue_unlocked_async1
++;
310 (void)remque(qe(entry
));
312 timer_call_dequeue_unlocked_async2
++;
316 timer_call_unlock(old_queue
);
318 simple_unlock(&call
->lock
);
323 timer_call_enter_internal(
325 timer_call_param_t param1
,
329 mpqueue_head_t
*queue
;
330 mpqueue_head_t
*old_queue
;
336 call
->soft_deadline
= deadline
;
339 if ((flags
& TIMER_CALL_CRITICAL
) == 0 &&
340 mach_timer_coalescing_enabled
) {
341 slop
= timer_call_slop(deadline
);
345 #if defined(__i386__) || defined(__x86_64__)
346 uint64_t ctime
= mach_absolute_time();
347 if (__improbable(deadline
< ctime
)) {
348 uint64_t delta
= (ctime
- deadline
);
350 past_deadline_timers
++;
351 past_deadline_deltas
+= delta
;
352 if (delta
> past_deadline_longest
)
353 past_deadline_longest
= deadline
;
354 if (delta
< past_deadline_shortest
)
355 past_deadline_shortest
= delta
;
357 deadline
= ctime
+ past_deadline_timer_adjustment
;
358 call
->soft_deadline
= deadline
;
361 call
->ttd
= call
->soft_deadline
- ctime
;
364 DTRACE_TMR6(callout__create
, timer_call_func_t
, CE(call
)->func
,
365 timer_call_param_t
, CE(call
)->param0
, uint32_t, call
->flags
,
366 (deadline
- call
->soft_deadline
),
367 (call
->ttd
>> 32), (unsigned) (call
->ttd
& 0xFFFFFFFF));
370 queue
= timer_queue_assign(deadline
);
372 old_queue
= timer_call_enqueue_deadline_unlocked(call
, queue
, deadline
);
374 CE(call
)->param1
= param1
;
378 return (old_queue
!= NULL
);
387 return timer_call_enter_internal(call
, NULL
, deadline
, flags
);
393 timer_call_param_t param1
,
397 return timer_call_enter_internal(call
, param1
, deadline
, flags
);
404 mpqueue_head_t
*old_queue
;
409 old_queue
= timer_call_dequeue_unlocked(call
);
411 if (old_queue
!= NULL
) {
412 timer_call_lock_spin(old_queue
);
413 if (!queue_empty(&old_queue
->head
))
414 timer_queue_cancel(old_queue
, CE(call
)->deadline
, CE(queue_first(&old_queue
->head
))->deadline
);
416 timer_queue_cancel(old_queue
, CE(call
)->deadline
, UINT64_MAX
);
417 timer_call_unlock(old_queue
);
422 DTRACE_TMR6(callout__cancel
, timer_call_func_t
, CE(call
)->func
,
423 timer_call_param_t
, CE(call
)->param0
, uint32_t, call
->flags
, 0,
424 (call
->ttd
>> 32), (unsigned) (call
->ttd
& 0xFFFFFFFF));
427 return (old_queue
!= NULL
);
430 uint32_t timer_queue_shutdown_lock_skips
;
432 timer_queue_shutdown(
433 mpqueue_head_t
*queue
)
436 mpqueue_head_t
*new_queue
;
439 DBG("timer_queue_shutdown(%p)\n", queue
);
443 /* Note comma operator in while expression re-locking each iteration */
444 while (timer_call_lock_spin(queue
), !queue_empty(&queue
->head
)) {
445 call
= TIMER_CALL(queue_first(&queue
->head
));
446 if (!simple_lock_try(&call
->lock
)) {
448 * case (2b) lock order inversion, dequeue and skip
449 * Don't change the call_entry queue back-pointer
450 * but set the async_dequeue field.
452 timer_queue_shutdown_lock_skips
++;
453 (void) remque(qe(call
));
454 call
->async_dequeue
= TRUE
;
455 timer_call_unlock(queue
);
459 /* remove entry from old queue */
460 timer_call_entry_dequeue(call
);
461 timer_call_unlock(queue
);
463 /* and queue it on new */
464 new_queue
= timer_queue_assign(CE(call
)->deadline
);
465 timer_call_lock_spin(new_queue
);
466 timer_call_entry_enqueue_deadline(
467 call
, new_queue
, CE(call
)->deadline
);
468 timer_call_unlock(new_queue
);
470 simple_unlock(&call
->lock
);
473 timer_call_unlock(queue
);
477 uint32_t timer_queue_expire_lock_skips
;
480 mpqueue_head_t
*queue
,
485 DBG("timer_queue_expire(%p,)\n", queue
);
487 timer_call_lock_spin(queue
);
489 while (!queue_empty(&queue
->head
)) {
490 call
= TIMER_CALL(queue_first(&queue
->head
));
492 if (call
->soft_deadline
<= deadline
) {
493 timer_call_func_t func
;
494 timer_call_param_t param0
, param1
;
496 if (!simple_lock_try(&call
->lock
)) {
497 /* case (2b) lock inversion, dequeue and skip */
498 timer_queue_expire_lock_skips
++;
499 (void) remque(qe(call
));
500 call
->async_dequeue
= TRUE
;
504 timer_call_entry_dequeue(call
);
506 func
= CE(call
)->func
;
507 param0
= CE(call
)->param0
;
508 param1
= CE(call
)->param1
;
510 simple_unlock(&call
->lock
);
511 timer_call_unlock(queue
);
513 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
514 DECR_TIMER_CALLOUT
| DBG_FUNC_START
,
515 VM_KERNEL_UNSLIDE(func
), param0
, param1
, 0, 0);
518 DTRACE_TMR6(callout__start
, timer_call_func_t
, func
,
519 timer_call_param_t
, param0
, unsigned, call
->flags
,
520 0, (call
->ttd
>> 32),
521 (unsigned) (call
->ttd
& 0xFFFFFFFF));
524 /* Maintain time-to-deadline in per-processor data
525 * structure for thread wakeup deadline statistics.
527 uint64_t *ttdp
= &(PROCESSOR_DATA(current_processor(), timer_call_ttd
));
529 (*func
)(param0
, param1
);
533 DTRACE_TMR3(callout__end
, timer_call_func_t
, func
,
534 timer_call_param_t
, param0
, timer_call_param_t
,
538 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
539 DECR_TIMER_CALLOUT
| DBG_FUNC_END
,
540 VM_KERNEL_UNSLIDE(func
), param0
, param1
, 0, 0);
542 timer_call_lock_spin(queue
);
548 if (!queue_empty(&queue
->head
))
549 deadline
= CE(call
)->deadline
;
551 deadline
= UINT64_MAX
;
553 timer_call_unlock(queue
);
559 extern int serverperfmode
;
560 uint32_t timer_queue_migrate_lock_skips
;
562 * timer_queue_migrate() is called by etimer_queue_migrate()
563 * to move timer requests from the local processor (queue_from)
564 * to a target processor's (queue_to).
567 timer_queue_migrate(mpqueue_head_t
*queue_from
, mpqueue_head_t
*queue_to
)
570 timer_call_t head_to
;
571 int timers_migrated
= 0;
573 DBG("timer_queue_migrate(%p,%p)\n", queue_from
, queue_to
);
575 assert(!ml_get_interrupts_enabled());
576 assert(queue_from
!= queue_to
);
578 if (serverperfmode
) {
580 * if we're running a high end server
581 * avoid migrations... they add latency
582 * and don't save us power under typical
589 * Take both local (from) and target (to) timer queue locks while
590 * moving the timers from the local queue to the target processor.
591 * We assume that the target is always the boot processor.
592 * But only move if all of the following is true:
593 * - the target queue is non-empty
594 * - the local queue is non-empty
595 * - the local queue's first deadline is later than the target's
596 * - the local queue contains no non-migrateable "local" call
597 * so that we need not have the target resync.
600 timer_call_lock_spin(queue_to
);
602 head_to
= TIMER_CALL(queue_first(&queue_to
->head
));
603 if (queue_empty(&queue_to
->head
)) {
604 timers_migrated
= -1;
608 timer_call_lock_spin(queue_from
);
610 if (queue_empty(&queue_from
->head
)) {
611 timers_migrated
= -2;
615 call
= TIMER_CALL(queue_first(&queue_from
->head
));
616 if (CE(call
)->deadline
< CE(head_to
)->deadline
) {
621 /* perform scan for non-migratable timers */
623 if (call
->flags
& TIMER_CALL_LOCAL
) {
624 timers_migrated
= -3;
627 call
= TIMER_CALL(queue_next(qe(call
)));
628 } while (!queue_end(&queue_from
->head
, qe(call
)));
630 /* migration loop itself -- both queues are locked */
631 while (!queue_empty(&queue_from
->head
)) {
632 call
= TIMER_CALL(queue_first(&queue_from
->head
));
633 if (!simple_lock_try(&call
->lock
)) {
634 /* case (2b) lock order inversion, dequeue only */
635 timer_queue_migrate_lock_skips
++;
636 (void) remque(qe(call
));
637 call
->async_dequeue
= TRUE
;
640 timer_call_entry_dequeue(call
);
641 timer_call_entry_enqueue_deadline(
642 call
, queue_to
, CE(call
)->deadline
);
644 simple_unlock(&call
->lock
);
648 timer_call_unlock(queue_from
);
650 timer_call_unlock(queue_to
);
652 return timers_migrated
;