]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOTimerEventSource.cpp
f3ec2c305394e5da8168ec3f074dafdbf2c15fe1
[apple/xnu.git] / iokit / Kernel / IOTimerEventSource.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
25 *
26 * IOTimerEventSource.cpp
27 *
28 * HISTORY
29 * 2-Feb-1999 Joe Liu (jliu) created.
30 * 1999-10-14 Godfrey van der Linden(gvdl)
31 * Revamped to use thread_call APIs
32 *
33 */
34
35 #include <sys/cdefs.h>
36
37 __BEGIN_DECLS
38 #include <kern/thread_call.h>
39 __END_DECLS
40
41 #include <IOKit/assert.h>
42 #include <IOKit/system.h>
43
44 #include <IOKit/IOLib.h>
45 #include <IOKit/IOTimerEventSource.h>
46 #include <IOKit/IOWorkLoop.h>
47
48 #include <IOKit/IOTimeStamp.h>
49
50 #define super IOEventSource
51 OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource)
52 OSMetaClassDefineReservedUnused(IOTimerEventSource, 0);
53 OSMetaClassDefineReservedUnused(IOTimerEventSource, 1);
54 OSMetaClassDefineReservedUnused(IOTimerEventSource, 2);
55 OSMetaClassDefineReservedUnused(IOTimerEventSource, 3);
56 OSMetaClassDefineReservedUnused(IOTimerEventSource, 4);
57 OSMetaClassDefineReservedUnused(IOTimerEventSource, 5);
58 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6);
59 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7);
60
61 //
62 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
63 // not a subclassed implementation.
64 //
65
66 bool IOTimerEventSource::checkForWork() { return false; }
67
68 // Timeout handler function. This function is called by the kernel when
69 // the timeout interval expires.
70 //
71 void IOTimerEventSource::timeout(void *self)
72 {
73 IOTimerEventSource *me = (IOTimerEventSource *) self;
74
75 if (me->enabled && me->action)
76 {
77 IOWorkLoop *
78 wl = me->workLoop;
79 if (wl)
80 {
81 Action doit;
82 wl->closeGate();
83 doit = (Action) me->action;
84 if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime))
85 {
86 IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION),
87 (unsigned int) doit, (unsigned int) me->owner);
88 (*doit)(me->owner, me);
89 }
90 wl->openGate();
91 }
92 }
93 }
94
95 void IOTimerEventSource::timeoutAndRelease(void * self, void * count)
96 {
97 IOTimerEventSource *me = (IOTimerEventSource *) self;
98
99 if (me->enabled && me->action)
100 {
101 IOWorkLoop *
102 wl = me->reserved->workLoop;
103 if (wl)
104 {
105 Action doit;
106 wl->closeGate();
107 doit = (Action) me->action;
108 if (doit && (me->reserved->calloutGeneration == (SInt32) count))
109 {
110 IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION),
111 (unsigned int) doit, (unsigned int) me->owner);
112 (*doit)(me->owner, me);
113 }
114 wl->openGate();
115 }
116 }
117
118 me->reserved->workLoop->release();
119 me->release();
120 }
121
122 void IOTimerEventSource::setTimeoutFunc()
123 {
124 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
125 // not a subclassed implementation
126 reserved = IONew(ExpansionData, 1);
127 calloutEntry = (void *) thread_call_allocate((thread_call_func_t) &IOTimerEventSource::timeoutAndRelease,
128 (thread_call_param_t) this);
129 }
130
131 bool IOTimerEventSource::init(OSObject *inOwner, Action inAction)
132 {
133 if (!super::init(inOwner, (IOEventSource::Action) inAction) )
134 return false;
135
136 setTimeoutFunc();
137 if (!calloutEntry)
138 return false;
139
140 return true;
141 }
142
143 IOTimerEventSource *
144 IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction)
145 {
146 IOTimerEventSource *me = new IOTimerEventSource;
147
148 if (me && !me->init(inOwner, inAction)) {
149 me->release();
150 return 0;
151 }
152
153 return me;
154 }
155
156 void IOTimerEventSource::free()
157 {
158 if (calloutEntry) {
159 cancelTimeout();
160 thread_call_free((thread_call_t) calloutEntry);
161 }
162
163 if (reserved)
164 IODelete(reserved, ExpansionData, 1);
165
166 super::free();
167 }
168
169 void IOTimerEventSource::cancelTimeout()
170 {
171 if (reserved)
172 reserved->calloutGeneration++;
173 bool active = thread_call_cancel((thread_call_t) calloutEntry);
174 AbsoluteTime_to_scalar(&abstime) = 0;
175 if (active && reserved)
176 {
177 release();
178 workLoop->release();
179 }
180 }
181
182 void IOTimerEventSource::enable()
183 {
184 super::enable();
185 if (kIOReturnSuccess != wakeAtTime(abstime))
186 super::disable(); // Problem re-scheduling timeout ignore enable
187 }
188
189 void IOTimerEventSource::disable()
190 {
191 if (reserved)
192 reserved->calloutGeneration++;
193 bool active = thread_call_cancel((thread_call_t) calloutEntry);
194 super::disable();
195 if (active && reserved)
196 {
197 release();
198 workLoop->release();
199 }
200 }
201
202 IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
203 {
204 return setTimeout(ticks, kTickScale);
205 }
206
207 IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms)
208 {
209 return setTimeout(ms, kMillisecondScale);
210 }
211
212 IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us)
213 {
214 return setTimeout(us, kMicrosecondScale);
215 }
216
217 IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
218 {
219 AbsoluteTime end;
220
221 clock_interval_to_deadline(interval, scale_factor, &end);
222 return wakeAtTime(end);
223 }
224
225 IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval)
226 {
227 AbsoluteTime end, nsecs;
228
229 clock_interval_to_absolutetime_interval
230 (interval.tv_nsec, kNanosecondScale, &nsecs);
231 clock_interval_to_deadline
232 (interval.tv_sec, NSEC_PER_SEC, &end);
233 ADD_ABSOLUTETIME(&end, &nsecs);
234
235 return wakeAtTime(end);
236 }
237
238 IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval)
239 {
240 AbsoluteTime end;
241
242 clock_get_uptime(&end);
243 ADD_ABSOLUTETIME(&end, &interval);
244
245 return wakeAtTime(end);
246 }
247
248 IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
249 {
250 return wakeAtTime(ticks, kTickScale);
251 }
252
253 IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
254 {
255 return wakeAtTime(ms, kMillisecondScale);
256 }
257
258 IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us)
259 {
260 return wakeAtTime(us, kMicrosecondScale);
261 }
262
263 IOReturn IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
264 {
265 AbsoluteTime end;
266 clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
267
268 return wakeAtTime(end);
269 }
270
271 IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
272 {
273 AbsoluteTime end, nsecs;
274
275 clock_interval_to_absolutetime_interval
276 (inAbstime.tv_nsec, kNanosecondScale, &nsecs);
277 clock_interval_to_absolutetime_interval
278 (inAbstime.tv_sec, kSecondScale, &end);
279 ADD_ABSOLUTETIME(&end, &nsecs);
280
281 return wakeAtTime(end);
282 }
283
284 void IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
285 {
286 super::setWorkLoop(inWorkLoop);
287 if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop )
288 wakeAtTime(abstime);
289 }
290
291 IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
292 {
293 if (!action)
294 return kIOReturnNoResources;
295
296 abstime = inAbstime;
297 if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop )
298 {
299 if (reserved)
300 {
301 retain();
302 workLoop->retain();
303 reserved->workLoop = workLoop;
304 reserved->calloutGeneration++;
305 if (thread_call_enter1_delayed((thread_call_t) calloutEntry,
306 (void *) reserved->calloutGeneration, abstime))
307 {
308 release();
309 workLoop->release();
310 }
311 }
312 else
313 thread_call_enter_delayed((thread_call_t) calloutEntry, abstime);
314 }
315
316 return kIOReturnSuccess;
317 }