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