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