]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOTimerEventSource.cpp
xnu-1504.3.12.tar.gz
[apple/xnu.git] / iokit / Kernel / IOTimerEventSource.cpp
index 21dcf4691d2cc328e3c603cc6a2c48ca5355a336..ed45f6ab94ce550e28c44e473d2897064a77c482 100644 (file)
@@ -1,16 +1,19 @@
 /*
  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
  * 
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
@@ -20,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved. 
@@ -60,6 +63,11 @@ OSMetaClassDefineReservedUnused(IOTimerEventSource, 5);
 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6);
 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7);
 
+// 
+// reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
+// not a subclassed implementation. 
+//
+
 bool IOTimerEventSource::checkForWork() { return false; }
 
 // Timeout handler function. This function is called by the kernel when
@@ -69,22 +77,62 @@ void IOTimerEventSource::timeout(void *self)
 {
     IOTimerEventSource *me = (IOTimerEventSource *) self;
 
-    if (me->enabled) {
-        Action doit = (Action) me->action;
+    if (me->enabled && me->action)
+    {
+        IOWorkLoop *
+        wl = me->workLoop;
+        if (wl)
+        {
+            Action doit;
+            wl->closeGate();
+            doit = (Action) me->action;
+            if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime))
+            {
+                IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION),
+                                    (uintptr_t) doit, (uintptr_t) me->owner);
+                (*doit)(me->owner, me);
+            }
+            wl->openGate();
+        }
+    }
+}
 
-        if (doit) {
-            IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION),
-                                (unsigned int) doit, (unsigned int) me->owner);
-            me->closeGate();
-            (*doit)(me->owner, me);
-            me->openGate();
+void IOTimerEventSource::timeoutAndRelease(void * self, void * c)
+{
+    IOTimerEventSource *me = (IOTimerEventSource *) self;
+       /* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count"
+          must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */
+       SInt32 count = (SInt32) (long) c;
+
+    if (me->enabled && me->action)
+    {
+        IOWorkLoop *
+        wl = me->reserved->workLoop;
+        if (wl)
+        {
+            Action doit;
+            wl->closeGate();
+            doit = (Action) me->action;
+            if (doit && (me->reserved->calloutGeneration == count))
+            {
+                IOTimeStampConstant(IODBG_TIMES(IOTIMES_ACTION),
+                                    (uintptr_t) doit, (uintptr_t) me->owner);
+                (*doit)(me->owner, me);
+            }
+            wl->openGate();
         }
     }
+
+    me->reserved->workLoop->release();
+    me->release();
 }
 
 void IOTimerEventSource::setTimeoutFunc()
 {
-    calloutEntry = (void *) thread_call_allocate((thread_call_func_t) timeout,
+    // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used,
+    // not a subclassed implementation
+    reserved = IONew(ExpansionData, 1);
+    calloutEntry = (void *) thread_call_allocate((thread_call_func_t) &IOTimerEventSource::timeoutAndRelease,
                                                  (thread_call_param_t) this);
 }
 
@@ -120,13 +168,23 @@ void IOTimerEventSource::free()
         thread_call_free((thread_call_t) calloutEntry);    
     }
 
+    if (reserved)
+        IODelete(reserved, ExpansionData, 1);
+
     super::free();
 }
 
 void IOTimerEventSource::cancelTimeout()
 {
-    thread_call_cancel((thread_call_t) calloutEntry);
+    if (reserved)
+        reserved->calloutGeneration++;
+    bool active = thread_call_cancel((thread_call_t) calloutEntry);
     AbsoluteTime_to_scalar(&abstime) = 0;
+    if (active && reserved)
+    {
+        release();
+        workLoop->release();
+    }
 }
 
 void IOTimerEventSource::enable()
@@ -138,13 +196,20 @@ void IOTimerEventSource::enable()
 
 void IOTimerEventSource::disable()
 {
-    thread_call_cancel((thread_call_t) calloutEntry);
+    if (reserved)
+        reserved->calloutGeneration++;
+    bool active = thread_call_cancel((thread_call_t) calloutEntry);
     super::disable();
+    if (active && reserved)
+    {
+        release();
+        workLoop->release();
+    }
 }
 
 IOReturn IOTimerEventSource::setTimeoutTicks(UInt32 ticks)
 {
-    return setTimeout(ticks, NSEC_PER_SEC/hz);
+    return setTimeout(ticks, kTickScale);
 }
 
 IOReturn IOTimerEventSource::setTimeoutMS(UInt32 ms)
@@ -160,11 +225,12 @@ IOReturn IOTimerEventSource::setTimeoutUS(UInt32 us)
 IOReturn IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor)
 {
     AbsoluteTime end;
-    
+
     clock_interval_to_deadline(interval, scale_factor, &end);
     return wakeAtTime(end);
 }
 
+#if !defined(__LP64__)
 IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval)
 {
     AbsoluteTime end, nsecs;
@@ -177,6 +243,7 @@ IOReturn IOTimerEventSource::setTimeout(mach_timespec_t interval)
 
     return wakeAtTime(end);
 }
+#endif
 
 IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval)
 {
@@ -190,7 +257,7 @@ IOReturn IOTimerEventSource::setTimeout(AbsoluteTime interval)
 
 IOReturn IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks)
 {
-    return wakeAtTime(ticks, NSEC_PER_SEC/hz);
+    return wakeAtTime(ticks, kTickScale);
 }
 
 IOReturn IOTimerEventSource::wakeAtTimeMS(UInt32 ms)
@@ -203,26 +270,35 @@ IOReturn IOTimerEventSource::wakeAtTimeUS(UInt32 us)
     return wakeAtTime(us, kMicrosecondScale);
 }
 
-IOReturn IOTimerEventSource::wakeAtTime(UInt32 abstime, UInt32 scale_factor)
+IOReturn IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor)
 {
     AbsoluteTime end;
-    clock_interval_to_absolutetime_interval(abstime, scale_factor, &end);
+    clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end);
 
     return wakeAtTime(end);
 }
 
-IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t abstime)
+#if !defined(__LP64__)
+IOReturn IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime)
 {
     AbsoluteTime end, nsecs;
 
     clock_interval_to_absolutetime_interval
-        (abstime.tv_nsec, kNanosecondScale, &nsecs);
+        (inAbstime.tv_nsec, kNanosecondScale, &nsecs);
     clock_interval_to_absolutetime_interval
-        (abstime.tv_sec, kSecondScale, &end);
+        (inAbstime.tv_sec, kSecondScale, &end);
     ADD_ABSOLUTETIME(&end, &nsecs);
 
     return wakeAtTime(end);
 }
+#endif
+
+void IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop)
+{
+    super::setWorkLoop(inWorkLoop);
+    if ( enabled && AbsoluteTime_to_scalar(&abstime) && workLoop )
+        wakeAtTime(abstime);
+}
 
 IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
 {
@@ -230,8 +306,24 @@ IOReturn IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime)
         return kIOReturnNoResources;
 
     abstime = inAbstime;
-    if ( enabled && AbsoluteTime_to_scalar(&abstime) )
-        thread_call_enter_delayed((thread_call_t) calloutEntry, abstime);
+    if ( enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop )
+    {
+        if (reserved)
+        {
+            retain();
+            workLoop->retain();
+            reserved->workLoop = workLoop;
+            reserved->calloutGeneration++;
+            if (thread_call_enter1_delayed((thread_call_t) calloutEntry, 
+                    (void *) reserved->calloutGeneration, inAbstime))
+            {
+                release();
+                workLoop->release();
+            }
+        }
+        else
+            thread_call_enter_delayed((thread_call_t) calloutEntry, inAbstime);
+    }
 
     return kIOReturnSuccess;
 }