1 /*
2  * Copyright (c) 1998-2000, 2009-2010 Apple 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 #include <sys/cdefs.h>
30 
31 __BEGIN_DECLS
32 #include <kern/thread_call.h>
33 __END_DECLS
34 
35 #include <IOKit/assert.h>
36 #include <IOKit/system.h>
37 
38 #include <IOKit/IOLib.h>
39 #include <IOKit/IOTimerEventSource.h>
40 #include <IOKit/IOWorkLoop.h>
41 
42 #include <IOKit/IOTimeStamp.h>
43 #include <IOKit/IOKitDebug.h>
44 #if CONFIG_DTRACE
45 #include <mach/sdt.h>
46 #endif
47 
48 #include <libkern/Block.h>
49 
50 
51 #define super IOEventSource
52 OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource)
53 OSMetaClassDefineReservedUsed(IOTimerEventSource, 0);
54 OSMetaClassDefineReservedUsed(IOTimerEventSource, 1);
55 OSMetaClassDefineReservedUsed(IOTimerEventSource, 2);
56 OSMetaClassDefineReservedUnused(IOTimerEventSource, 3);
57 OSMetaClassDefineReservedUnused(IOTimerEventSource, 4);
58 OSMetaClassDefineReservedUnused(IOTimerEventSource, 5);
59 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6);
60 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7);
61 
62 #if IOKITSTATS
63 
64 #define IOStatisticsInitializeCounter() \
65 do { \
66 	IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsTimerEventSourceCounter); \
67 } while (0)
68 
69 #define IOStatisticsOpenGate() \
70 do { \
71 	IOStatistics::countOpenGate(me->IOEventSource::reserved->counter); \
72 } while (0)
73 
74 #define IOStatisticsCloseGate() \
75 do { \
76 	IOStatistics::countCloseGate(me->IOEventSource::reserved->counter); \
77 } while (0)
78 
79 #define IOStatisticsTimeout() \
80 do { \
81 	IOStatistics::countTimerTimeout(me->IOEventSource::reserved->counter); \
82 } while (0)
83 
84 #else
85 
86 #define IOStatisticsInitializeCounter()
87 #define IOStatisticsOpenGate()
88 #define IOStatisticsCloseGate()
89 #define IOStatisticsTimeout()
90 
91 #endif /* IOKITSTATS */
92 
93 //
94 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
95 // not a subclassed implementation.
96 //
97 
98 // Timeout handler function. This function is called by the kernel when
99 // the timeout interval expires.
100 //
101 
102 __inline__ void
103 IOTimerEventSource::invokeAction(IOTimerEventSource::Action _action, IOTimerEventSource * ts,
104     OSObject * _owner, IOWorkLoop * _workLoop)
105 {
106 	bool    trace = (gIOKitTrace & kIOTraceTimers) ? true : false;
107 
108 	if (trace) {
109 		IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION),
110 		    VM_KERNEL_ADDRHIDE(_action), VM_KERNEL_ADDRHIDE(_owner));
111 	}
112 
113 	if (kActionBlock & flags) {
114 		((IOTimerEventSource::ActionBlock) actionBlock)(ts);
115 	} else {
116 		(*_action)(_owner, ts);
117 	}
118 
119 #if CONFIG_DTRACE
120 	DTRACE_TMR3(iotescallout__expire, Action, _action, OSObject, _owner, void, _workLoop);
121 #endif
122 
123 	if (trace) {
124 		IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
125 		    VM_KERNEL_UNSLIDE(_action), VM_KERNEL_ADDRHIDE(_owner));
126 	}
127 }
128 
129 void
130 IOTimerEventSource::timeout(void *self)
131 {
132 	IOTimerEventSource *me = (IOTimerEventSource *) self;
133 
134 	IOStatisticsTimeout();
135 
136 	if (me->enabled && me->action) {
137 		IOWorkLoop *
138 		    wl = me->workLoop;
139 		if (wl) {
140 			Action doit;
141 			wl->closeGate();
142 			IOStatisticsCloseGate();
143 			doit = (Action) me->action;
144 			if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime)) {
145 				me->invokeAction(doit, me, me->owner, me->workLoop);
146 			}
147 			IOStatisticsOpenGate();
148 			wl->openGate();
149 		}
150 	}
151 }
152 
153 void
154 IOTimerEventSource::timeoutAndRelease(void * self, void * c)
155 {
156 	IOTimerEventSource *me = (IOTimerEventSource *) self;
157 	/* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
158 	 *  must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
159 	SInt32 count = (SInt32) (long) c;
160 
161 	IOStatisticsTimeout();
162 
163 	if (me->enabled && me->action) {
164 		IOWorkLoop *
165 		    wl = me->reserved->workLoop;
166 		if (wl) {
167 			Action doit;
168 			wl->closeGate();
169 			IOStatisticsCloseGate();
170 			doit = (Action) me->action;
171 			if (doit && (me->reserved->calloutGeneration == count)) {
172 				me->invokeAction(doit, me, me->owner, me->workLoop);
173 			}
174 			IOStatisticsOpenGate();
175 			wl->openGate();
176 		}
177 	}
178 
179 	me->reserved->workLoop->release();
180 	me->release();
181 }
182 
183 // -- work loop delivery
184 
185 bool
186 IOTimerEventSource::checkForWork()
187 {
188 	Action doit;
189 
190 	if (reserved
191 	    && (reserved->calloutGenerationSignaled == reserved->calloutGeneration)
192 	    && enabled && (doit = (Action) action)) {
193 		reserved->calloutGenerationSignaled = ~reserved->calloutGeneration;
194 		invokeAction(doit, this, owner, workLoop);
195 	}
196 
197 	return false;
198 }
199 
200 void
201 IOTimerEventSource::timeoutSignaled(void * self, void * c)
202 {
203 	IOTimerEventSource *me = (IOTimerEventSource *) self;
204 
205 	me->reserved->calloutGenerationSignaled = (SInt32)(long) c;
206 	if (me->enabled) {
207 		me->signalWorkAvailable();
208 	}
209 }
210 
211 // --
212 
213 void
214 IOTimerEventSource::setTimeoutFunc()
215 {
216 	thread_call_priority_t pri;
217 	uint32_t options;
218 
219 	if (reserved) {
220 		panic("setTimeoutFunc already %p, %p", this, reserved);
221 	}
222 
223 	// reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
224 	// not a subclassed implementation
225 	reserved = IONew(ExpansionData, 1);
226 	reserved->calloutGenerationSignaled = ~reserved->calloutGeneration;
227 	options = abstime;
228 	abstime = 0;
229 
230 	thread_call_options_t tcoptions = 0;
231 	thread_call_func_t    func      = NULL;
232 
233 	switch (kIOTimerEventSourceOptionsPriorityMask & options) {
234 	case kIOTimerEventSourceOptionsPriorityHigh:
235 		pri = THREAD_CALL_PRIORITY_HIGH;
236 		func = &IOTimerEventSource::timeoutAndRelease;
237 		break;
238 
239 	case kIOTimerEventSourceOptionsPriorityKernel:
240 		pri = THREAD_CALL_PRIORITY_KERNEL;
241 		func = &IOTimerEventSource::timeoutAndRelease;
242 		break;
243 
244 	case kIOTimerEventSourceOptionsPriorityKernelHigh:
245 		pri = THREAD_CALL_PRIORITY_KERNEL_HIGH;
246 		func = &IOTimerEventSource::timeoutAndRelease;
247 		break;
248 
249 	case kIOTimerEventSourceOptionsPriorityUser:
250 		pri = THREAD_CALL_PRIORITY_USER;
251 		func = &IOTimerEventSource::timeoutAndRelease;
252 		break;
253 
254 	case kIOTimerEventSourceOptionsPriorityLow:
255 		pri = THREAD_CALL_PRIORITY_LOW;
256 		func = &IOTimerEventSource::timeoutAndRelease;
257 		break;
258 
259 	case kIOTimerEventSourceOptionsPriorityWorkLoop:
260 		pri = THREAD_CALL_PRIORITY_KERNEL;
261 		tcoptions |= THREAD_CALL_OPTIONS_SIGNAL;
262 		if (kIOTimerEventSourceOptionsAllowReenter & options) {
263 			break;
264 		}
265 		func = &IOTimerEventSource::timeoutSignaled;
266 		break;
267 
268 	default:
269 		break;
270 	}
271 
272 	assertf(func, "IOTimerEventSource options 0x%x", options);
273 	if (!func) {
274 		return;                                              // init will fail
275 	}
276 	if (THREAD_CALL_OPTIONS_SIGNAL & tcoptions) {
277 		flags |= kActive;
278 	} else {
279 		flags |= kPassive;
280 	}
281 
282 	if (!(kIOTimerEventSourceOptionsAllowReenter & options)) {
283 		tcoptions |= THREAD_CALL_OPTIONS_ONCE;
284 	}
285 
286 	calloutEntry = (void *) thread_call_allocate_with_options(func,
287 	    (thread_call_param_t) this, pri, tcoptions);
288 	assert(calloutEntry);
289 }
290 
291 bool
292 IOTimerEventSource::init(OSObject *inOwner, Action inAction)
293 {
294 	if (!super::init(inOwner, (IOEventSource::Action) inAction)) {
295 		return false;
296 	}
297 
298 	setTimeoutFunc();
299 	if (!calloutEntry) {
300 		return false;
301 	}
302 
303 	IOStatisticsInitializeCounter();
304 
305 	return true;
306 }
307 
308 bool
309 IOTimerEventSource::init(uint32_t options, OSObject *inOwner, Action inAction)
310 {
311 	abstime = options;
312 	return init(inOwner, inAction);
313 }
314 
315 IOTimerEventSource *
316 IOTimerEventSource::timerEventSource(uint32_t inOptions, OSObject *inOwner, Action inAction)
317 {
318 	IOTimerEventSource *me = new IOTimerEventSource;
319 
320 	if (me && !me->init(inOptions, inOwner, inAction)) {
321 		me->release();
322 		return NULL;
323 	}
324 
325 	return me;
326 }
327 
328 IOTimerEventSource *
329 IOTimerEventSource::timerEventSource(uint32_t options, OSObject *inOwner, ActionBlock _action)
330 {
331 	IOTimerEventSource * tes;
332 	tes = IOTimerEventSource::timerEventSource(options, inOwner, (Action) NULL);
333 	if (tes) {
334 		tes->setActionBlock((IOEventSource::ActionBlock) _action);
335 	}
336 
337 	return tes;
338 }
339 
340 #define _thread_call_cancel(tc)   ((kActive & flags) ? thread_call_cancel_wait((tc)) : thread_call_cancel((tc)))
341 
342 IOTimerEventSource *
343 IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction)
344 {
345 	return IOTimerEventSource::timerEventSource(
346 		kIOTimerEventSourceOptionsPriorityKernelHigh,
347 		inOwner, inAction);
348 }
349 
350 void
351 IOTimerEventSource::free()
352 {
353 	if (calloutEntry) {
354 		__assert_only bool freed;
355 
356 		cancelTimeout();
357 
358 		freed = thread_call_free((thread_call_t) calloutEntry);
359 		assert(freed);
360 	}
361 
362 	if (reserved) {
363 		IODelete(reserved, ExpansionData, 1);
364 	}
365 
366 	super::free();
367 }
368 
369 void
370 IOTimerEventSource::cancelTimeout()
371 {
372 	if (reserved) {
373 		reserved->calloutGeneration++;
374 	}
375 	bool active = _thread_call_cancel((thread_call_t) calloutEntry);
376 	AbsoluteTime_to_scalar(&abstime) = 0;
377 	if (active && reserved && (kPassive & flags)) {
378 		release();
379 		workLoop->release();
380 	}
381 }
382 
383 void
384 IOTimerEventSource::enable()
385 {
386 	super::enable();
387 	if (kIOReturnSuccess != wakeAtTime(abstime)) {
388 		super::disable(); // Problem re-scheduling timeout ignore enable
389 	}
390 }
391 
392 void
393 IOTimerEventSource::disable()
394 {
395 	if (reserved) {
396 		reserved->calloutGeneration++;
397 	}
398 	bool active = _thread_call_cancel((thread_call_t) calloutEntry);
399 	super::disable();
400 	if (active && reserved && (kPassive & flags)) {
401 		release();
402 		workLoop->release();
403 	}
404 }
405 
406 IOReturn
407 IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
408 {
409 	return setTimeout(ticks, kTickScale);
410 }
411 
412 IOReturn
413 IOTimerEventSource::setTimeoutMS(UInt32 ms)
414 {
415 	return setTimeout(ms, kMillisecondScale);
416 }
417 
418 IOReturn
419 IOTimerEventSource::setTimeoutUS(UInt32 us)
420 {
421 	return setTimeout(us, kMicrosecondScale);
422 }
423 
424 IOReturn
425 IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
426 {
427 	AbsoluteTime end;
428 
429 	clock_interval_to_deadline(interval, scale_factor, &end);
430 	return wakeAtTime(end);
431 }
432 
433 #if !defined(__LP64__)
434 IOReturn
435 IOTimerEventSource::setTimeout(mach_timespec_t interval)
436 {
437 	AbsoluteTime end, nsecs;
438 
439 	clock_interval_to_absolutetime_interval
440 	(interval.tv_nsec, kNanosecondScale, &nsecs);
441 	clock_interval_to_deadline
442 	(interval.tv_sec, NSEC_PER_SEC, &end);
443 	ADD_ABSOLUTETIME(&end, &nsecs);
444 
445 	return wakeAtTime(end);
446 }
447 #endif
448 
449 IOReturn
450 IOTimerEventSource::setTimeout(AbsoluteTime interval)
451 {
452 	AbsoluteTime end;
453 	clock_absolutetime_interval_to_deadline(interval, &end);
454 	return wakeAtTime(end);
455 }
456 
457 IOReturn
458 IOTimerEventSource::setTimeout(uint32_t options,
459     AbsoluteTime abstime, AbsoluteTime leeway)
460 {
461 	AbsoluteTime end;
462 	if (options & kIOTimeOptionsContinuous) {
463 		clock_continuoustime_interval_to_deadline(abstime, &end);
464 	} else {
465 		clock_absolutetime_interval_to_deadline(abstime, &end);
466 	}
467 
468 	return wakeAtTime(options, end, leeway);
469 }
470 
471 IOReturn
472 IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
473 {
474 	return wakeAtTime(ticks, kTickScale);
475 }
476 
477 IOReturn
478 IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
479 {
480 	return wakeAtTime(ms, kMillisecondScale);
481 }
482 
483 IOReturn
484 IOTimerEventSource::wakeAtTimeUS(UInt32 us)
485 {
486 	return wakeAtTime(us, kMicrosecondScale);
487 }
488 
489 IOReturn
490 IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
491 {
492 	AbsoluteTime end;
493 	clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
494 
495 	return wakeAtTime(end);
496 }
497 
498 #if !defined(__LP64__)
499 IOReturn
500 IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
501 {
502 	AbsoluteTime end, nsecs;
503 
504 	clock_interval_to_absolutetime_interval
505 	(inAbstime.tv_nsec, kNanosecondScale, &nsecs);
506 	clock_interval_to_absolutetime_interval
507 	(inAbstime.tv_sec, kSecondScale, &end);
508 	ADD_ABSOLUTETIME(&end, &nsecs);
509 
510 	return wakeAtTime(end);
511 }
512 #endif
513 
514 void
515 IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
516 {
517 	super::setWorkLoop(inWorkLoop);
518 	if (enabled && AbsoluteTime_to_scalar(&abstime) && workLoop) {
519 		wakeAtTime(abstime);
520 	}
521 }
522 
523 IOReturn
524 IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
525 {
526 	return wakeAtTime(0, inAbstime, 0);
527 }
528 
529 IOReturn
530 IOTimerEventSource::wakeAtTime(uint32_t options, AbsoluteTime inAbstime, AbsoluteTime leeway)
531 {
532 	if (!action) {
533 		return kIOReturnNoResources;
534 	}
535 
536 	abstime = inAbstime;
537 	if (enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop) {
538 		uint32_t tcoptions = 0;
539 
540 		if (kIOTimeOptionsWithLeeway & options) {
541 			tcoptions |= THREAD_CALL_DELAY_LEEWAY;
542 		}
543 		if (kIOTimeOptionsContinuous & options) {
544 			tcoptions |= THREAD_CALL_CONTINUOUS;
545 		}
546 
547 		if (reserved) {
548 			if (kPassive & flags) {
549 				retain();
550 				workLoop->retain();
551 			}
552 			reserved->workLoop = workLoop;
553 			reserved->calloutGeneration++;
554 			if (thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry,
555 			    (void *)(uintptr_t) reserved->calloutGeneration, inAbstime, leeway, tcoptions)
556 			    && (kPassive & flags)) {
557 				release();
558 				workLoop->release();
559 			}
560 		} else {
561 			thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry,
562 			    NULL, inAbstime, leeway, tcoptions);
563 		}
564 	}
565 
566 	return kIOReturnSuccess;
567 }
568