Author: lubosd
Date: Wed Apr 16 16:00:32 2014
New Revision: 37797

URL: http://svn.gna.org/viewcvs/gnustep?rev=37797&view=rev
Log:
* Source/CFRunLoop.c,
  Source/CFRuntime.c: Work on CFRunLoop


Modified:
    libs/corebase/trunk/ChangeLog
    libs/corebase/trunk/Source/CFRunLoop.c
    libs/corebase/trunk/Source/CFRuntime.c

Modified: libs/corebase/trunk/ChangeLog
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/ChangeLog?rev=37797&r1=37796&r2=37797&view=diff
==============================================================================
--- libs/corebase/trunk/ChangeLog       (original)
+++ libs/corebase/trunk/ChangeLog       Wed Apr 16 16:00:32 2014
@@ -1,3 +1,7 @@
+2014-04-16 Lubos Dolezel <[email protected]>
+       * Source/CFRunLoop.c,
+         Source/CFRuntime.c: Work on CFRunLoop
+
 2014-02-19 Stefan Bidigaray <[email protected]>
        * configure,
        * configure.ac: Use autoconf's built-in functions and introduce

Modified: libs/corebase/trunk/Source/CFRunLoop.c
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/Source/CFRunLoop.c?rev=37797&r1=37796&r2=37797&view=diff
==============================================================================
--- libs/corebase/trunk/Source/CFRunLoop.c      (original)
+++ libs/corebase/trunk/Source/CFRunLoop.c      Wed Apr 16 16:00:32 2014
@@ -33,6 +33,15 @@
 #include "GSPrivate.h"
 #include "GSObjCRuntime.h"
 
+#ifndef _WIN32
+#      include <unistd.h>
+#      include <fcntl.h>
+#      include <poll.h>
+#endif
+#ifdef HAVE_LIBDISPATCH
+#      include <dispatch/dispatch.h>
+#endif
+
 /* From NSDate.m in GNUstep-base */
 #define DISTANT_FUTURE 63113990400.0
 
@@ -40,6 +49,9 @@
 static CFTypeID _kCFRunLoopSourceTypeID = 0;
 static CFTypeID _kCFRunLoopObserverTypeID = 0;
 static CFTypeID _kCFRunLoopTimerTypeID = 0;
+
+static CFRunLoopRef static_mainLoop = NULL;
+static pthread_key_t static_loopKey;
 
 CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode");
 CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes");
@@ -62,6 +74,10 @@
   CFMutableSetRef   _commonModes;
   CFMutableArrayRef _commonObjects;
   CFMutableDictionaryRef _contexts;
+
+  int     _wakeUpPipe[2];
+  Boolean _isWaiting; /* Whether the runloop is currently in a select/poll 
call */
+  Boolean _stop; /* Whether the runloop was told to stop */
 };
 
 struct __CFRunLoopSource
@@ -72,6 +88,7 @@
   Boolean       _isSignaled;
   Boolean       _isValid;
   CFRunLoopSourceContext _context; /* FIXME: Handle version 1 contexts */
+  CFRunLoopRef   _runloop;
 };
 
 struct __CFRunLoopObserver
@@ -84,6 +101,7 @@
   Boolean       _isValid;
   CFRunLoopObserverCallBack _callback;
   CFRunLoopObserverContext  _context;
+  CFRunLoopRef   _runloop;
 };
 
 struct __CFRunLoopTimer
@@ -96,6 +114,7 @@
   Boolean        _isValid;
   CFRunLoopTimerCallBack _callback;
   CFRunLoopTimerContext  _context;
+  CFRunLoopRef   _runloop;
 };
 
 static GSRunLoopContextRef
@@ -112,7 +131,7 @@
 {
   CFRunLoopRef rl = (CFRunLoopRef)cf;
   CFAllocatorRef alloc = CFGetAllocator (rl);
-  CFRelease (rl->_currentMode);
+
   CFRelease (rl->_commonModes);
   CFRelease (rl->_commonObjects);
   CFDictionaryApplyFunction (rl->_contexts, GSRunLoopContextDeallocFunc,
@@ -196,7 +215,8 @@
   NULL
 };
 
-
+#define CFRUNLOOP_SIZE \
+  sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase)
 
 void
 CFRunLoopInitialize (void)
@@ -303,18 +323,66 @@
   return ctxt;
 }
 
-
+static CFRunLoopRef
+CFRunLoopCreate (void)
+{
+  CFRunLoopRef rl;
+
+  rl = (CFRunLoopRef)_CFRuntimeCreateInstance (kCFAllocatorDefault,
+                                               _kCFRunLoopTypeID,
+                                               CFRUNLOOP_SIZE,
+                                               0);
+  rl->_commonModes = CFSetCreateMutable(kCFAllocatorDefault,
+                                        0, &kCFTypeSetCallBacks);
+  rl->_commonObjects = CFArrayCreateMutable(kCFAllocatorDefault,
+                                        0, &kCFTypeArrayCallBacks);
+  rl->_contexts = CFDictionaryCreateMutable(kCFAllocatorDefault,
+                                        0, &kCFTypeDictionaryKeyCallBacks,
+                                        NULL);
+
+  pipe(rl->_wakeUpPipe);
+  fcntl(rl->_wakeUpPipe[0], F_SETFL, O_NONBLOCK);
+  fcntl(rl->_wakeUpPipe[1], F_SETFL, O_NONBLOCK);
+
+  return rl;
+}
+
+static void
+_CFRunLoopCreateThreadKey (void)
+{
+  pthread_key_create(&static_loopKey, (void(*)(void*)) CFRelease);
+}
 
 CFRunLoopRef
 CFRunLoopGetCurrent (void)
 {
-  return NULL;
+  static pthread_once_t once = PTHREAD_ONCE_INIT;
+  CFRunLoopRef rl;
+
+  pthread_once(&once, _CFRunLoopCreateThreadKey);
+
+  rl = pthread_getspecific(static_loopKey);
+  if (rl == NULL)
+    {
+      rl = CFRunLoopCreate();
+      pthread_setspecific(static_loopKey, rl);
+    }
+
+  return rl;
+}
+
+static void
+_CFRunLoopCreateMain (void)
+{
+  static_mainLoop = CFRunLoopGetCurrent();
 }
 
 CFRunLoopRef
 CFRunLoopGetMain (void)
 {
-  return NULL;
+  static pthread_once_t once = PTHREAD_ONCE_INIT;
+  pthread_once(&once, _CFRunLoopCreateMain);
+  return static_mainLoop;
 }
 
 void
@@ -325,6 +393,121 @@
     {
       code = CFRunLoopRunInMode (kCFRunLoopDefaultMode, DISTANT_FUTURE, false);
     } while (code != kCFRunLoopRunFinished || code != kCFRunLoopRunStopped);
+}
+
+static void
+CFRunLoopNotifyObservers (GSRunLoopContextRef context, CFRunLoopActivity 
activity)
+{
+  CFRunLoopObserverRef *observers;
+  CFIndex i, count;
+
+  count = CFSetGetCount(context->observers);
+  observers = (CFRunLoopObserverRef*) CFAllocatorAllocate(NULL,
+                                   sizeof(CFRunLoopObserverRef)*count, 0);
+  CFSetGetValues(context->observers, (const void**) observers);
+
+  for (i = 0; i < count; i++)
+    CFRetain(observers[i]);
+
+  for (i = 0; i < count; i++)
+    {
+      CFRunLoopObserverRef observer = observers[i];
+
+      if (observer->_isValid && observer->_activities & activity)
+        {
+          observer->_callback(observer, activity, observer->_context.info);
+
+          if (!observer->_repeats)
+            observer->_isValid = false;
+        }
+
+      CFRelease(observer);
+    }
+
+  CFAllocatorDeallocate(NULL, (void*) observers);
+}
+
+static Boolean
+CFRunLoopProcessTimers (CFAbsoluteTime now, GSRunLoopContextRef context)
+{
+  CFIndex i, count;
+  CFRunLoopTimerRef *timers;
+  Boolean hadTimer = false;
+
+  CFRunLoopNotifyObservers(context, kCFRunLoopBeforeTimers);
+
+  // Make a copy of timers so that we don't crash if timer's callback removes 
it
+  // from the set of timers.
+  count = CFArrayGetCount(context->timers);
+  timers = (CFRunLoopTimerRef*) CFAllocatorAllocate(NULL,
+                                sizeof(CFRunLoopTimerRef)*count, 0);
+
+  CFArrayGetValues(context->timers, CFRangeMake(0, count), (const void**) 
timers);
+
+  for (i = 0; i < count; i++)
+    CFRetain(timers[i]);
+
+  for (i = 0; i < count; i++)
+    {
+      CFRunLoopTimerRef timer = timers[i];
+
+      if (timer->_nextFireDate < now)
+        {
+          hadTimer = true;
+          timer->_callback(timer, timer->_context.info);
+        }
+
+      if (timer->_isValid)
+        {
+          // Compute the next time
+          if (timer->_interval <= 0)
+            timer->_isValid = false;
+          else
+            timer->_nextFireDate = now + timer->_interval;
+        }
+
+      CFRelease(timer);
+    }
+
+  CFAllocatorDeallocate(NULL, (void*) timers);
+  return hadTimer;
+}
+
+static Boolean
+CFRunLoopProcessSourcesVersion0 (CFAbsoluteTime now, GSRunLoopContextRef 
context)
+{
+  CFIndex i, count;
+  CFRunLoopSourceRef *sources;
+  Boolean hadSource = false;
+
+  // Notify observers with kCFRunLoopBeforeSources activity.
+  CFRunLoopNotifyObservers(context, kCFRunLoopBeforeSources);
+
+  count = CFSetGetCount(context->sources0);
+  sources = (CFRunLoopSourceRef*) CFAllocatorAllocate(NULL,
+                                  sizeof(CFRunLoopSourceRef)*count, 0);
+
+  CFSetGetValues(context->sources0, (const void**) sources);
+
+  for (i = 0; i < count; i++)
+    CFRetain(sources[i]);
+
+  for (i = 0; i < count; i++)
+    {
+      CFRunLoopSourceRef source = sources[i];
+
+      if (source->_isValid && source->_isSignaled)
+        {
+          hadSource = true;
+          source->_isSignaled = false;
+          source->_context.perform(source->_context.info);
+        }
+
+      CFRelease(source);
+    }
+
+  CFAllocatorDeallocate(NULL, (void*) sources);
+  return hadSource;
 }
 
 SInt32
@@ -346,31 +529,169 @@
    *   - Someone calls CFRunLoopWakeUp(). 
    * 8. Notify observers with kCFRunLoopAfterWaiting activity.
    * 9. Process the pending event.
-   *   - Process timers with fire dates in the pass.
+   *   - Process timers with fire dates in the past.
    *   - If an input source fired, deliver the event.
    *   - If CFRunLoopWakeUp() was called but the run loop has not timed out,
    *     restart the loop. Go to step 2.
    * 10. Notify observers with kCFRunLoopExit activity.
    */
-  return 0;
+  CFRunLoopRef rl = CFRunLoopGetCurrent();
+  const Boolean isMainLoop = CFRunLoopGetCurrent() == CFRunLoopGetMain();
+  const CFAbsoluteTime timeStart = CFAbsoluteTimeGetCurrent();
+  CFAbsoluteTime timeNow = timeStart;
+  SInt32 exitReason = 0;
+  Boolean hadSource = false;
+  struct pollfd pfd[2];
+  int numSources = 1;
+  GSRunLoopContextRef context = GSRunLoopContextGet(rl, mode);
+
+  rl->_currentMode = mode;
+
+  pfd[0].fd = rl->_wakeUpPipe[0];
+  pfd[0].events = POLLIN;
+  pfd[0].revents = 0;
+
+#if HAVE_LIBDISPATCH
+  if (isMainLoop)
+    {
+      // integrate libdispatch
+      pfd[1].fd = dispatch_get_main_queue_eventfd_np();
+      pfd[1].events = POLLIN;
+      pfd[1].revents = 0;
+
+      numSources++;
+    }
+#endif
+
+  // Notify observers with kCFRunLoopEntry activity.
+  CFRunLoopNotifyObservers(context, kCFRunLoopEntry);
+
+  GSMutexLock (&rl->_lock);
+  hadSource |= CFRunLoopProcessTimers(timeStart, context);
+  hadSource |= CFRunLoopProcessSourcesVersion0(timeStart, context);
+  GSMutexUnlock (&rl->_lock);
+
+  if (returnAfterSourceHandled && hadSource)
+    {
+      exitReason = kCFRunLoopRunHandledSource;
+    }
+
+  timeNow = CFAbsoluteTimeGetCurrent();
+
+  while (exitReason == 0)
+    {
+      int sourcesFired, timeout;
+
+      hadSource = false;
+
+      if (seconds == 0)
+        timeout = 0; // only one pass
+      else if (seconds >= DISTANT_FUTURE)
+        timeout = -1;
+      else
+        timeout = (int) (seconds - (timeNow - timeStart) * 1000);
+
+      if (timeout != 0)
+        {
+          // Check all timers in current mode and plan the timeout accordingly.
+          CFAbsoluteTime nextTimer = CFRunLoopGetNextTimerFireDate(rl, mode);
+          if (nextTimer < DISTANT_FUTURE)
+            {
+              int delay = (int) ( (nextTimer - timeNow)*1000 );
+              if (timeout == -1 || delay < timeout)
+                timeout = delay;
+            }
+        }
+
+      if (rl->_stop)
+        {
+          exitReason = kCFRunLoopRunStopped;
+          rl->_stop = false;
+          break;
+        }
+        
+      // Notify observers with kCFRunLoopBeforeWaiting activity.
+      CFRunLoopNotifyObservers(context, kCFRunLoopBeforeWaiting);
+      rl->_isWaiting = true;
+
+      sourcesFired = poll(pfd, numSources, timeout);
+
+      rl->_isWaiting = false;
+      // Notify observers with kCFRunLoopAfterWaiting activity.
+      CFRunLoopNotifyObservers(context, kCFRunLoopAfterWaiting);
+
+      if (sourcesFired < 0) // error
+        {
+          // TODO: print explanation into the console?
+          exitReason = kCFRunLoopRunFinished;
+          break;
+        }
+      else if (sourcesFired > 0)
+        {
+          if (pfd[0].revents != 0)
+            {
+              int dummy;
+
+              // Remove everything from the notification pipe that woke us up
+              while (read(pfd[0].fd, &dummy, sizeof(dummy)) > 0);
+            }
+
+#if HAVE_LIBDISPATCH
+          if (pfd[1].revents != 0)
+            {
+              dispatch_main_queue_drain_np();
+              hadSource = true;
+            }
+#endif
+
+          GSMutexLock (&rl->_lock);
+          hadSource |= CFRunLoopProcessTimers(timeNow, context);
+          hadSource |= CFRunLoopProcessSourcesVersion0(timeNow, context);
+          GSMutexUnlock (&rl->_lock);
+        }
+
+      if (returnAfterSourceHandled && hadSource)
+        {
+          exitReason = kCFRunLoopRunHandledSource;
+          break;
+        }
+
+      timeNow = CFAbsoluteTimeGetCurrent();
+      if (CFAbsoluteTimeGetCurrent() >= timeStart+seconds)
+        {
+          exitReason = kCFRunLoopRunTimedOut;
+          break;
+        }
+    }
+
+  // Notify observers with kCFRunLoopExit activity.
+  CFRunLoopNotifyObservers(context, kCFRunLoopExit);
+  rl->_currentMode = NULL;
+
+  return exitReason;
 }
 
 void
 CFRunLoopWakeUp (CFRunLoopRef rl)
 {
-  return;
+  if (CFRunLoopIsWaiting(rl))
+    {
+      int dummy = 1;
+      write(rl->_wakeUpPipe[1], &dummy, sizeof(dummy));
+    }
 }
 
 void
 CFRunLoopStop (CFRunLoopRef rl)
 {
-  return;
+  if (rl->_currentMode != NULL)
+    rl->_stop = true;
 }
 
 Boolean
 CFRunLoopIsWaiting (CFRunLoopRef rl)
 {
-  return false;
+  return rl->_isWaiting;
 }
 
 void
@@ -424,16 +745,19 @@
 CFStringRef
 CFRunLoopCopyCurrentMode (CFRunLoopRef rl)
 {
-  return CFRetain (rl->_currentMode);
-}
-
-#if __BLOCKS__
-void
-CFRunLoopPerformBlock (CFRunLoopRef rl, CFTypeRef mode, void (^block)(void))
+  CFStringRef mode = rl->_currentMode;
+
+  if (mode != NULL)
+    return CFRetain (rl->_currentMode);
+  else
+    return NULL;
+}
+
+void
+CFRunLoopPerformBlock (CFRunLoopRef rl, CFTypeRef mode, PerformBlockType block)
 {
   return;
 }
-#endif
 
 
 
@@ -454,12 +778,19 @@
                            CFStringRef mode)
 {
   GSRunLoopContextRef ctxt;
+
+  if (source->_runloop != NULL && source->_runloop != rl)
+    return; // This source is already added elsewhere
+
+  source->_runloop = rl;
   
   ctxt = GSRunLoopContextGet (rl, mode);
   if (source->_context.version == 0)
     CFSetAddValue (ctxt->sources0, source);
   else if (source->_context.version == 1)
     CFSetAddValue (ctxt->sources1, source);
+
+  CFRunLoopWakeUp(rl);
 }
 
 static void
@@ -468,6 +799,11 @@
 {
   GSRunLoopContextRef ctxt;
   CFMutableSetRef observers;
+
+  if (obs->_runloop != NULL && obs->_runloop != rl)
+    return; // This observer is already added elsewhere
+
+  obs->_runloop = rl;
   
   ctxt = GSRunLoopContextGet (rl, mode);
   observers = ctxt->observers;
@@ -480,12 +816,20 @@
 {
   GSRunLoopContextRef ctxt;
   CFRange range;
+
+  if (timer->_runloop != NULL && timer->_runloop != rl)
+    return; // This timer is already added elsewhere
+
+  timer->_runloop = rl;
   
   ctxt = GSRunLoopContextGet (rl, mode);
   /* Only add the timer if one doesn't exist */
   range = CFRangeMake (0, CFArrayGetCount (ctxt->timers));
   if (CFArrayContainsValue (ctxt->timers, range, timer) == false)
     CFArrayAppendValue (ctxt->timers, timer);
+
+  // Wake up the runloop so that it can recalculate the next timer date
+  CFRunLoopWakeUp(rl);
 }
 
 
@@ -512,9 +856,9 @@
   Boolean ret;
   GSRunLoopContextRef ctxt;
   
-  GSMutexLock (&rl->_lock);
   ctxt = GSRunLoopContextGet (rl, mode);
   ret = CFSetContainsValue (ctxt->observers, obs);
+
   return ret;
 }
 
@@ -540,7 +884,6 @@
 {
   GSRunLoopContextRef ctxt;
   
-  GSMutexLock (&rl->_lock);
   ctxt = GSRunLoopContextGet (rl, mode);
   if (source->_context.version == 0)
     CFSetRemoveValue (ctxt->sources0, source);
@@ -554,7 +897,6 @@
 {
   GSRunLoopContextRef ctxt;
   
-  GSMutexLock (&rl->_lock);
   ctxt = GSRunLoopContextGet (rl, mode);
   CFSetRemoveValue (ctxt->observers, obs);
 }
@@ -926,7 +1268,7 @@
 void
 CFRunLoopObserverInvalidate (CFRunLoopObserverRef observer)
 {
-  return;
+  observer->_isValid = false;
 }
 
 Boolean
@@ -940,7 +1282,24 @@
 CFAbsoluteTime
 CFRunLoopGetNextTimerFireDate (CFRunLoopRef rl, CFStringRef mode)
 {
-  return 0.0;
+  CFAbsoluteTime rv = DISTANT_FUTURE;
+  CFIndex i, count;
+  GSRunLoopContextRef context = GSRunLoopContextGet(rl, mode);
+  
+  count = CFArrayGetCount(context->timers);
+
+  for (i = 0; i < count; i++)
+    {
+      CFRunLoopTimerRef timer = (CFRunLoopTimerRef) 
CFArrayGetValueAtIndex(context->timers, i);
+
+      if (timer->_isValid)
+        {
+          if (timer->_nextFireDate < rv)
+            rv = timer->_nextFireDate;
+        }
+    }
+
+  return rv;
 }
 
 #define CFRUNLOOPTIMER_SIZE \
@@ -1033,7 +1392,7 @@
   CF_OBJC_FUNCDISPATCHV(_kCFRunLoopTimerTypeID, void, timer,
                         "invalidate");
   
-  
+  timer->_isValid = false;
 }
 
 Boolean
@@ -1053,6 +1412,8 @@
   CF_OBJC_FUNCDISPATCHV(_kCFRunLoopTimerTypeID, void, timer,
                         "_cfSetNextFireDate:", fireDate);
   
-  return;
-}
-
+  timer->_nextFireDate = fireDate;
+  // Wake up the runloop so that it can recalculate the next timer date
+  CFRunLoopWakeUp(timer->_runloop);
+}
+

Modified: libs/corebase/trunk/Source/CFRuntime.c
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/Source/CFRuntime.c?rev=37797&r1=37796&r2=37797&view=diff
==============================================================================
--- libs/corebase/trunk/Source/CFRuntime.c      (original)
+++ libs/corebase/trunk/Source/CFRuntime.c      Wed Apr 16 16:00:32 2014
@@ -495,7 +495,6 @@
   CFNullInitialize ();
   CFNumberInitialize ();
   CFNumberFormatterInitialize ();
-  CFRunLoopInitialize ();
   CFSetInitialize ();
   CFStreamInitialize ();
   CFStringInitialize ();
@@ -505,6 +504,7 @@
   CFURLInitialize ();
   CFUUIDInitialize ();
   CFXMLNodeInitialize ();
+  CFRunLoopInitialize ();
 }
 
 #if defined(_MSC_VER)


_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs

Reply via email to