1c1dac77fSApple OSS Distributions /*
2855239e5SApple OSS Distributions  * Copyright (c) 1998-2000, 2009-2010 Apple Inc. All rights reserved.
3c1dac77fSApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5c1dac77fSApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14c1dac77fSApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20c1dac77fSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21c1dac77fSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
25c1dac77fSApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27c1dac77fSApple OSS Distributions  */
28c1dac77fSApple OSS Distributions 
29bb611c8fSApple OSS Distributions #include <ptrauth.h>
30c1dac77fSApple OSS Distributions #include <sys/cdefs.h>
31c1dac77fSApple OSS Distributions 
32c1dac77fSApple OSS Distributions __BEGIN_DECLS
33c1dac77fSApple OSS Distributions #include <kern/thread_call.h>
34c1dac77fSApple OSS Distributions __END_DECLS
35c1dac77fSApple OSS Distributions 
36c1dac77fSApple OSS Distributions #include <IOKit/assert.h>
37c1dac77fSApple OSS Distributions #include <IOKit/system.h>
38c1dac77fSApple OSS Distributions 
39c1dac77fSApple OSS Distributions #include <IOKit/IOLib.h>
40c1dac77fSApple OSS Distributions #include <IOKit/IOTimerEventSource.h>
41c1dac77fSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
42c1dac77fSApple OSS Distributions 
43c1dac77fSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
44855239e5SApple OSS Distributions #include <IOKit/IOKitDebug.h>
45186b8fceSApple OSS Distributions #if CONFIG_DTRACE
46186b8fceSApple OSS Distributions #include <mach/sdt.h>
47186b8fceSApple OSS Distributions #endif
48c1dac77fSApple OSS Distributions 
49cc9a6355SApple OSS Distributions #include <libkern/Block.h>
50bb611c8fSApple OSS Distributions #include <libkern/Block_private.h>
51cc9a6355SApple OSS Distributions 
52cc9a6355SApple OSS Distributions 
53c1dac77fSApple OSS Distributions #define super IOEventSource
54c1dac77fSApple OSS Distributions OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource)
55bb611c8fSApple OSS Distributions OSMetaClassDefineReservedUsedX86(IOTimerEventSource, 0);
56bb611c8fSApple OSS Distributions OSMetaClassDefineReservedUsedX86(IOTimerEventSource, 1);
57bb611c8fSApple OSS Distributions OSMetaClassDefineReservedUsedX86(IOTimerEventSource, 2);
58c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOTimerEventSource, 3);
59c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOTimerEventSource, 4);
60c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOTimerEventSource, 5);
61c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOTimerEventSource, 6);
62c1dac77fSApple OSS Distributions OSMetaClassDefineReservedUnused(IOTimerEventSource, 7);
63c1dac77fSApple OSS Distributions 
64855239e5SApple OSS Distributions #if IOKITSTATS
65855239e5SApple OSS Distributions 
66855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter() \
67855239e5SApple OSS Distributions do { \
68855239e5SApple OSS Distributions 	IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsTimerEventSourceCounter); \
69855239e5SApple OSS Distributions } while (0)
70855239e5SApple OSS Distributions 
71855239e5SApple OSS Distributions #define IOStatisticsOpenGate() \
72855239e5SApple OSS Distributions do { \
73855239e5SApple OSS Distributions 	IOStatistics::countOpenGate(me->IOEventSource::reserved->counter); \
74855239e5SApple OSS Distributions } while (0)
75855239e5SApple OSS Distributions 
76855239e5SApple OSS Distributions #define IOStatisticsCloseGate() \
77855239e5SApple OSS Distributions do { \
78855239e5SApple OSS Distributions 	IOStatistics::countCloseGate(me->IOEventSource::reserved->counter); \
79855239e5SApple OSS Distributions } while (0)
80855239e5SApple OSS Distributions 
81855239e5SApple OSS Distributions #define IOStatisticsTimeout() \
82855239e5SApple OSS Distributions do { \
83855239e5SApple OSS Distributions 	IOStatistics::countTimerTimeout(me->IOEventSource::reserved->counter); \
84855239e5SApple OSS Distributions } while (0)
85855239e5SApple OSS Distributions 
86855239e5SApple OSS Distributions #else
87855239e5SApple OSS Distributions 
88855239e5SApple OSS Distributions #define IOStatisticsInitializeCounter()
89855239e5SApple OSS Distributions #define IOStatisticsOpenGate()
90855239e5SApple OSS Distributions #define IOStatisticsCloseGate()
91855239e5SApple OSS Distributions #define IOStatisticsTimeout()
92855239e5SApple OSS Distributions 
93855239e5SApple OSS Distributions #endif /* IOKITSTATS */
94855239e5SApple OSS Distributions 
9514e3d835SApple OSS Distributions //
9614e3d835SApple OSS Distributions // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
9714e3d835SApple OSS Distributions // not a subclassed implementation.
9814e3d835SApple OSS Distributions //
9914e3d835SApple OSS Distributions 
100c1dac77fSApple OSS Distributions // Timeout handler function. This function is called by the kernel when
101c1dac77fSApple OSS Distributions // the timeout interval expires.
102c1dac77fSApple OSS Distributions //
10376e12aa3SApple OSS Distributions 
104cc9a6355SApple OSS Distributions __inline__ void
invokeAction(IOEventSource::Action _action,IOTimerEventSource * ts,OSObject * _owner,IOWorkLoop * _workLoop)105bb611c8fSApple OSS Distributions IOTimerEventSource::invokeAction(IOEventSource::Action _action, IOTimerEventSource * ts,
106a5e72196SApple OSS Distributions     OSObject * _owner, IOWorkLoop * _workLoop)
10776e12aa3SApple OSS Distributions {
10876e12aa3SApple OSS Distributions 	bool    trace = (gIOKitTrace & kIOTraceTimers) ? true : false;
109bb611c8fSApple OSS Distributions 	void  * address;
110bb611c8fSApple OSS Distributions 
111bb611c8fSApple OSS Distributions 	if (kActionBlock & flags) {
112bb611c8fSApple OSS Distributions 		address = ptrauth_nop_cast(void *, _Block_get_invoke_fn((struct Block_layout *) actionBlock));
113bb611c8fSApple OSS Distributions 	} else {
114bb611c8fSApple OSS Distributions 		address = ptrauth_nop_cast(void *, _action);
115bb611c8fSApple OSS Distributions 	}
11676e12aa3SApple OSS Distributions 
117a5e72196SApple OSS Distributions 	if (trace) {
11876e12aa3SApple OSS Distributions 		IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION),
119bb611c8fSApple OSS Distributions 		    VM_KERNEL_ADDRHIDE(address),
120bb611c8fSApple OSS Distributions 		    VM_KERNEL_ADDRHIDE(_owner));
12176e12aa3SApple OSS Distributions 	}
12276e12aa3SApple OSS Distributions 
123a5e72196SApple OSS Distributions 	if (kActionBlock & flags) {
124a5e72196SApple OSS Distributions 		((IOTimerEventSource::ActionBlock) actionBlock)(ts);
125a5e72196SApple OSS Distributions 	} else {
126bb611c8fSApple OSS Distributions 		((IOTimerEventSource::Action)_action)(_owner, ts);
127a5e72196SApple OSS Distributions 	}
128a5e72196SApple OSS Distributions 
129a5e72196SApple OSS Distributions #if CONFIG_DTRACE
130bb611c8fSApple OSS Distributions 	DTRACE_TMR3(iotescallout__expire, Action, address, OSObject, _owner, void, _workLoop);
131a5e72196SApple OSS Distributions #endif
132a5e72196SApple OSS Distributions 
133a5e72196SApple OSS Distributions 	if (trace) {
134a5e72196SApple OSS Distributions 		IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
135bb611c8fSApple OSS Distributions 		    VM_KERNEL_UNSLIDE(address),
136bb611c8fSApple OSS Distributions 		    VM_KERNEL_ADDRHIDE(_owner));
137a5e72196SApple OSS Distributions 	}
138a5e72196SApple OSS Distributions }
139a5e72196SApple OSS Distributions 
140a5e72196SApple OSS Distributions void
timeout(void * self)141a5e72196SApple OSS Distributions IOTimerEventSource::timeout(void *self)
142c1dac77fSApple OSS Distributions {
143c1dac77fSApple OSS Distributions 	IOTimerEventSource *me = (IOTimerEventSource *) self;
144c1dac77fSApple OSS Distributions 
145855239e5SApple OSS Distributions 	IOStatisticsTimeout();
146855239e5SApple OSS Distributions 
147a5e72196SApple OSS Distributions 	if (me->enabled && me->action) {
14814e3d835SApple OSS Distributions 		IOWorkLoop *
14914e3d835SApple OSS Distributions 		    wl = me->workLoop;
150a5e72196SApple OSS Distributions 		if (wl) {
151bb611c8fSApple OSS Distributions 			IOEventSource::Action doit;
15214e3d835SApple OSS Distributions 			wl->closeGate();
153855239e5SApple OSS Distributions 			IOStatisticsCloseGate();
154bb611c8fSApple OSS Distributions 			doit = me->action;
155a5e72196SApple OSS Distributions 			if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime)) {
156cc9a6355SApple OSS Distributions 				me->invokeAction(doit, me, me->owner, me->workLoop);
15714e3d835SApple OSS Distributions 			}
158855239e5SApple OSS Distributions 			IOStatisticsOpenGate();
15914e3d835SApple OSS Distributions 			wl->openGate();
160c1dac77fSApple OSS Distributions 		}
161c1dac77fSApple OSS Distributions 	}
162c1dac77fSApple OSS Distributions }
163c1dac77fSApple OSS Distributions 
164a5e72196SApple OSS Distributions void
timeoutAndRelease(void * self,void * c)165a5e72196SApple OSS Distributions IOTimerEventSource::timeoutAndRelease(void * self, void * c)
16614e3d835SApple OSS Distributions {
16714e3d835SApple OSS Distributions 	IOTimerEventSource *me = (IOTimerEventSource *) self;
1683ca3bd55SApple OSS Distributions 	/* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
169a5e72196SApple OSS Distributions 	 *  must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
1703ca3bd55SApple OSS Distributions 	SInt32 count = (SInt32) (long) c;
17114e3d835SApple OSS Distributions 
172855239e5SApple OSS Distributions 	IOStatisticsTimeout();
173855239e5SApple OSS Distributions 
174a5e72196SApple OSS Distributions 	if (me->enabled && me->action) {
17514e3d835SApple OSS Distributions 		IOWorkLoop *
17614e3d835SApple OSS Distributions 		    wl = me->reserved->workLoop;
177a5e72196SApple OSS Distributions 		if (wl) {
178bb611c8fSApple OSS Distributions 			IOEventSource::Action doit;
17914e3d835SApple OSS Distributions 			wl->closeGate();
180855239e5SApple OSS Distributions 			IOStatisticsCloseGate();
181bb611c8fSApple OSS Distributions 			doit = me->action;
182a5e72196SApple OSS Distributions 			if (doit && (me->reserved->calloutGeneration == count)) {
183bb611c8fSApple OSS Distributions 				thread_call_start_iotes_invocation((thread_call_t)me->calloutEntry);
184cc9a6355SApple OSS Distributions 				me->invokeAction(doit, me, me->owner, me->workLoop);
18514e3d835SApple OSS Distributions 			}
186855239e5SApple OSS Distributions 			IOStatisticsOpenGate();
18714e3d835SApple OSS Distributions 			wl->openGate();
18814e3d835SApple OSS Distributions 		}
18914e3d835SApple OSS Distributions 	}
190*e7776783SApple OSS Distributions 	if (me->reserved->workLoop) {
19114e3d835SApple OSS Distributions 		me->reserved->workLoop->release();
192*e7776783SApple OSS Distributions 	}
19314e3d835SApple OSS Distributions 	me->release();
19414e3d835SApple OSS Distributions }
19514e3d835SApple OSS Distributions 
19676e12aa3SApple OSS Distributions // -- work loop delivery
19776e12aa3SApple OSS Distributions 
198a5e72196SApple OSS Distributions bool
checkForWork()199a5e72196SApple OSS Distributions IOTimerEventSource::checkForWork()
20076e12aa3SApple OSS Distributions {
201bb611c8fSApple OSS Distributions 	IOEventSource::Action doit;
20276e12aa3SApple OSS Distributions 
20376e12aa3SApple OSS Distributions 	if (reserved
20476e12aa3SApple OSS Distributions 	    && (reserved->calloutGenerationSignaled == reserved->calloutGeneration)
205bb611c8fSApple OSS Distributions 	    && enabled && (doit = action)) {
20676e12aa3SApple OSS Distributions 		reserved->calloutGenerationSignaled = ~reserved->calloutGeneration;
207cc9a6355SApple OSS Distributions 		invokeAction(doit, this, owner, workLoop);
20876e12aa3SApple OSS Distributions 	}
20976e12aa3SApple OSS Distributions 
21076e12aa3SApple OSS Distributions 	return false;
21176e12aa3SApple OSS Distributions }
21276e12aa3SApple OSS Distributions 
213a5e72196SApple OSS Distributions void
timeoutSignaled(void * self,void * c)214a5e72196SApple OSS Distributions IOTimerEventSource::timeoutSignaled(void * self, void * c)
21576e12aa3SApple OSS Distributions {
21676e12aa3SApple OSS Distributions 	IOTimerEventSource *me = (IOTimerEventSource *) self;
21776e12aa3SApple OSS Distributions 
21876e12aa3SApple OSS Distributions 	me->reserved->calloutGenerationSignaled = (SInt32)(long) c;
219a5e72196SApple OSS Distributions 	if (me->enabled) {
220a5e72196SApple OSS Distributions 		me->signalWorkAvailable();
221a5e72196SApple OSS Distributions 	}
22276e12aa3SApple OSS Distributions }
22376e12aa3SApple OSS Distributions 
22476e12aa3SApple OSS Distributions // --
22576e12aa3SApple OSS Distributions 
226a5e72196SApple OSS Distributions void
setTimeoutFunc()227a5e72196SApple OSS Distributions IOTimerEventSource::setTimeoutFunc()
228c1dac77fSApple OSS Distributions {
22976e12aa3SApple OSS Distributions 	thread_call_priority_t pri;
23076e12aa3SApple OSS Distributions 	uint32_t options;
23176e12aa3SApple OSS Distributions 
232a5e72196SApple OSS Distributions 	if (reserved) {
233a5e72196SApple OSS Distributions 		panic("setTimeoutFunc already %p, %p", this, reserved);
234a5e72196SApple OSS Distributions 	}
23576e12aa3SApple OSS Distributions 
23614e3d835SApple OSS Distributions 	// reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
23714e3d835SApple OSS Distributions 	// not a subclassed implementation
238e6231be0SApple OSS Distributions 	reserved = IOMallocType(ExpansionData);
239bb611c8fSApple OSS Distributions 
24076e12aa3SApple OSS Distributions 	reserved->calloutGenerationSignaled = ~reserved->calloutGeneration;
241bb611c8fSApple OSS Distributions 	// make use of an existing ivar for parameter passing
242bb611c8fSApple OSS Distributions 	options = (uint32_t) abstime;
24376e12aa3SApple OSS Distributions 	abstime = 0;
24476e12aa3SApple OSS Distributions 
24576e12aa3SApple OSS Distributions 	thread_call_options_t tcoptions = 0;
24676e12aa3SApple OSS Distributions 	thread_call_func_t    func      = NULL;
24776e12aa3SApple OSS Distributions 
248a5e72196SApple OSS Distributions 	switch (kIOTimerEventSourceOptionsPriorityMask & options) {
24976e12aa3SApple OSS Distributions 	case kIOTimerEventSourceOptionsPriorityHigh:
25076e12aa3SApple OSS Distributions 		pri = THREAD_CALL_PRIORITY_HIGH;
25176e12aa3SApple OSS Distributions 		func = &IOTimerEventSource::timeoutAndRelease;
25276e12aa3SApple OSS Distributions 		break;
25376e12aa3SApple OSS Distributions 
25476e12aa3SApple OSS Distributions 	case kIOTimerEventSourceOptionsPriorityKernel:
25576e12aa3SApple OSS Distributions 		pri = THREAD_CALL_PRIORITY_KERNEL;
25676e12aa3SApple OSS Distributions 		func = &IOTimerEventSource::timeoutAndRelease;
25776e12aa3SApple OSS Distributions 		break;
25876e12aa3SApple OSS Distributions 
25976e12aa3SApple OSS Distributions 	case kIOTimerEventSourceOptionsPriorityKernelHigh:
26076e12aa3SApple OSS Distributions 		pri = THREAD_CALL_PRIORITY_KERNEL_HIGH;
26176e12aa3SApple OSS Distributions 		func = &IOTimerEventSource::timeoutAndRelease;
26276e12aa3SApple OSS Distributions 		break;
26376e12aa3SApple OSS Distributions 
26476e12aa3SApple OSS Distributions 	case kIOTimerEventSourceOptionsPriorityUser:
26576e12aa3SApple OSS Distributions 		pri = THREAD_CALL_PRIORITY_USER;
26676e12aa3SApple OSS Distributions 		func = &IOTimerEventSource::timeoutAndRelease;
26776e12aa3SApple OSS Distributions 		break;
26876e12aa3SApple OSS Distributions 
26976e12aa3SApple OSS Distributions 	case kIOTimerEventSourceOptionsPriorityLow:
27076e12aa3SApple OSS Distributions 		pri = THREAD_CALL_PRIORITY_LOW;
27176e12aa3SApple OSS Distributions 		func = &IOTimerEventSource::timeoutAndRelease;
27276e12aa3SApple OSS Distributions 		break;
27376e12aa3SApple OSS Distributions 
27476e12aa3SApple OSS Distributions 	case kIOTimerEventSourceOptionsPriorityWorkLoop:
27576e12aa3SApple OSS Distributions 		pri = THREAD_CALL_PRIORITY_KERNEL;
27676e12aa3SApple OSS Distributions 		tcoptions |= THREAD_CALL_OPTIONS_SIGNAL;
277a5e72196SApple OSS Distributions 		if (kIOTimerEventSourceOptionsAllowReenter & options) {
278a5e72196SApple OSS Distributions 			break;
279a5e72196SApple OSS Distributions 		}
28076e12aa3SApple OSS Distributions 		func = &IOTimerEventSource::timeoutSignaled;
28176e12aa3SApple OSS Distributions 		break;
28276e12aa3SApple OSS Distributions 
28376e12aa3SApple OSS Distributions 	default:
28476e12aa3SApple OSS Distributions 		break;
28576e12aa3SApple OSS Distributions 	}
28676e12aa3SApple OSS Distributions 
28776e12aa3SApple OSS Distributions 	assertf(func, "IOTimerEventSource options 0x%x", options);
288a5e72196SApple OSS Distributions 	if (!func) {
289a5e72196SApple OSS Distributions 		return;                                              // init will fail
290a5e72196SApple OSS Distributions 	}
291a5e72196SApple OSS Distributions 	if (THREAD_CALL_OPTIONS_SIGNAL & tcoptions) {
292a5e72196SApple OSS Distributions 		flags |= kActive;
293a5e72196SApple OSS Distributions 	} else {
294a5e72196SApple OSS Distributions 		flags |= kPassive;
295a5e72196SApple OSS Distributions 	}
29676e12aa3SApple OSS Distributions 
297a5e72196SApple OSS Distributions 	if (!(kIOTimerEventSourceOptionsAllowReenter & options)) {
298a5e72196SApple OSS Distributions 		tcoptions |= THREAD_CALL_OPTIONS_ONCE;
299a5e72196SApple OSS Distributions 	}
30076e12aa3SApple OSS Distributions 
30176e12aa3SApple OSS Distributions 	calloutEntry = (void *) thread_call_allocate_with_options(func,
30276e12aa3SApple OSS Distributions 	    (thread_call_param_t) this, pri, tcoptions);
30376e12aa3SApple OSS Distributions 	assert(calloutEntry);
304c1dac77fSApple OSS Distributions }
305c1dac77fSApple OSS Distributions 
306a5e72196SApple OSS Distributions bool
init(OSObject * inOwner,Action inAction)307a5e72196SApple OSS Distributions IOTimerEventSource::init(OSObject *inOwner, Action inAction)
308c1dac77fSApple OSS Distributions {
309a5e72196SApple OSS Distributions 	if (!super::init(inOwner, (IOEventSource::Action) inAction)) {
310c1dac77fSApple OSS Distributions 		return false;
311a5e72196SApple OSS Distributions 	}
312c1dac77fSApple OSS Distributions 
313c1dac77fSApple OSS Distributions 	setTimeoutFunc();
314a5e72196SApple OSS Distributions 	if (!calloutEntry) {
315c1dac77fSApple OSS Distributions 		return false;
316a5e72196SApple OSS Distributions 	}
317c1dac77fSApple OSS Distributions 
318855239e5SApple OSS Distributions 	IOStatisticsInitializeCounter();
319855239e5SApple OSS Distributions 
320c1dac77fSApple OSS Distributions 	return true;
321c1dac77fSApple OSS Distributions }
322c1dac77fSApple OSS Distributions 
323a5e72196SApple OSS Distributions bool
init(uint32_t options,OSObject * inOwner,Action inAction)324a5e72196SApple OSS Distributions IOTimerEventSource::init(uint32_t options, OSObject *inOwner, Action inAction)
32576e12aa3SApple OSS Distributions {
326bb611c8fSApple OSS Distributions 	// make use of an existing ivar for parameter passing
32776e12aa3SApple OSS Distributions 	abstime = options;
328a5e72196SApple OSS Distributions 	return init(inOwner, inAction);
32976e12aa3SApple OSS Distributions }
33076e12aa3SApple OSS Distributions 
331c1dac77fSApple OSS Distributions IOTimerEventSource *
timerEventSource(uint32_t inOptions,OSObject * inOwner,Action inAction)33276e12aa3SApple OSS Distributions IOTimerEventSource::timerEventSource(uint32_t inOptions, OSObject *inOwner, Action inAction)
333c1dac77fSApple OSS Distributions {
334c1dac77fSApple OSS Distributions 	IOTimerEventSource *me = new IOTimerEventSource;
335c1dac77fSApple OSS Distributions 
33676e12aa3SApple OSS Distributions 	if (me && !me->init(inOptions, inOwner, inAction)) {
337368ad365SApple OSS Distributions 		me->release();
338a5e72196SApple OSS Distributions 		return NULL;
339c1dac77fSApple OSS Distributions 	}
340c1dac77fSApple OSS Distributions 
341c1dac77fSApple OSS Distributions 	return me;
342c1dac77fSApple OSS Distributions }
343c1dac77fSApple OSS Distributions 
344cc9a6355SApple OSS Distributions IOTimerEventSource *
timerEventSource(uint32_t options,OSObject * inOwner,ActionBlock _action)345a5e72196SApple OSS Distributions IOTimerEventSource::timerEventSource(uint32_t options, OSObject *inOwner, ActionBlock _action)
346cc9a6355SApple OSS Distributions {
347cc9a6355SApple OSS Distributions 	IOTimerEventSource * tes;
348cc9a6355SApple OSS Distributions 	tes = IOTimerEventSource::timerEventSource(options, inOwner, (Action) NULL);
349a5e72196SApple OSS Distributions 	if (tes) {
350a5e72196SApple OSS Distributions 		tes->setActionBlock((IOEventSource::ActionBlock) _action);
351a5e72196SApple OSS Distributions 	}
352cc9a6355SApple OSS Distributions 
353cc9a6355SApple OSS Distributions 	return tes;
354cc9a6355SApple OSS Distributions }
355cc9a6355SApple OSS Distributions 
35676e12aa3SApple OSS Distributions #define _thread_call_cancel(tc)   ((kActive & flags) ? thread_call_cancel_wait((tc)) : thread_call_cancel((tc)))
35776e12aa3SApple OSS Distributions 
35876e12aa3SApple OSS Distributions IOTimerEventSource *
timerEventSource(OSObject * inOwner,Action inAction)35976e12aa3SApple OSS Distributions IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction)
36076e12aa3SApple OSS Distributions {
361a5e72196SApple OSS Distributions 	return IOTimerEventSource::timerEventSource(
36276e12aa3SApple OSS Distributions 		kIOTimerEventSourceOptionsPriorityKernelHigh,
363a5e72196SApple OSS Distributions 		inOwner, inAction);
36476e12aa3SApple OSS Distributions }
36576e12aa3SApple OSS Distributions 
366a5e72196SApple OSS Distributions void
free()367a5e72196SApple OSS Distributions IOTimerEventSource::free()
368c1dac77fSApple OSS Distributions {
369c1dac77fSApple OSS Distributions 	if (calloutEntry) {
37076e12aa3SApple OSS Distributions 		__assert_only bool freed;
37176e12aa3SApple OSS Distributions 
372c1dac77fSApple OSS Distributions 		cancelTimeout();
37376e12aa3SApple OSS Distributions 
37476e12aa3SApple OSS Distributions 		freed = thread_call_free((thread_call_t) calloutEntry);
37576e12aa3SApple OSS Distributions 		assert(freed);
376c1dac77fSApple OSS Distributions 	}
377c1dac77fSApple OSS Distributions 
378a5e72196SApple OSS Distributions 	if (reserved) {
379e6231be0SApple OSS Distributions 		IOFreeType(reserved, ExpansionData);
380a5e72196SApple OSS Distributions 	}
38114e3d835SApple OSS Distributions 
382c1dac77fSApple OSS Distributions 	super::free();
383c1dac77fSApple OSS Distributions }
384c1dac77fSApple OSS Distributions 
385a5e72196SApple OSS Distributions void
cancelTimeout()386a5e72196SApple OSS Distributions IOTimerEventSource::cancelTimeout()
387c1dac77fSApple OSS Distributions {
388a5e72196SApple OSS Distributions 	if (reserved) {
38914e3d835SApple OSS Distributions 		reserved->calloutGeneration++;
390a5e72196SApple OSS Distributions 	}
39176e12aa3SApple OSS Distributions 	bool active = _thread_call_cancel((thread_call_t) calloutEntry);
392c1dac77fSApple OSS Distributions 	AbsoluteTime_to_scalar(&abstime) = 0;
393a5e72196SApple OSS Distributions 	if (active && reserved && (kPassive & flags)) {
39414e3d835SApple OSS Distributions 		release();
39514e3d835SApple OSS Distributions 		workLoop->release();
39614e3d835SApple OSS Distributions 	}
397c1dac77fSApple OSS Distributions }
398c1dac77fSApple OSS Distributions 
399a5e72196SApple OSS Distributions void
enable()400a5e72196SApple OSS Distributions IOTimerEventSource::enable()
401c1dac77fSApple OSS Distributions {
402c1dac77fSApple OSS Distributions 	super::enable();
403a5e72196SApple OSS Distributions 	if (kIOReturnSuccess != wakeAtTime(abstime)) {
404c1dac77fSApple OSS Distributions 		super::disable(); // Problem re-scheduling timeout ignore enable
405c1dac77fSApple OSS Distributions 	}
406a5e72196SApple OSS Distributions }
407c1dac77fSApple OSS Distributions 
408a5e72196SApple OSS Distributions void
disable()409a5e72196SApple OSS Distributions IOTimerEventSource::disable()
410c1dac77fSApple OSS Distributions {
411a5e72196SApple OSS Distributions 	if (reserved) {
41214e3d835SApple OSS Distributions 		reserved->calloutGeneration++;
413a5e72196SApple OSS Distributions 	}
41476e12aa3SApple OSS Distributions 	bool active = _thread_call_cancel((thread_call_t) calloutEntry);
415c1dac77fSApple OSS Distributions 	super::disable();
416a5e72196SApple OSS Distributions 	if (active && reserved && (kPassive & flags)) {
41714e3d835SApple OSS Distributions 		release();
41814e3d835SApple OSS Distributions 		workLoop->release();
41914e3d835SApple OSS Distributions 	}
420c1dac77fSApple OSS Distributions }
421c1dac77fSApple OSS Distributions 
422a5e72196SApple OSS Distributions IOReturn
setTimeoutTicks(UInt32 ticks)423a5e72196SApple OSS Distributions IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
424c1dac77fSApple OSS Distributions {
42514e3d835SApple OSS Distributions 	return setTimeout(ticks, kTickScale);
426c1dac77fSApple OSS Distributions }
427c1dac77fSApple OSS Distributions 
428a5e72196SApple OSS Distributions IOReturn
setTimeoutMS(UInt32 ms)429a5e72196SApple OSS Distributions IOTimerEventSource::setTimeoutMS(UInt32 ms)
430c1dac77fSApple OSS Distributions {
431c1dac77fSApple OSS Distributions 	return setTimeout(ms, kMillisecondScale);
432c1dac77fSApple OSS Distributions }
433c1dac77fSApple OSS Distributions 
434a5e72196SApple OSS Distributions IOReturn
setTimeoutUS(UInt32 us)435a5e72196SApple OSS Distributions IOTimerEventSource::setTimeoutUS(UInt32 us)
436c1dac77fSApple OSS Distributions {
437c1dac77fSApple OSS Distributions 	return setTimeout(us, kMicrosecondScale);
438c1dac77fSApple OSS Distributions }
439c1dac77fSApple OSS Distributions 
440a5e72196SApple OSS Distributions IOReturn
setTimeout(UInt32 interval,UInt32 scale_factor)441a5e72196SApple OSS Distributions IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
442c1dac77fSApple OSS Distributions {
443c1dac77fSApple OSS Distributions 	AbsoluteTime end;
444c1dac77fSApple OSS Distributions 
445c1dac77fSApple OSS Distributions 	clock_interval_to_deadline(interval, scale_factor, &end);
446c1dac77fSApple OSS Distributions 	return wakeAtTime(end);
447c1dac77fSApple OSS Distributions }
448c1dac77fSApple OSS Distributions 
4493ca3bd55SApple OSS Distributions #if !defined(__LP64__)
450a5e72196SApple OSS Distributions IOReturn
setTimeout(mach_timespec_t interval)451a5e72196SApple OSS Distributions IOTimerEventSource::setTimeout(mach_timespec_t interval)
452c1dac77fSApple OSS Distributions {
453c1dac77fSApple OSS Distributions 	AbsoluteTime end, nsecs;
454c1dac77fSApple OSS Distributions 
455c1dac77fSApple OSS Distributions 	clock_interval_to_absolutetime_interval
456c1dac77fSApple OSS Distributions 	(interval.tv_nsec, kNanosecondScale, &nsecs);
457c1dac77fSApple OSS Distributions 	clock_interval_to_deadline
458c1dac77fSApple OSS Distributions 	(interval.tv_sec, NSEC_PER_SEC, &end);
459c1dac77fSApple OSS Distributions 	ADD_ABSOLUTETIME(&end, &nsecs);
460c1dac77fSApple OSS Distributions 
461c1dac77fSApple OSS Distributions 	return wakeAtTime(end);
462c1dac77fSApple OSS Distributions }
4633ca3bd55SApple OSS Distributions #endif
464c1dac77fSApple OSS Distributions 
465a5e72196SApple OSS Distributions IOReturn
setTimeout(AbsoluteTime interval)466a5e72196SApple OSS Distributions IOTimerEventSource::setTimeout(AbsoluteTime interval)
467c1dac77fSApple OSS Distributions {
468c1dac77fSApple OSS Distributions 	AbsoluteTime end;
46976e12aa3SApple OSS Distributions 	clock_absolutetime_interval_to_deadline(interval, &end);
470c1dac77fSApple OSS Distributions 	return wakeAtTime(end);
471c1dac77fSApple OSS Distributions }
472c1dac77fSApple OSS Distributions 
473a5e72196SApple OSS Distributions IOReturn
setTimeout(uint32_t options,AbsoluteTime abstime,AbsoluteTime leeway)474a5e72196SApple OSS Distributions IOTimerEventSource::setTimeout(uint32_t options,
47576e12aa3SApple OSS Distributions     AbsoluteTime abstime, AbsoluteTime leeway)
47676e12aa3SApple OSS Distributions {
47776e12aa3SApple OSS Distributions 	AbsoluteTime end;
478a5e72196SApple OSS Distributions 	if (options & kIOTimeOptionsContinuous) {
47976e12aa3SApple OSS Distributions 		clock_continuoustime_interval_to_deadline(abstime, &end);
480a5e72196SApple OSS Distributions 	} else {
481cc9a6355SApple OSS Distributions 		clock_absolutetime_interval_to_deadline(abstime, &end);
482a5e72196SApple OSS Distributions 	}
48376e12aa3SApple OSS Distributions 
484cc9a6355SApple OSS Distributions 	return wakeAtTime(options, end, leeway);
48576e12aa3SApple OSS Distributions }
48676e12aa3SApple OSS Distributions 
487a5e72196SApple OSS Distributions IOReturn
wakeAtTimeTicks(UInt32 ticks)488a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
489c1dac77fSApple OSS Distributions {
49014e3d835SApple OSS Distributions 	return wakeAtTime(ticks, kTickScale);
491c1dac77fSApple OSS Distributions }
492c1dac77fSApple OSS Distributions 
493a5e72196SApple OSS Distributions IOReturn
wakeAtTimeMS(UInt32 ms)494a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
495c1dac77fSApple OSS Distributions {
496c1dac77fSApple OSS Distributions 	return wakeAtTime(ms, kMillisecondScale);
497c1dac77fSApple OSS Distributions }
498c1dac77fSApple OSS Distributions 
499a5e72196SApple OSS Distributions IOReturn
wakeAtTimeUS(UInt32 us)500a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTimeUS(UInt32 us)
501c1dac77fSApple OSS Distributions {
502c1dac77fSApple OSS Distributions 	return wakeAtTime(us, kMicrosecondScale);
503c1dac77fSApple OSS Distributions }
504c1dac77fSApple OSS Distributions 
505a5e72196SApple OSS Distributions IOReturn
wakeAtTime(UInt32 inAbstime,UInt32 scale_factor)506a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
507c1dac77fSApple OSS Distributions {
508c1dac77fSApple OSS Distributions 	AbsoluteTime end;
50914e3d835SApple OSS Distributions 	clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
510c1dac77fSApple OSS Distributions 
511c1dac77fSApple OSS Distributions 	return wakeAtTime(end);
512c1dac77fSApple OSS Distributions }
513c1dac77fSApple OSS Distributions 
5143ca3bd55SApple OSS Distributions #if !defined(__LP64__)
515a5e72196SApple OSS Distributions IOReturn
wakeAtTime(mach_timespec_t inAbstime)516a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
517c1dac77fSApple OSS Distributions {
518c1dac77fSApple OSS Distributions 	AbsoluteTime end, nsecs;
519c1dac77fSApple OSS Distributions 
520c1dac77fSApple OSS Distributions 	clock_interval_to_absolutetime_interval
52114e3d835SApple OSS Distributions 	(inAbstime.tv_nsec, kNanosecondScale, &nsecs);
522c1dac77fSApple OSS Distributions 	clock_interval_to_absolutetime_interval
52314e3d835SApple OSS Distributions 	(inAbstime.tv_sec, kSecondScale, &end);
524c1dac77fSApple OSS Distributions 	ADD_ABSOLUTETIME(&end, &nsecs);
525c1dac77fSApple OSS Distributions 
526c1dac77fSApple OSS Distributions 	return wakeAtTime(end);
527c1dac77fSApple OSS Distributions }
5283ca3bd55SApple OSS Distributions #endif
529c1dac77fSApple OSS Distributions 
530a5e72196SApple OSS Distributions void
setWorkLoop(IOWorkLoop * inWorkLoop)531a5e72196SApple OSS Distributions IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
53214e3d835SApple OSS Distributions {
53314e3d835SApple OSS Distributions 	super::setWorkLoop(inWorkLoop);
534a5e72196SApple OSS Distributions 	if (enabled && AbsoluteTime_to_scalar(&abstime) && workLoop) {
53514e3d835SApple OSS Distributions 		wakeAtTime(abstime);
53614e3d835SApple OSS Distributions 	}
537a5e72196SApple OSS Distributions }
53814e3d835SApple OSS Distributions 
539a5e72196SApple OSS Distributions IOReturn
wakeAtTime(AbsoluteTime inAbstime)540a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
541c1dac77fSApple OSS Distributions {
54276e12aa3SApple OSS Distributions 	return wakeAtTime(0, inAbstime, 0);
54376e12aa3SApple OSS Distributions }
54476e12aa3SApple OSS Distributions 
545a5e72196SApple OSS Distributions IOReturn
wakeAtTime(uint32_t options,AbsoluteTime inAbstime,AbsoluteTime leeway)546a5e72196SApple OSS Distributions IOTimerEventSource::wakeAtTime(uint32_t options, AbsoluteTime inAbstime, AbsoluteTime leeway)
54776e12aa3SApple OSS Distributions {
548a5e72196SApple OSS Distributions 	if (!action) {
549c1dac77fSApple OSS Distributions 		return kIOReturnNoResources;
550a5e72196SApple OSS Distributions 	}
551c1dac77fSApple OSS Distributions 
552c1dac77fSApple OSS Distributions 	abstime = inAbstime;
553a5e72196SApple OSS Distributions 	if (enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop) {
55476e12aa3SApple OSS Distributions 		uint32_t tcoptions = 0;
55576e12aa3SApple OSS Distributions 
556a5e72196SApple OSS Distributions 		if (kIOTimeOptionsWithLeeway & options) {
557a5e72196SApple OSS Distributions 			tcoptions |= THREAD_CALL_DELAY_LEEWAY;
558a5e72196SApple OSS Distributions 		}
559a5e72196SApple OSS Distributions 		if (kIOTimeOptionsContinuous & options) {
560a5e72196SApple OSS Distributions 			tcoptions |= THREAD_CALL_CONTINUOUS;
561a5e72196SApple OSS Distributions 		}
56276e12aa3SApple OSS Distributions 
563a5e72196SApple OSS Distributions 		if (reserved) {
564a5e72196SApple OSS Distributions 			if (kPassive & flags) {
56514e3d835SApple OSS Distributions 				retain();
56614e3d835SApple OSS Distributions 				workLoop->retain();
56776e12aa3SApple OSS Distributions 			}
56814e3d835SApple OSS Distributions 			reserved->workLoop = workLoop;
56914e3d835SApple OSS Distributions 			reserved->calloutGeneration++;
57076e12aa3SApple OSS Distributions 			if (thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry,
57176e12aa3SApple OSS Distributions 			    (void *)(uintptr_t) reserved->calloutGeneration, inAbstime, leeway, tcoptions)
572a5e72196SApple OSS Distributions 			    && (kPassive & flags)) {
57314e3d835SApple OSS Distributions 				release();
57414e3d835SApple OSS Distributions 				workLoop->release();
57514e3d835SApple OSS Distributions 			}
576a5e72196SApple OSS Distributions 		} else {
57776e12aa3SApple OSS Distributions 			thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry,
57876e12aa3SApple OSS Distributions 			    NULL, inAbstime, leeway, tcoptions);
57976e12aa3SApple OSS Distributions 		}
58014e3d835SApple OSS Distributions 	}
581c1dac77fSApple OSS Distributions 
582c1dac77fSApple OSS Distributions 	return kIOReturnSuccess;
583c1dac77fSApple OSS Distributions }
584