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