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