Author: lubosd
Date: Fri Apr 18 23:06:15 2014
New Revision: 37803

URL: http://svn.gna.org/viewcvs/gnustep?rev=37803&view=rev
Log:
2014-04-18 Lubos Dolezel <[email protected]>
        * Source/CFRunLoop.c,
          Tests/CFRunLoop/source.m: CFRunLoop impl that passes the test


Modified:
    libs/corebase/trunk/ChangeLog
    libs/corebase/trunk/Headers/CoreFoundation/CFRunLoop.h
    libs/corebase/trunk/Source/CFRunLoop.c
    libs/corebase/trunk/Tests/CFRunLoop/source.m

Modified: libs/corebase/trunk/ChangeLog
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/ChangeLog?rev=37803&r1=37802&r2=37803&view=diff
==============================================================================
--- libs/corebase/trunk/ChangeLog       (original)
+++ libs/corebase/trunk/ChangeLog       Fri Apr 18 23:06:15 2014
@@ -1,3 +1,7 @@
+2014-04-18 Lubos Dolezel <[email protected]>
+       * Source/CFRunLoop.c,
+         Tests/CFRunLoop/source.m: CFRunLoop impl that passes the test
+
 2014-04-16 Lubos Dolezel <[email protected]>
        * Source/CFRunLoop.c,
          Source/CFRuntime.c: Work on CFRunLoop

Modified: libs/corebase/trunk/Headers/CoreFoundation/CFRunLoop.h
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/Headers/CoreFoundation/CFRunLoop.h?rev=37803&r1=37802&r2=37803&view=diff
==============================================================================
--- libs/corebase/trunk/Headers/CoreFoundation/CFRunLoop.h      (original)
+++ libs/corebase/trunk/Headers/CoreFoundation/CFRunLoop.h      Fri Apr 18 
23:06:15 2014
@@ -31,6 +31,7 @@
 #include <CoreFoundation/CFArray.h>
 #include <CoreFoundation/CFDate.h>
 #include <CoreFoundation/CFError.h>
+#include <GNUstepBase/GSBlocks.h>
 
 CF_EXTERN_C_BEGIN
 
@@ -197,11 +198,11 @@
 /*
  * Scheduling Blocks
  */
-#if __BLOCKS__
 #if OS_API_VERSION(MAC_OS_X_VERSION_10_4, GS_API_LATEST)
-CF_EXPORT void
-CFRunLoopPerformBlock (CFRunLoopRef rl, CFTypeRef mode, void (^block)(void));
-#endif
+DEFINE_BLOCK_TYPE_NO_ARGS(PerformBlockType, void);
+
+CF_EXPORT void
+CFRunLoopPerformBlock (CFRunLoopRef rl, CFTypeRef mode, PerformBlockType 
block);
 #endif
 
 /*

Modified: libs/corebase/trunk/Source/CFRunLoop.c
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/Source/CFRunLoop.c?rev=37803&r1=37802&r2=37803&view=diff
==============================================================================
--- libs/corebase/trunk/Source/CFRunLoop.c      (original)
+++ libs/corebase/trunk/Source/CFRunLoop.c      Fri Apr 18 23:06:15 2014
@@ -64,6 +64,7 @@
   CFMutableSetRef observers;
   CFMutableSetRef sources0;
   CFMutableSetRef sources1; /* This is only a place holder for now. */
+  CFMutableArrayRef blocks;
 };
 
 struct __CFRunLoop
@@ -126,6 +127,26 @@
 static void
 GSRunLoopContextDeallocFunc (const void *key, const void *value, void *ctxt);
 
+static const void *
+BlockRetainCallback(CFAllocatorRef allocator, const void *value)
+{
+  return (const void *) _Block_copy((void *) value);
+}
+
+static void
+BlockReleaseCallback(CFAllocatorRef allocator, const void *value)
+{
+  _Block_release((void *) value);
+}
+
+static const CFArrayCallBacks _kBlockArrayCallbacks = {
+  .version = 0,
+  .retain = BlockRetainCallback,
+  .release = BlockReleaseCallback,
+  .copyDescription = NULL,
+  .equal = NULL
+};
+
 static void
 CFRunLoopFinalize (CFTypeRef cf)
 {
@@ -263,6 +284,7 @@
       new->observers = CFSetCreateMutable (alloc, 0, &kCFTypeSetCallBacks);
       new->sources0 = CFSetCreateMutable (alloc, 0, &kCFTypeSetCallBacks);
       new->sources1 = CFSetCreateMutable (alloc, 0, &kCFTypeSetCallBacks);
+      new->blocks = CFArrayCreateMutable (alloc, 0, &_kBlockArrayCallbacks);
     }
   
   return new;
@@ -275,6 +297,7 @@
   CFRelease (ctxt->observers);
   CFRelease (ctxt->sources0);
   CFRelease (ctxt->sources1);
+  CFRelease (ctxt->blocks);
 }
 
 static void
@@ -396,15 +419,17 @@
 }
 
 static void
-CFRunLoopNotifyObservers (GSRunLoopContextRef context, CFRunLoopActivity 
activity)
+CFRunLoopNotifyObservers (CFRunLoopRef rl, GSRunLoopContextRef context, 
CFRunLoopActivity activity)
 {
   CFRunLoopObserverRef *observers;
   CFIndex i, count;
 
+  GSMutexLock (&rl->_lock);
   count = CFSetGetCount(context->observers);
   observers = (CFRunLoopObserverRef*) CFAllocatorAllocate(NULL,
                                    sizeof(CFRunLoopObserverRef)*count, 0);
   CFSetGetValues(context->observers, (const void**) observers);
+  GSMutexUnlock (&rl->_lock);
 
   for (i = 0; i < count; i++)
     CFRetain(observers[i]);
@@ -428,21 +453,23 @@
 }
 
 static Boolean
-CFRunLoopProcessTimers (CFAbsoluteTime now, GSRunLoopContextRef context)
+CFRunLoopProcessTimers (CFRunLoopRef rl, 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.
+  CFRunLoopNotifyObservers(rl, context, kCFRunLoopBeforeTimers);
+
+  GSMutexLock (&rl->_lock);
+  // Make a copy of timers so that we don't hold the mutex when using the 
callback
+  // and cause a deadlock.
   count = CFArrayGetCount(context->timers);
   timers = (CFRunLoopTimerRef*) CFAllocatorAllocate(NULL,
                                 sizeof(CFRunLoopTimerRef)*count, 0);
 
   CFArrayGetValues(context->timers, CFRangeMake(0, count), (const void**) 
timers);
+  GSMutexUnlock (&rl->_lock);
 
   for (i = 0; i < count; i++)
     CFRetain(timers[i]);
@@ -474,20 +501,22 @@
 }
 
 static Boolean
-CFRunLoopProcessSourcesVersion0 (CFAbsoluteTime now, GSRunLoopContextRef 
context)
+CFRunLoopProcessSourcesVersion0 (CFRunLoopRef rl, CFAbsoluteTime now, 
GSRunLoopContextRef context)
 {
   CFIndex i, count;
   CFRunLoopSourceRef *sources;
   Boolean hadSource = false;
 
   // Notify observers with kCFRunLoopBeforeSources activity.
-  CFRunLoopNotifyObservers(context, kCFRunLoopBeforeSources);
-
+  CFRunLoopNotifyObservers(rl, context, kCFRunLoopBeforeSources);
+
+  GSMutexLock (&rl->_lock);
   count = CFSetGetCount(context->sources0);
   sources = (CFRunLoopSourceRef*) CFAllocatorAllocate(NULL,
                                   sizeof(CFRunLoopSourceRef)*count, 0);
 
   CFSetGetValues(context->sources0, (const void**) sources);
+  GSMutexUnlock (&rl->_lock);
 
   for (i = 0; i < count; i++)
     CFRetain(sources[i]);
@@ -507,7 +536,65 @@
     }
 
   CFAllocatorDeallocate(NULL, (void*) sources);
+
   return hadSource;
+}
+
+static void
+CFRunLoopPerformBlocks (GSRunLoopContextRef context)
+{
+  CFIndex i, count;
+
+  count = CFArrayGetCount(context->blocks);
+
+  for (i = 0; i < count; i++)
+    {
+      PerformBlockType block = (PerformBlockType)
+                               CFArrayGetValueAtIndex(context->blocks, i);
+      CALL_BLOCK_NO_ARGS(block);
+    }
+
+  CFArrayRemoveAllValues(context->blocks);
+}
+
+static void
+CFRunLoopHasAnyValidSources_SourceApplier(const void *value, void *context)
+{
+  CFRunLoopSourceRef source = (CFRunLoopSourceRef) value;
+  Boolean* hasSource = (Boolean*) context;
+  
+  if (source->_isValid)
+    *hasSource = true;
+}
+
+static void
+CFRunLoopHasAnyValidSources_TimerApplier(const void *value, void *context)
+{
+  CFRunLoopTimerRef timer = (CFRunLoopTimerRef) value;
+  Boolean* hasSource = (Boolean*) context;
+  
+  if (timer->_isValid)
+    *hasSource = true;
+}
+
+static Boolean
+CFRunLoopHasAnyValidSources (CFRunLoopRef rl, GSRunLoopContextRef context)
+{
+  Boolean hasSource = false;
+  
+  GSMutexLock (&rl->_lock);
+  CFSetApplyFunction(context->sources0, 
CFRunLoopHasAnyValidSources_SourceApplier,
+                       &hasSource);
+  
+  if (!hasSource)
+    {
+      CFArrayApplyFunction(context->timers, CFRangeMake(0, 
CFArrayGetCount(context->timers)),
+                           CFRunLoopHasAnyValidSources_TimerApplier,
+                           &hasSource);
+    }
+  GSMutexUnlock (&rl->_lock);
+  
+  return hasSource;
 }
 
 SInt32
@@ -564,11 +651,10 @@
 #endif
 
   // Notify observers with kCFRunLoopEntry activity.
-  CFRunLoopNotifyObservers(context, kCFRunLoopEntry);
-
-  GSMutexLock (&rl->_lock);
-  hadSource |= CFRunLoopProcessTimers(timeStart, context);
-  hadSource |= CFRunLoopProcessSourcesVersion0(timeStart, context);
+  CFRunLoopNotifyObservers(rl, context, kCFRunLoopEntry);
+
+  hadSource |= CFRunLoopProcessTimers(rl, timeStart, context);
+  hadSource |= CFRunLoopProcessSourcesVersion0(rl, timeStart, context);
   GSMutexUnlock (&rl->_lock);
 
   if (returnAfterSourceHandled && hadSource)
@@ -584,12 +670,25 @@
 
       hadSource = false;
 
-      if (seconds == 0)
-        timeout = 0; // only one pass
-      else if (seconds >= DISTANT_FUTURE)
-        timeout = -1;
+      if (!returnAfterSourceHandled)
+        {
+          if (seconds == 0)
+            timeout = 0; // only one pass
+          else if (seconds >= DISTANT_FUTURE)
+            timeout = -1;
+          else
+            timeout = (int) ((seconds - (timeNow - timeStart)) * 1000);
+        }
       else
-        timeout = (int) (seconds - (timeNow - timeStart) * 1000);
+        {
+          timeout = -1;
+        }
+        
+      if (!CFRunLoopHasAnyValidSources(rl, context))
+        {
+          exitReason = kCFRunLoopRunFinished;
+          break;
+        }
 
       if (timeout != 0)
         {
@@ -600,6 +699,8 @@
               int delay = (int) ( (nextTimer - timeNow)*1000 );
               if (timeout == -1 || delay < timeout)
                 timeout = delay;
+              if (timeout < 0)
+                timeout = 0;
             }
         }
 
@@ -609,16 +710,20 @@
           rl->_stop = false;
           break;
         }
+
+      GSMutexLock (&rl->_lock);
+      CFRunLoopPerformBlocks(context);
+      GSMutexUnlock (&rl->_lock);
         
       // Notify observers with kCFRunLoopBeforeWaiting activity.
-      CFRunLoopNotifyObservers(context, kCFRunLoopBeforeWaiting);
+      CFRunLoopNotifyObservers(rl, context, kCFRunLoopBeforeWaiting);
       rl->_isWaiting = true;
 
       sourcesFired = poll(pfd, numSources, timeout);
 
       rl->_isWaiting = false;
       // Notify observers with kCFRunLoopAfterWaiting activity.
-      CFRunLoopNotifyObservers(context, kCFRunLoopAfterWaiting);
+      CFRunLoopNotifyObservers(rl, context, kCFRunLoopAfterWaiting);
 
       if (sourcesFired < 0) // error
         {
@@ -644,10 +749,8 @@
             }
 #endif
 
-          GSMutexLock (&rl->_lock);
-          hadSource |= CFRunLoopProcessTimers(timeNow, context);
-          hadSource |= CFRunLoopProcessSourcesVersion0(timeNow, context);
-          GSMutexUnlock (&rl->_lock);
+          hadSource |= CFRunLoopProcessTimers(rl, timeNow, context);
+          hadSource |= CFRunLoopProcessSourcesVersion0(rl, timeNow, context);
         }
 
       if (returnAfterSourceHandled && hadSource)
@@ -665,7 +768,7 @@
     }
 
   // Notify observers with kCFRunLoopExit activity.
-  CFRunLoopNotifyObservers(context, kCFRunLoopExit);
+  CFRunLoopNotifyObservers(rl, context, kCFRunLoopExit);
   rl->_currentMode = NULL;
 
   return exitReason;
@@ -753,10 +856,39 @@
     return NULL;
 }
 
+static void
+CFRunLoopPerformBlock_nolock (CFRunLoopRef rl, CFTypeRef mode,
+                              PerformBlockType block)
+{
+  if (CFGetTypeID(mode) == CFStringGetTypeID())
+    {
+      GSRunLoopContextRef ctxt;
+
+      ctxt = GSRunLoopContextGet (rl, mode);
+      CFArrayAppendValue(ctxt->blocks, block);
+    }
+  else if (CFGetTypeID(mode) == CFArrayGetTypeID())
+    {
+      CFIndex i, count;
+      CFArrayRef array = (CFArrayRef) mode;
+      
+      count = CFArrayGetCount(array);
+
+      for (i = 0; i < count; i++)
+        {
+          CFTypeRef m = CFArrayGetValueAtIndex(array, i);
+          
+          CFRunLoopPerformBlock_nolock(rl, m, block);
+        }
+    }
+}
+
 void
 CFRunLoopPerformBlock (CFRunLoopRef rl, CFTypeRef mode, PerformBlockType block)
 {
-  return;
+  GSMutexLock (&rl->_lock);
+  CFRunLoopPerformBlock_nolock(rl, mode, block);
+  GSMutexUnlock (&rl->_lock);
 }
 
 
@@ -1154,6 +1286,7 @@
   if (new)
     {
       GSMutexInitialize (&(new->_lock));
+      new->_isValid = true;
       new->_order = order;
       if (context)
         {
@@ -1190,7 +1323,7 @@
 void
 CFRunLoopSourceInvalidate (CFRunLoopSourceRef source)
 {
-  return;
+  source->_isValid = false;
 }
 
 Boolean
@@ -1202,7 +1335,8 @@
 void
 CFRunLoopSourceSignal (CFRunLoopSourceRef source)
 {
-  return;
+  source->_isSignaled = true;
+  CFRunLoopWakeUp(source->_runloop);
 }
 
 
@@ -1320,6 +1454,7 @@
   if (new)
     {
       GSMutexInitialize (&(new->_lock));
+      new->_isValid = true;
       new->_nextFireDate = fireDate;
       new->_interval = interval;
       /* 'flags' is ignored */

Modified: libs/corebase/trunk/Tests/CFRunLoop/source.m
URL: 
http://svn.gna.org/viewcvs/gnustep/libs/corebase/trunk/Tests/CFRunLoop/source.m?rev=37803&r1=37802&r2=37803&view=diff
==============================================================================
--- libs/corebase/trunk/Tests/CFRunLoop/source.m        (original)
+++ libs/corebase/trunk/Tests/CFRunLoop/source.m        Fri Apr 18 23:06:15 2014
@@ -1,13 +1,19 @@
 #include <CoreFoundation/CFRunLoop.h>
 
 #include "../CFTesting.h"
+#include <pthread.h>
+#include <unistd.h>
+
+CFRunLoopSourceRef rls1 = NULL;
+CFRunLoopSourceRef rls2 = NULL;
+pthread_t thread2 = 0;
 
 void perform1 (void *info)
 {
   SInt32 ret;
   CFIndex *i = (CFIndex*)info;
-  ret = CFRunLoopRunInMode (CFSTR("another_mode"), 0.0, true);
-  PASS_CF(ret == kCFRunLoopRunFinished, "Run loop run in 'another_mode' 
returned"
+  ret = CFRunLoopRunInMode (CFSTR("another_mode"), 3.0, false);
+  PASS_CF(ret == kCFRunLoopRunTimedOut, "Run loop run in 'another_mode' 
returned"
        " '%d'", ret);
   (*i)++;
 }
@@ -18,13 +24,34 @@
   (*i)++;
 }
 
+void* delay_signal(void* arg)
+{
+       //CFRunLoopSourceRef src = (CFRunLoopSourceRef) arg;
+       int i;
+       
+       for (i = 0; i < 2; i++)
+       {
+               sleep(1);
+       
+               printf("Signalling!\n");
+               CFRunLoopSourceSignal(rls1);
+               CFRunLoopSourceSignal(rls2);
+       }
+       
+       return NULL;
+}
 
+void schedule2 (void* info, CFRunLoopRef rl, CFStringRef mode)
+{
+       if (!thread2)
+       {
+               pthread_create(&thread2, NULL, delay_signal, rls2);
+       }
+}
 
 int main (void)
 {
   CFRunLoopRef rl;
-  CFRunLoopSourceRef rls1;
-  CFRunLoopSourceRef rls2;
   CFIndex i1 = 0;
   CFIndex i2 = 0;
   CFRunLoopSourceContext c1 = { 0 };
@@ -35,8 +62,10 @@
   PASS_CF(rl != NULL, "Got main run loop.");
   
   c1.info = &i1;
+  // c1.schedule = schedule1;
   c1.perform = perform1;
   c2.info = &i2;
+  c2.schedule = schedule2;
   c2.perform = perform2;
   rls1 = CFRunLoopSourceCreate (NULL, 0, &c1);
   PASS_CF(rls1 != NULL, "First run loop source create.");
@@ -55,8 +84,11 @@
   
   CFRunLoopRemoveSource (rl, rls2, CFSTR("another_mode"));
   CFRunLoopSourceInvalidate (rls2);
+  CFRunLoopSourceInvalidate (rls1);
   
   ret = CFRunLoopRunInMode (kCFRunLoopDefaultMode, 0.0, true);
+  PASS_CF(ret == kCFRunLoopRunFinished, "Run loop handled sources.  Exit"
+          " code '%d'.", ret);
   
   CFRelease (rls1);
   CFRelease (rls2);


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

Reply via email to