2 * Copyright (c) 1998-2000, 2009-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/cdefs.h>
32 #include <kern/thread_call.h>
35 #include <IOKit/assert.h>
36 #include <IOKit/system.h>
38 #include <IOKit/IOLib.h>
39 #include <IOKit/IOTimerEventSource.h>
40 #include <IOKit/IOWorkLoop.h>
42 #include <IOKit/IOTimeStamp.h>
43 #include <IOKit/IOKitDebug.h>
48 #define super IOEventSource
49 OSDefineMetaClassAndStructors(IOTimerEventSource
, IOEventSource
)
50 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 0);
51 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 1);
52 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 2);
53 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 3);
54 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 4);
55 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 5);
56 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 6);
57 OSMetaClassDefineReservedUnused(IOTimerEventSource
, 7);
61 #define IOStatisticsInitializeCounter() \
63 IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsTimerEventSourceCounter); \
66 #define IOStatisticsOpenGate() \
68 IOStatistics::countOpenGate(me->IOEventSource::reserved->counter); \
71 #define IOStatisticsCloseGate() \
73 IOStatistics::countCloseGate(me->IOEventSource::reserved->counter); \
76 #define IOStatisticsTimeout() \
78 IOStatistics::countTimerTimeout(me->IOEventSource::reserved->counter); \
83 #define IOStatisticsInitializeCounter()
84 #define IOStatisticsOpenGate()
85 #define IOStatisticsCloseGate()
86 #define IOStatisticsTimeout()
88 #endif /* IOKITSTATS */
91 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
92 // not a subclassed implementation.
95 // Timeout handler function. This function is called by the kernel when
96 // the timeout interval expires.
98 void IOTimerEventSource::timeout(void *self
)
100 IOTimerEventSource
*me
= (IOTimerEventSource
*) self
;
102 IOStatisticsTimeout();
104 if (me
->enabled
&& me
->action
)
112 IOStatisticsCloseGate();
113 doit
= (Action
) me
->action
;
114 if (doit
&& me
->enabled
&& AbsoluteTime_to_scalar(&me
->abstime
))
116 bool trace
= (gIOKitTrace
& kIOTraceTimers
) ? true : false;
119 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION
),
120 VM_KERNEL_UNSLIDE(doit
), (uintptr_t) me
->owner
);
122 (*doit
)(me
->owner
, me
);
124 DTRACE_TMR3(iotescallout__expire
, Action
, doit
, OSObject
, me
->owner
, void, me
->workLoop
);
128 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION
),
129 VM_KERNEL_UNSLIDE(doit
), (uintptr_t) me
->owner
);
131 IOStatisticsOpenGate();
137 void IOTimerEventSource::timeoutAndRelease(void * self
, void * c
)
139 IOTimerEventSource
*me
= (IOTimerEventSource
*) self
;
140 /* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
141 must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
142 SInt32 count
= (SInt32
) (long) c
;
144 IOStatisticsTimeout();
146 if (me
->enabled
&& me
->action
)
149 wl
= me
->reserved
->workLoop
;
154 IOStatisticsCloseGate();
155 doit
= (Action
) me
->action
;
156 if (doit
&& (me
->reserved
->calloutGeneration
== count
))
158 bool trace
= (gIOKitTrace
& kIOTraceTimers
) ? true : false;
161 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION
),
162 VM_KERNEL_UNSLIDE(doit
), (uintptr_t) me
->owner
);
164 (*doit
)(me
->owner
, me
);
166 DTRACE_TMR3(iotescallout__expire
, Action
, doit
, OSObject
, me
->owner
, void, me
->workLoop
);
170 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION
),
171 VM_KERNEL_UNSLIDE(doit
), (uintptr_t) me
->owner
);
173 IOStatisticsOpenGate();
178 me
->reserved
->workLoop
->release();
182 void IOTimerEventSource::setTimeoutFunc()
184 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
185 // not a subclassed implementation
186 reserved
= IONew(ExpansionData
, 1);
187 calloutEntry
= (void *) thread_call_allocate((thread_call_func_t
) &IOTimerEventSource::timeoutAndRelease
,
188 (thread_call_param_t
) this);
191 bool IOTimerEventSource::init(OSObject
*inOwner
, Action inAction
)
193 if (!super::init(inOwner
, (IOEventSource::Action
) inAction
) )
200 IOStatisticsInitializeCounter();
206 IOTimerEventSource::timerEventSource(OSObject
*inOwner
, Action inAction
)
208 IOTimerEventSource
*me
= new IOTimerEventSource
;
210 if (me
&& !me
->init(inOwner
, inAction
)) {
218 void IOTimerEventSource::free()
222 thread_call_free((thread_call_t
) calloutEntry
);
226 IODelete(reserved
, ExpansionData
, 1);
231 void IOTimerEventSource::cancelTimeout()
234 reserved
->calloutGeneration
++;
235 bool active
= thread_call_cancel((thread_call_t
) calloutEntry
);
236 AbsoluteTime_to_scalar(&abstime
) = 0;
237 if (active
&& reserved
)
244 void IOTimerEventSource::enable()
247 if (kIOReturnSuccess
!= wakeAtTime(abstime
))
248 super::disable(); // Problem re-scheduling timeout ignore enable
251 void IOTimerEventSource::disable()
254 reserved
->calloutGeneration
++;
255 bool active
= thread_call_cancel((thread_call_t
) calloutEntry
);
257 if (active
&& reserved
)
264 IOReturn
IOTimerEventSource::setTimeoutTicks(UInt32 ticks
)
266 return setTimeout(ticks
, kTickScale
);
269 IOReturn
IOTimerEventSource::setTimeoutMS(UInt32 ms
)
271 return setTimeout(ms
, kMillisecondScale
);
274 IOReturn
IOTimerEventSource::setTimeoutUS(UInt32 us
)
276 return setTimeout(us
, kMicrosecondScale
);
279 IOReturn
IOTimerEventSource::setTimeout(UInt32 interval
, UInt32 scale_factor
)
283 clock_interval_to_deadline(interval
, scale_factor
, &end
);
284 return wakeAtTime(end
);
287 #if !defined(__LP64__)
288 IOReturn
IOTimerEventSource::setTimeout(mach_timespec_t interval
)
290 AbsoluteTime end
, nsecs
;
292 clock_interval_to_absolutetime_interval
293 (interval
.tv_nsec
, kNanosecondScale
, &nsecs
);
294 clock_interval_to_deadline
295 (interval
.tv_sec
, NSEC_PER_SEC
, &end
);
296 ADD_ABSOLUTETIME(&end
, &nsecs
);
298 return wakeAtTime(end
);
302 IOReturn
IOTimerEventSource::setTimeout(AbsoluteTime interval
)
306 clock_get_uptime(&end
);
307 ADD_ABSOLUTETIME(&end
, &interval
);
309 return wakeAtTime(end
);
312 IOReturn
IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks
)
314 return wakeAtTime(ticks
, kTickScale
);
317 IOReturn
IOTimerEventSource::wakeAtTimeMS(UInt32 ms
)
319 return wakeAtTime(ms
, kMillisecondScale
);
322 IOReturn
IOTimerEventSource::wakeAtTimeUS(UInt32 us
)
324 return wakeAtTime(us
, kMicrosecondScale
);
327 IOReturn
IOTimerEventSource::wakeAtTime(UInt32 inAbstime
, UInt32 scale_factor
)
330 clock_interval_to_absolutetime_interval(inAbstime
, scale_factor
, &end
);
332 return wakeAtTime(end
);
335 #if !defined(__LP64__)
336 IOReturn
IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime
)
338 AbsoluteTime end
, nsecs
;
340 clock_interval_to_absolutetime_interval
341 (inAbstime
.tv_nsec
, kNanosecondScale
, &nsecs
);
342 clock_interval_to_absolutetime_interval
343 (inAbstime
.tv_sec
, kSecondScale
, &end
);
344 ADD_ABSOLUTETIME(&end
, &nsecs
);
346 return wakeAtTime(end
);
350 void IOTimerEventSource::setWorkLoop(IOWorkLoop
*inWorkLoop
)
352 super::setWorkLoop(inWorkLoop
);
353 if ( enabled
&& AbsoluteTime_to_scalar(&abstime
) && workLoop
)
357 IOReturn
IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime
)
360 return kIOReturnNoResources
;
363 if ( enabled
&& AbsoluteTime_to_scalar(&inAbstime
) && AbsoluteTime_to_scalar(&abstime
) && workLoop
)
369 reserved
->workLoop
= workLoop
;
370 reserved
->calloutGeneration
++;
371 if (thread_call_enter1_delayed((thread_call_t
) calloutEntry
,
372 (void *)(uintptr_t) reserved
->calloutGeneration
, inAbstime
))
379 thread_call_enter_delayed((thread_call_t
) calloutEntry
, inAbstime
);
382 return kIOReturnSuccess
;