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