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     if (kActionBlock & flags) ((IOTimerEventSource::ActionBlock) actionBlock)(ts);
113     else                      (*action)(owner, ts);
114 
115 #if CONFIG_DTRACE
116     DTRACE_TMR3(iotescallout__expire, Action, action, OSObject, owner, void, workLoop);
117 #endif
118 
119     if (trace)
120 	IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION),
121 			       VM_KERNEL_UNSLIDE(action), VM_KERNEL_ADDRHIDE(owner));
122 }
123 
124 void IOTimerEventSource::timeout(void *self)
125 {
126     IOTimerEventSource *me = (IOTimerEventSource *) self;
127 
128     IOStatisticsTimeout();
129 
130     if (me->enabled && me->action)
131     {
132         IOWorkLoop *
133         wl = me->workLoop;
134         if (wl)
135         {
136             Action doit;
137             wl->closeGate();
138             IOStatisticsCloseGate();
139             doit = (Action) me->action;
140             if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime))
141             {
142                 me->invokeAction(doit, me, me->owner, me->workLoop);
143             }
144             IOStatisticsOpenGate();
145             wl->openGate();
146         }
147     }
148 }
149 
150 void IOTimerEventSource::timeoutAndRelease(void * self, void * c)
151 {
152     IOTimerEventSource *me = (IOTimerEventSource *) self;
153 	/* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
154 	   must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
155 	SInt32 count = (SInt32) (long) c;
156 
157     IOStatisticsTimeout();
158 
159     if (me->enabled && me->action)
160     {
161         IOWorkLoop *
162         wl = me->reserved->workLoop;
163         if (wl)
164         {
165             Action doit;
166             wl->closeGate();
167             IOStatisticsCloseGate();
168             doit = (Action) me->action;
169             if (doit && (me->reserved->calloutGeneration == count))
170             {
171                 me->invokeAction(doit, me, me->owner, me->workLoop);
172             }
173             IOStatisticsOpenGate();
174             wl->openGate();
175         }
176     }
177 
178     me->reserved->workLoop->release();
179     me->release();
180 }
181 
182 // -- work loop delivery
183 
184 bool IOTimerEventSource::checkForWork()
185 {
186     Action doit;
187 
188     if (reserved
189      && (reserved->calloutGenerationSignaled == reserved->calloutGeneration)
190      && enabled && (doit = (Action) action))
191     {
192 	reserved->calloutGenerationSignaled = ~reserved->calloutGeneration;
193 	invokeAction(doit, this, owner, workLoop);
194     }
195 
196     return false;
197 }
198 
199 void IOTimerEventSource::timeoutSignaled(void * self, void * c)
200 {
201     IOTimerEventSource *me = (IOTimerEventSource *) self;
202 
203     me->reserved->calloutGenerationSignaled = (SInt32)(long) c;
204     if (me->enabled) me->signalWorkAvailable();
205 }
206 
207 // --
208 
209 void IOTimerEventSource::setTimeoutFunc()
210 {
211     thread_call_priority_t pri;
212     uint32_t options;
213 
214     if (reserved) panic("setTimeoutFunc already %p, %p", this, reserved);
215 
216     // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
217     // not a subclassed implementation
218     reserved = IONew(ExpansionData, 1);
219     reserved->calloutGenerationSignaled = ~reserved->calloutGeneration;
220     options = abstime;
221     abstime = 0;
222 
223     thread_call_options_t tcoptions = 0;
224     thread_call_func_t    func      = NULL;
225 
226     switch (kIOTimerEventSourceOptionsPriorityMask & options)
227     {
228       case kIOTimerEventSourceOptionsPriorityHigh:
229         pri = THREAD_CALL_PRIORITY_HIGH;
230         func = &IOTimerEventSource::timeoutAndRelease;
231         break;
232 
233       case kIOTimerEventSourceOptionsPriorityKernel:
234         pri = THREAD_CALL_PRIORITY_KERNEL;
235         func = &IOTimerEventSource::timeoutAndRelease;
236         break;
237 
238       case kIOTimerEventSourceOptionsPriorityKernelHigh:
239         pri = THREAD_CALL_PRIORITY_KERNEL_HIGH;
240         func = &IOTimerEventSource::timeoutAndRelease;
241         break;
242 
243       case kIOTimerEventSourceOptionsPriorityUser:
244         pri = THREAD_CALL_PRIORITY_USER;
245         func = &IOTimerEventSource::timeoutAndRelease;
246         break;
247 
248       case kIOTimerEventSourceOptionsPriorityLow:
249         pri = THREAD_CALL_PRIORITY_LOW;
250         func = &IOTimerEventSource::timeoutAndRelease;
251         break;
252 
253       case kIOTimerEventSourceOptionsPriorityWorkLoop:
254         pri = THREAD_CALL_PRIORITY_KERNEL;
255         tcoptions |= THREAD_CALL_OPTIONS_SIGNAL;
256         if (kIOTimerEventSourceOptionsAllowReenter & options) break;
257         func = &IOTimerEventSource::timeoutSignaled;
258         break;
259 
260       default:
261         break;
262     }
263 
264     assertf(func, "IOTimerEventSource options 0x%x", options);
265     if (!func) return;		                                     // init will fail
266 
267     if (THREAD_CALL_OPTIONS_SIGNAL & tcoptions) flags |= kActive;
268     else                                        flags |= kPassive;
269 
270     if (!(kIOTimerEventSourceOptionsAllowReenter & options)) tcoptions |= THREAD_CALL_OPTIONS_ONCE;
271 
272     calloutEntry = (void *) thread_call_allocate_with_options(func,
273         (thread_call_param_t) this, pri, tcoptions);
274     assert(calloutEntry);
275 }
276 
277 bool IOTimerEventSource::init(OSObject *inOwner, Action inAction)
278 {
279     if (!super::init(inOwner, (IOEventSource::Action) inAction) )
280         return false;
281 
282     setTimeoutFunc();
283     if (!calloutEntry)
284         return false;
285 
286     IOStatisticsInitializeCounter();
287 
288     return true;
289 }
290 
291 bool IOTimerEventSource::init(uint32_t options, OSObject *inOwner, Action inAction)
292 {
293     abstime = options;
294     return (init(inOwner, inAction));
295 }
296 
297 IOTimerEventSource *
298 IOTimerEventSource::timerEventSource(uint32_t inOptions, OSObject *inOwner, Action inAction)
299 {
300     IOTimerEventSource *me = new IOTimerEventSource;
301 
302     if (me && !me->init(inOptions, inOwner, inAction)) {
303         me->release();
304         return 0;
305     }
306 
307     return me;
308 }
309 
310 IOTimerEventSource *
311 IOTimerEventSource::timerEventSource(uint32_t options, OSObject *inOwner, ActionBlock action)
312 {
313     IOTimerEventSource * tes;
314     tes = IOTimerEventSource::timerEventSource(options, inOwner, (Action) NULL);
315     if (tes) tes->setActionBlock((IOEventSource::ActionBlock) action);
316 
317     return tes;
318 }
319 
320 #define _thread_call_cancel(tc)   ((kActive & flags) ? thread_call_cancel_wait((tc)) : thread_call_cancel((tc)))
321 
322 IOTimerEventSource *
323 IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction)
324 {
325     return (IOTimerEventSource::timerEventSource(
326                 kIOTimerEventSourceOptionsPriorityKernelHigh,
327                 inOwner, inAction));
328 }
329 
330 void IOTimerEventSource::free()
331 {
332     if (calloutEntry) {
333         __assert_only bool freed;
334 
335         cancelTimeout();
336 
337         freed = thread_call_free((thread_call_t) calloutEntry);
338         assert(freed);
339     }
340 
341     if (reserved)
342         IODelete(reserved, ExpansionData, 1);
343 
344     super::free();
345 }
346 
347 void IOTimerEventSource::cancelTimeout()
348 {
349     if (reserved)
350         reserved->calloutGeneration++;
351     bool active = _thread_call_cancel((thread_call_t) calloutEntry);
352     AbsoluteTime_to_scalar(&abstime) = 0;
353     if (active && reserved && (kPassive & flags))
354     {
355         release();
356         workLoop->release();
357     }
358 }
359 
360 void IOTimerEventSource::enable()
361 {
362     super::enable();
363     if (kIOReturnSuccess != wakeAtTime(abstime))
364         super::disable(); // Problem re-scheduling timeout ignore enable
365 }
366 
367 void IOTimerEventSource::disable()
368 {
369     if (reserved)
370         reserved->calloutGeneration++;
371     bool active = _thread_call_cancel((thread_call_t) calloutEntry);
372     super::disable();
373     if (active && reserved && (kPassive & flags))
374     {
375         release();
376         workLoop->release();
377     }
378 }
379 
380 IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
381 {
382     return setTimeout(ticks, kTickScale);
383 }
384 
385 IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms)
386 {
387     return setTimeout(ms, kMillisecondScale);
388 }
389 
390 IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us)
391 {
392     return setTimeout(us, kMicrosecondScale);
393 }
394 
395 IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
396 {
397     AbsoluteTime end;
398 
399     clock_interval_to_deadline(interval, scale_factor, &end);
400     return wakeAtTime(end);
401 }
402 
403 #if !defined(__LP64__)
404 IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval)
405 {
406     AbsoluteTime end, nsecs;
407 
408     clock_interval_to_absolutetime_interval
409         (interval.tv_nsec, kNanosecondScale, &nsecs);
410     clock_interval_to_deadline
411         (interval.tv_sec, NSEC_PER_SEC, &end);
412     ADD_ABSOLUTETIME(&end, &nsecs);
413 
414     return wakeAtTime(end);
415 }
416 #endif
417 
418 IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval)
419 {
420     AbsoluteTime end;
421     clock_absolutetime_interval_to_deadline(interval, &end);
422     return wakeAtTime(end);
423 }
424 
425 IOReturn IOTimerEventSource::setTimeout(uint32_t options,
426 					AbsoluteTime abstime, AbsoluteTime leeway)
427 {
428     AbsoluteTime end;
429     if (options & kIOTimeOptionsContinuous)
430         clock_continuoustime_interval_to_deadline(abstime, &end);
431     else
432         clock_absolutetime_interval_to_deadline(abstime, &end);
433 
434     return wakeAtTime(options, end, leeway);
435 }
436 
437 IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
438 {
439     return wakeAtTime(ticks, kTickScale);
440 }
441 
442 IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
443 {
444     return wakeAtTime(ms, kMillisecondScale);
445 }
446 
447 IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us)
448 {
449     return wakeAtTime(us, kMicrosecondScale);
450 }
451 
452 IOReturn IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
453 {
454     AbsoluteTime end;
455     clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
456 
457     return wakeAtTime(end);
458 }
459 
460 #if !defined(__LP64__)
461 IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
462 {
463     AbsoluteTime end, nsecs;
464 
465     clock_interval_to_absolutetime_interval
466         (inAbstime.tv_nsec, kNanosecondScale, &nsecs);
467     clock_interval_to_absolutetime_interval
468         (inAbstime.tv_sec, kSecondScale, &end);
469     ADD_ABSOLUTETIME(&end, &nsecs);
470 
471     return wakeAtTime(end);
472 }
473 #endif
474 
475 void IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
476 {
477     super::setWorkLoop(inWorkLoop);
478     if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop )
479         wakeAtTime(abstime);
480 }
481 
482 IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
483 {
484     return wakeAtTime(0, inAbstime, 0);
485 }
486 
487 IOReturn IOTimerEventSource::wakeAtTime(uint32_t options, AbsoluteTime inAbstime, AbsoluteTime leeway)
488 {
489     if (!action)
490         return kIOReturnNoResources;
491 
492     abstime = inAbstime;
493     if ( enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop )
494     {
495         uint32_t tcoptions = 0;
496 
497         if (kIOTimeOptionsWithLeeway & options) tcoptions |= THREAD_CALL_DELAY_LEEWAY;
498         if (kIOTimeOptionsContinuous & options) tcoptions |= THREAD_CALL_CONTINUOUS;
499 
500         if (reserved)
501         {
502 	    if (kPassive & flags)
503 	    {
504 		retain();
505 		workLoop->retain();
506 	    }
507             reserved->workLoop = workLoop;
508             reserved->calloutGeneration++;
509             if (thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry,
510                     (void *)(uintptr_t) reserved->calloutGeneration, inAbstime, leeway, tcoptions)
511               && (kPassive & flags))
512             {
513                 release();
514                 workLoop->release();
515             }
516         }
517         else
518         {
519             thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry,
520                     NULL, inAbstime, leeway, tcoptions);
521         }
522     }
523 
524     return kIOReturnSuccess;
525 }
526