]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOTimerEventSource.cpp
112deeee73e2d73f0a0045f1ce5ec1aa339c1a5a
[apple/xnu.git] / iokit / Kernel / IOTimerEventSource.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
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>
43 #include <IOKit/IOKitDebug.h>
44
45 #define super IOEventSource
46 OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource)
47 OSMetaClassDefineReservedUnused(IOTimerEventSource, 0);
48 OSMetaClassDefineReservedUnused(IOTimerEventSource, 1);
49 OSMetaClassDefineReservedUnused(IOTimerEventSource, 2);
50 OSMetaClassDefineReservedUnused(IOTimerEventSource, 3);
51 OSMetaClassDefineReservedUnused(IOTimerEventSource, 4);
52 OSMetaClassDefineReservedUnused(IOTimerEventSource, 5);
53 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6);
54 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7);
55
56 //
57 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
58 // not a subclassed implementation.
59 //
60
61 bool IOTimerEventSource::checkForWork() { return false; }
62
63 // Timeout handler function. This function is called by the kernel when
64 // the timeout interval expires.
65 //
66 void IOTimerEventSource::timeout(void *self)
67 {
68 IOTimerEventSource *me = (IOTimerEventSource *) self;
69
70 if (me->enabled && me->action)
71 {
72 IOWorkLoop *
73 wl = me->workLoop;
74 if (wl)
75 {
76 Action doit;
77 wl->closeGate();
78 doit = (Action) me->action;
79 if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime))
80 {
81 bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false;
82
83 if (trace)
84 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION),
85 (uintptr_t) doit, (uintptr_t) me->owner);
86
87 (*doit)(me->owner, me);
88
89 if (trace)
90 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
91 (uintptr_t) doit, (uintptr_t) me->owner);
92 }
93 wl->openGate();
94 }
95 }
96 }
97
98 void IOTimerEventSource::timeoutAndRelease(void * self, void * c)
99 {
100 IOTimerEventSource *me = (IOTimerEventSource *) self;
101 /* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
102 must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
103 SInt32 count = (SInt32) (long) c;
104
105 if (me->enabled && me->action)
106 {
107 IOWorkLoop *
108 wl = me->reserved->workLoop;
109 if (wl)
110 {
111 Action doit;
112 wl->closeGate();
113 doit = (Action) me->action;
114 if (doit && (me->reserved->calloutGeneration == count))
115 {
116 bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false;
117
118 if (trace)
119 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION),
120 (uintptr_t) doit, (uintptr_t) me->owner);
121
122 (*doit)(me->owner, me);
123
124 if (trace)
125 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
126 (uintptr_t) doit, (uintptr_t) me->owner);
127 }
128 wl->openGate();
129 }
130 }
131
132 me->reserved->workLoop->release();
133 me->release();
134 }
135
136 void IOTimerEventSource::setTimeoutFunc()
137 {
138 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
139 // not a subclassed implementation
140 reserved = IONew(ExpansionData, 1);
141 calloutEntry = (void *) thread_call_allocate((thread_call_func_t) &IOTimerEventSource::timeoutAndRelease,
142 (thread_call_param_t) this);
143 }
144
145 bool IOTimerEventSource::init(OSObject *inOwner, Action inAction)
146 {
147 if (!super::init(inOwner, (IOEventSource::Action) inAction) )
148 return false;
149
150 setTimeoutFunc();
151 if (!calloutEntry)
152 return false;
153
154 return true;
155 }
156
157 IOTimerEventSource *
158 IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction)
159 {
160 IOTimerEventSource *me = new IOTimerEventSource;
161
162 if (me && !me->init(inOwner, inAction)) {
163 me->release();
164 return 0;
165 }
166
167 return me;
168 }
169
170 void IOTimerEventSource::free()
171 {
172 if (calloutEntry) {
173 cancelTimeout();
174 thread_call_free((thread_call_t) calloutEntry);
175 }
176
177 if (reserved)
178 IODelete(reserved, ExpansionData, 1);
179
180 super::free();
181 }
182
183 void IOTimerEventSource::cancelTimeout()
184 {
185 if (reserved)
186 reserved->calloutGeneration++;
187 bool active = thread_call_cancel((thread_call_t) calloutEntry);
188 AbsoluteTime_to_scalar(&abstime) = 0;
189 if (active && reserved)
190 {
191 release();
192 workLoop->release();
193 }
194 }
195
196 void IOTimerEventSource::enable()
197 {
198 super::enable();
199 if (kIOReturnSuccess != wakeAtTime(abstime))
200 super::disable(); // Problem re-scheduling timeout ignore enable
201 }
202
203 void IOTimerEventSource::disable()
204 {
205 if (reserved)
206 reserved->calloutGeneration++;
207 bool active = thread_call_cancel((thread_call_t) calloutEntry);
208 super::disable();
209 if (active && reserved)
210 {
211 release();
212 workLoop->release();
213 }
214 }
215
216 IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
217 {
218 return setTimeout(ticks, kTickScale);
219 }
220
221 IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms)
222 {
223 return setTimeout(ms, kMillisecondScale);
224 }
225
226 IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us)
227 {
228 return setTimeout(us, kMicrosecondScale);
229 }
230
231 IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
232 {
233 AbsoluteTime end;
234
235 clock_interval_to_deadline(interval, scale_factor, &end);
236 return wakeAtTime(end);
237 }
238
239 #if !defined(__LP64__)
240 IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval)
241 {
242 AbsoluteTime end, nsecs;
243
244 clock_interval_to_absolutetime_interval
245 (interval.tv_nsec, kNanosecondScale, &nsecs);
246 clock_interval_to_deadline
247 (interval.tv_sec, NSEC_PER_SEC, &end);
248 ADD_ABSOLUTETIME(&end, &nsecs);
249
250 return wakeAtTime(end);
251 }
252 #endif
253
254 IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval)
255 {
256 AbsoluteTime end;
257
258 clock_get_uptime(&end);
259 ADD_ABSOLUTETIME(&end, &interval);
260
261 return wakeAtTime(end);
262 }
263
264 IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
265 {
266 return wakeAtTime(ticks, kTickScale);
267 }
268
269 IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
270 {
271 return wakeAtTime(ms, kMillisecondScale);
272 }
273
274 IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us)
275 {
276 return wakeAtTime(us, kMicrosecondScale);
277 }
278
279 IOReturn IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
280 {
281 AbsoluteTime end;
282 clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
283
284 return wakeAtTime(end);
285 }
286
287 #if !defined(__LP64__)
288 IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
289 {
290 AbsoluteTime end, nsecs;
291
292 clock_interval_to_absolutetime_interval
293 (inAbstime.tv_nsec, kNanosecondScale, &nsecs);
294 clock_interval_to_absolutetime_interval
295 (inAbstime.tv_sec, kSecondScale, &end);
296 ADD_ABSOLUTETIME(&end, &nsecs);
297
298 return wakeAtTime(end);
299 }
300 #endif
301
302 void IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
303 {
304 super::setWorkLoop(inWorkLoop);
305 if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop )
306 wakeAtTime(abstime);
307 }
308
309 IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
310 {
311 if (!action)
312 return kIOReturnNoResources;
313
314 abstime = inAbstime;
315 if ( enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop )
316 {
317 if (reserved)
318 {
319 retain();
320 workLoop->retain();
321 reserved->workLoop = workLoop;
322 reserved->calloutGeneration++;
323 if (thread_call_enter1_delayed((thread_call_t) calloutEntry,
324 (void *) reserved->calloutGeneration, inAbstime))
325 {
326 release();
327 workLoop->release();
328 }
329 }
330 else
331 thread_call_enter_delayed((thread_call_t) calloutEntry, inAbstime);
332 }
333
334 return kIOReturnSuccess;
335 }