]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOTimerEventSource.cpp
xnu-2050.18.24.tar.gz
[apple/xnu.git] / iokit / Kernel / IOTimerEventSource.cpp
CommitLineData
1c79356b 1/*
6d2010ae 2 * Copyright (c) 1998-2000, 2009-2010 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b
A
28
29#include <sys/cdefs.h>
30
31__BEGIN_DECLS
32#include <kern/thread_call.h>
33__END_DECLS
34
35#include <IOKit/assert.h>
36#include <IOKit/system.h>
37
38#include <IOKit/IOLib.h>
39#include <IOKit/IOTimerEventSource.h>
40#include <IOKit/IOWorkLoop.h>
41
42#include <IOKit/IOTimeStamp.h>
060df5ea 43#include <IOKit/IOKitDebug.h>
1c79356b
A
44
45#define super IOEventSource
46OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource)
47OSMetaClassDefineReservedUnused(IOTimerEventSource, 0);
48OSMetaClassDefineReservedUnused(IOTimerEventSource, 1);
49OSMetaClassDefineReservedUnused(IOTimerEventSource, 2);
50OSMetaClassDefineReservedUnused(IOTimerEventSource, 3);
51OSMetaClassDefineReservedUnused(IOTimerEventSource, 4);
52OSMetaClassDefineReservedUnused(IOTimerEventSource, 5);
53OSMetaClassDefineReservedUnused(IOTimerEventSource, 6);
54OSMetaClassDefineReservedUnused(IOTimerEventSource, 7);
55
6d2010ae
A
56#if IOKITSTATS
57
58#define IOStatisticsInitializeCounter() \
59do { \
60 IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsTimerEventSourceCounter); \
61} while (0)
62
63#define IOStatisticsOpenGate() \
64do { \
65 IOStatistics::countOpenGate(me->IOEventSource::reserved->counter); \
66} while (0)
67
68#define IOStatisticsCloseGate() \
69do { \
70 IOStatistics::countCloseGate(me->IOEventSource::reserved->counter); \
71} while (0)
72
73#define IOStatisticsTimeout() \
74do { \
75 IOStatistics::countTimerTimeout(me->IOEventSource::reserved->counter); \
76} while (0)
77
78#else
79
80#define IOStatisticsInitializeCounter()
81#define IOStatisticsOpenGate()
82#define IOStatisticsCloseGate()
83#define IOStatisticsTimeout()
84
85#endif /* IOKITSTATS */
86
91447636
A
87//
88// reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
89// not a subclassed implementation.
90//
91
1c79356b
A
92// Timeout handler function. This function is called by the kernel when
93// the timeout interval expires.
94//
95void IOTimerEventSource::timeout(void *self)
96{
97 IOTimerEventSource *me = (IOTimerEventSource *) self;
98
6d2010ae
A
99 IOStatisticsTimeout();
100
91447636
A
101 if (me->enabled && me->action)
102 {
103 IOWorkLoop *
104 wl = me->workLoop;
105 if (wl)
106 {
107 Action doit;
108 wl->closeGate();
6d2010ae 109 IOStatisticsCloseGate();
91447636
A
110 doit = (Action) me->action;
111 if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime))
112 {
060df5ea
A
113 bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false;
114
115 if (trace)
116 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION),
6d2010ae 117 (uintptr_t) doit, (uintptr_t) me->owner);
060df5ea 118
91447636 119 (*doit)(me->owner, me);
060df5ea
A
120
121 if (trace)
122 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
123 (uintptr_t) doit, (uintptr_t) me->owner);
91447636 124 }
6d2010ae 125 IOStatisticsOpenGate();
91447636
A
126 wl->openGate();
127 }
128 }
129}
1c79356b 130
b0d623f7 131void IOTimerEventSource::timeoutAndRelease(void * self, void * c)
91447636
A
132{
133 IOTimerEventSource *me = (IOTimerEventSource *) self;
b0d623f7
A
134 /* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
135 must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
136 SInt32 count = (SInt32) (long) c;
91447636 137
6d2010ae
A
138 IOStatisticsTimeout();
139
91447636
A
140 if (me->enabled && me->action)
141 {
142 IOWorkLoop *
143 wl = me->reserved->workLoop;
144 if (wl)
145 {
146 Action doit;
147 wl->closeGate();
6d2010ae 148 IOStatisticsCloseGate();
91447636 149 doit = (Action) me->action;
b0d623f7 150 if (doit && (me->reserved->calloutGeneration == count))
91447636 151 {
060df5ea
A
152 bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false;
153
154 if (trace)
155 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION),
6d2010ae 156 (uintptr_t) doit, (uintptr_t) me->owner);
060df5ea 157
91447636 158 (*doit)(me->owner, me);
060df5ea
A
159
160 if (trace)
161 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
162 (uintptr_t) doit, (uintptr_t) me->owner);
91447636 163 }
6d2010ae 164 IOStatisticsOpenGate();
91447636 165 wl->openGate();
1c79356b
A
166 }
167 }
91447636
A
168
169 me->reserved->workLoop->release();
170 me->release();
1c79356b
A
171}
172
173void IOTimerEventSource::setTimeoutFunc()
174{
91447636
A
175 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
176 // not a subclassed implementation
177 reserved = IONew(ExpansionData, 1);
178 calloutEntry = (void *) thread_call_allocate((thread_call_func_t) &IOTimerEventSource::timeoutAndRelease,
1c79356b
A
179 (thread_call_param_t) this);
180}
181
182bool IOTimerEventSource::init(OSObject *inOwner, Action inAction)
183{
184 if (!super::init(inOwner, (IOEventSource::Action) inAction) )
185 return false;
186
187 setTimeoutFunc();
188 if (!calloutEntry)
189 return false;
190
6d2010ae
A
191 IOStatisticsInitializeCounter();
192
1c79356b
A
193 return true;
194}
195
196IOTimerEventSource *
197IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction)
198{
199 IOTimerEventSource *me = new IOTimerEventSource;
200
201 if (me && !me->init(inOwner, inAction)) {
55e303ae 202 me->release();
1c79356b
A
203 return 0;
204 }
205
206 return me;
207}
208
209void IOTimerEventSource::free()
210{
211 if (calloutEntry) {
212 cancelTimeout();
213 thread_call_free((thread_call_t) calloutEntry);
214 }
215
91447636
A
216 if (reserved)
217 IODelete(reserved, ExpansionData, 1);
218
1c79356b
A
219 super::free();
220}
221
222void IOTimerEventSource::cancelTimeout()
223{
91447636
A
224 if (reserved)
225 reserved->calloutGeneration++;
226 bool active = thread_call_cancel((thread_call_t) calloutEntry);
1c79356b 227 AbsoluteTime_to_scalar(&abstime) = 0;
91447636
A
228 if (active && reserved)
229 {
230 release();
231 workLoop->release();
232 }
1c79356b
A
233}
234
235void IOTimerEventSource::enable()
236{
237 super::enable();
238 if (kIOReturnSuccess != wakeAtTime(abstime))
239 super::disable(); // Problem re-scheduling timeout ignore enable
240}
241
242void IOTimerEventSource::disable()
243{
91447636
A
244 if (reserved)
245 reserved->calloutGeneration++;
246 bool active = thread_call_cancel((thread_call_t) calloutEntry);
1c79356b 247 super::disable();
91447636
A
248 if (active && reserved)
249 {
250 release();
251 workLoop->release();
252 }
1c79356b
A
253}
254
255IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
256{
91447636 257 return setTimeout(ticks, kTickScale);
1c79356b
A
258}
259
260IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms)
261{
262 return setTimeout(ms, kMillisecondScale);
263}
264
265IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us)
266{
267 return setTimeout(us, kMicrosecondScale);
268}
269
270IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
271{
272 AbsoluteTime end;
2d21ac55 273
1c79356b
A
274 clock_interval_to_deadline(interval, scale_factor, &end);
275 return wakeAtTime(end);
276}
277
b0d623f7 278#if !defined(__LP64__)
1c79356b
A
279IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval)
280{
281 AbsoluteTime end, nsecs;
282
283 clock_interval_to_absolutetime_interval
284 (interval.tv_nsec, kNanosecondScale, &nsecs);
285 clock_interval_to_deadline
286 (interval.tv_sec, NSEC_PER_SEC, &end);
287 ADD_ABSOLUTETIME(&end, &nsecs);
288
289 return wakeAtTime(end);
290}
b0d623f7 291#endif
1c79356b
A
292
293IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval)
294{
295 AbsoluteTime end;
296
297 clock_get_uptime(&end);
298 ADD_ABSOLUTETIME(&end, &interval);
299
300 return wakeAtTime(end);
301}
302
303IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
304{
91447636 305 return wakeAtTime(ticks, kTickScale);
1c79356b
A
306}
307
308IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
309{
310 return wakeAtTime(ms, kMillisecondScale);
311}
312
313IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us)
314{
315 return wakeAtTime(us, kMicrosecondScale);
316}
317
91447636 318IOReturn IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
1c79356b
A
319{
320 AbsoluteTime end;
91447636 321 clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
1c79356b
A
322
323 return wakeAtTime(end);
324}
325
b0d623f7 326#if !defined(__LP64__)
91447636 327IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
1c79356b
A
328{
329 AbsoluteTime end, nsecs;
330
331 clock_interval_to_absolutetime_interval
91447636 332 (inAbstime.tv_nsec, kNanosecondScale, &nsecs);
1c79356b 333 clock_interval_to_absolutetime_interval
91447636 334 (inAbstime.tv_sec, kSecondScale, &end);
1c79356b
A
335 ADD_ABSOLUTETIME(&end, &nsecs);
336
337 return wakeAtTime(end);
338}
b0d623f7 339#endif
1c79356b 340
91447636
A
341void IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
342{
343 super::setWorkLoop(inWorkLoop);
344 if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop )
345 wakeAtTime(abstime);
346}
347
1c79356b
A
348IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
349{
350 if (!action)
351 return kIOReturnNoResources;
352
353 abstime = inAbstime;
c910b4d9 354 if ( enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop )
91447636
A
355 {
356 if (reserved)
357 {
358 retain();
359 workLoop->retain();
360 reserved->workLoop = workLoop;
361 reserved->calloutGeneration++;
362 if (thread_call_enter1_delayed((thread_call_t) calloutEntry,
c910b4d9 363 (void *) reserved->calloutGeneration, inAbstime))
91447636
A
364 {
365 release();
366 workLoop->release();
367 }
368 }
369 else
c910b4d9 370 thread_call_enter_delayed((thread_call_t) calloutEntry, inAbstime);
91447636 371 }
1c79356b
A
372
373 return kIOReturnSuccess;
374}