]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/etimer.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / osfmk / kern / etimer.c
CommitLineData
0c530ab8
A
1/*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
25/*
26 * @APPLE_FREE_COPYRIGHT@
27 */
28/*
29 * File: etimer.c
30 * Purpose: Routines for handling the machine independent
31 * event timer.
32 */
33
34#include <mach/mach_types.h>
35
36#include <kern/clock.h>
37#include <kern/thread.h>
38#include <kern/processor.h>
39#include <kern/macro_help.h>
40#include <kern/spl.h>
41#include <kern/etimer.h>
42#include <kern/pms.h>
43
44#include <machine/commpage.h>
45#include <machine/machine_routines.h>
46
47#include <sys/kdebug.h>
48
49#ifdef __ppc__
50#include <ppc/exception.h>
51#else
52#include <i386/cpu_data.h>
53#endif
54
55#include <sys/kdebug.h>
56
57
58/* XXX from <arch>/rtclock.c */
59uint32_t rtclock_tick_interval;
60clock_timer_func_t rtclock_timer_expire;
61
62#ifdef __ppc__
63# define PER_PROC_INFO struct per_proc_info
64# define GET_PER_PROC_INFO() getPerProc()
65#else
66# define PER_PROC_INFO cpu_data_t
67# define GET_PER_PROC_INFO() current_cpu_datap()
68#endif
69
70/*
71 * Event timer interrupt.
72 *
73 * XXX a drawback of this implementation is that events serviced earlier must not set deadlines
74 * that occur before the entire chain completes.
75 *
76 * XXX a better implementation would use a set of generic callouts and iterate over them
77 */
78void etimer_intr(int inuser, uint64_t iaddr) {
79
80 uint64_t abstime;
81 rtclock_timer_t *mytimer;
82 PER_PROC_INFO *pp;
83
84 pp = GET_PER_PROC_INFO();
85
86 mytimer = &pp->rtclock_timer; /* Point to the event timer */
87
88 abstime = mach_absolute_time(); /* Get the time now */
89
90 /* is it time for power management state change? */
91 if (pp->pms.pmsPop <= abstime) {
92
93 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 3) | DBG_FUNC_START, 0, 0, 0, 0, 0);
94 pmsStep(1); /* Yes, advance step */
95 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 3) | DBG_FUNC_END, 0, 0, 0, 0, 0);
96
97 abstime = mach_absolute_time(); /* Get the time again since we ran a bit */
98 }
99
100 /* have we passed the rtclock pop time? */
101 if (pp->rtclock_intr_deadline <= abstime) {
102
103 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 4) | DBG_FUNC_START, (int)rtclock_tick_interval, 0, 0, 0, 0);
104
105 clock_deadline_for_periodic_event(rtclock_tick_interval,
106 abstime,
107 &pp->rtclock_intr_deadline);
108
109 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 4) | DBG_FUNC_END, 0, 0, 0, 0, 0);
110#if STAT_TIME
111 hertz_tick(NSEC_PER_HZ, inuser, iaddr); /* Accumulate hertz */
112#else
113 hertz_tick(inuser, iaddr); /* Accumulate hertz */
114#endif
115
116 abstime = mach_absolute_time(); /* Refresh the current time since we went away */
117 }
118
119 /* has a pending clock timer expired? */
120 if (mytimer->deadline <= abstime) { /* Have we expired the deadline? */
121 mytimer->has_expired = TRUE; /* Remember that we popped */
122 mytimer->deadline = EndOfAllTime; /* Set timer request to the end of all time in case we have no more events */
123 (*rtclock_timer_expire)(abstime); /* Process pop */
124 mytimer->has_expired = FALSE;
125 }
126
127 /* schedule our next deadline */
128 pp->rtcPop = EndOfAllTime; /* any real deadline will be earlier */
129 etimer_resync_deadlines();
130}
131
132/*
133 * Set the clock deadline; called by the thread scheduler.
134 */
135void etimer_set_deadline(uint64_t deadline)
136{
137 rtclock_timer_t *mytimer;
138 spl_t s;
139 PER_PROC_INFO *pp;
140
141 s = splclock(); /* no interruptions */
142 pp = GET_PER_PROC_INFO();
143
144 mytimer = &pp->rtclock_timer; /* Point to the timer itself */
145 mytimer->deadline = deadline; /* Set the new expiration time */
146
147 etimer_resync_deadlines();
148
149 splx(s);
150}
151
152/*
153 * Re-evaluate the outstanding deadlines and select the most proximate.
154 *
155 * Should be called at splclock.
156 */
157void
158etimer_resync_deadlines(void)
159{
160 uint64_t deadline;
161 rtclock_timer_t *mytimer;
162 spl_t s = splclock(); /* No interruptions please */
163 PER_PROC_INFO *pp;
164
165 pp = GET_PER_PROC_INFO();
166
167 deadline = 0;
168
169 /* next rtclock interrupt? */
170 if (pp->rtclock_intr_deadline > 0)
171 deadline = pp->rtclock_intr_deadline;
172
173 /* if we have a clock timer set sooner, pop on that */
174 mytimer = &pp->rtclock_timer; /* Point to the timer itself */
175 if ((!mytimer->has_expired) && (mytimer->deadline > 0) && (mytimer->deadline < deadline))
176 deadline = mytimer->deadline;
177
178 /* if we have a power management event coming up, how about that? */
179 if ((pp->pms.pmsPop > 0) && (pp->pms.pmsPop < deadline))
180 deadline = pp->pms.pmsPop;
181
182#ifdef __ppc__
183#endif
184
185 if ((deadline > 0) && (deadline < pp->rtcPop)) {
186 int decr;
187
188 pp->rtcPop = deadline;
189 decr = setPop(deadline);
190
191 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1) | DBG_FUNC_NONE, decr, 2, 0, 0, 0);
192 }
193 splx(s);
194}