// Just reads the bits, for those cases where we don't want to go through any callback checking
#define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
-static void _CFStreamSignalEventSynch(void* info);
__private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream);
static Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode);
static void _wakeUpRunLoop(struct _CFStream *stream);
}
else {
- CFArrayRef key;
+ CFArrayRef runLoopAndSourceKey;
CFMutableArrayRef list;
CFIndex c, i;
__CFSpinLock(&sSourceLock);
- key = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
- list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, key);
+ runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
+ list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
c = CFArrayGetCount(list);
i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, c), stream);
CFAssert(CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, CFArrayGetCount(list)), stream) == kCFNotFound, __kCFLogAssertion, "CFStreamClose: stream found twice in its shared source's list");
if (!c) {
- CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(key, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(key, 1));
+ CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
CFRunLoopSourceInvalidate(stream->client->rlSource);
- CFDictionaryRemoveValue(sSharedSources, key);
+ CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
}
CFDictionaryRemoveValue(sSharedSources, stream);
}
else {
- CFArrayRef key;
+ CFArrayRef runLoopAndSourceKey;
CFMutableArrayRef list;
CFIndex c, i;
__CFSpinLock(&sSourceLock);
- key = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
- list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, key);
+ runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
+ list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
c = CFArrayGetCount(list);
i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, c), stream);
}
if (!c) {
- CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(key, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(key, 1));
+ CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
CFRunLoopSourceInvalidate(stream->client->rlSource);
- CFDictionaryRemoveValue(sSharedSources, key);
+ CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
}
CFDictionaryRemoveValue(sSharedSources, stream);
return (CFWriteStreamRef)newStream;
}
-static void _CFStreamSignalEventSynch(void* info) {
+static void _signalEventSync(struct _CFStream* stream, CFOptionFlags whatToSignal)
+{
+ CFOptionFlags eventMask;
- struct _CFStream *stream = NULL;
- CFOptionFlags eventMask, whatToSignal = 0;
+ __CFBitSet(stream->flags, CALLING_CLIENT);
+
+ for (eventMask = 1; eventMask <= whatToSignal; eventMask = eventMask << 1) {
+ if ((eventMask & whatToSignal) && (stream->client->when & eventMask)) {
+ stream->client->cb(stream, eventMask, stream->client->cbContext.info);
+
+ /* What happens if the callback sets the client to NULL? We're in a loop here... Hmm. */
+ /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
+ }
+ }
- if (CFGetTypeID((CFTypeRef)info) != CFArrayGetTypeID()) {
- stream = (struct _CFStream*)info;
- whatToSignal = stream->client->whatToSignal;
+ __CFBitClear(stream->flags, CALLING_CLIENT);
+}
+
+static void _cfstream_solo_signalEventSync(void* info)
+{
+ CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
+
+ if (typeID != CFReadStreamGetTypeID() && typeID != CFWriteStreamGetTypeID()) {
+ CFLog(__kCFLogAssertion, CFSTR("Expected an read or write stream for %p"), info);
+#if defined(DEBUG)
+ abort();
+#endif
+ } else {
+ struct _CFStream* stream = (struct _CFStream*) info;
+ CFOptionFlags whatToSignal = stream->client->whatToSignal;
stream->client->whatToSignal = 0;
+
+ /* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
+ CFRetain(stream);
+ _signalEventSync(stream, whatToSignal);
+ CFRelease(stream);
}
- else {
+}
+
+static void _cfstream_shared_signalEventSync(void* info)
+{
+ CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
+ if (typeID != CFArrayGetTypeID()) {
+ CFLog(__kCFLogAssertion, CFSTR("Expected an array for %p"), info);
+#if defined(DEBUG)
+ abort();
+#endif
+ } else {
CFMutableArrayRef list = (CFMutableArrayRef)info;
CFIndex c, i;
+ CFOptionFlags whatToSignal = 0;
+ struct _CFStream* stream = NULL;
__CFSpinLock(&sSourceLock);
+ /* Looks like, we grab the first stream that wants an event... */
+ /* Note that I grab an extra retain when I pull out the stream here... */
c = CFArrayGetCount(list);
for (i = 0; i < c; i++) {
struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
+
if (s->client->whatToSignal) {
stream = s;
+ CFRetain(stream);
whatToSignal = stream->client->whatToSignal;
s->client->whatToSignal = 0;
break;
}
}
- while (i < c) {
+ /* And then we also signal any other streams in this array so that we get them next go? */
+ for (; i < c; i++) {
struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
if (s->client->whatToSignal) {
CFRunLoopSourceSignal(s->client->rlSource);
break;
}
- i++;
}
__CFSpinUnlock(&sSourceLock);
- }
- if (!stream)
- return;
+ /* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
+ if (stream) {
+ _signalEventSync(stream, whatToSignal);
- CFRetain(stream); // In case the client releases the stream while we're still in the for loop....
-
- __CFBitSet(stream->flags, CALLING_CLIENT);
-
- for (eventMask = 1; eventMask <= whatToSignal; eventMask = eventMask << 1) {
- if ((eventMask & whatToSignal) && (stream->client->when & eventMask)) {
- stream->client->cb(stream, eventMask, stream->client->cbContext.info);
+ /* Lose our extra retain */
+ CFRelease(stream);
}
}
-
- __CFBitClear(stream->flags, CALLING_CLIENT);
-
- CFRelease(stream);
}
// Largely cribbed from CFSocket.c; find a run loop where our source is scheduled and wake it up. We skip the runloop cycling, so we
if (signalNow) {
// Can call out safely right now
- _CFStreamSignalEventSynch(stream);
+ _cfstream_solo_signalEventSync(stream);
} else {
// Schedule for later delivery
CFRunLoopSourceSignal(stream->client->rlSource);
}
if (!stream->client->rlSource) {
+ /* No source, so we join the shared source group */
+ CFTypeRef a[] = { runLoop, runLoopMode };
- CFArrayRef key;
- CFMutableArrayRef list;
- CFTypeRef a[2];
-
- a[0] = runLoop;
- a[1] = runLoopMode;
-
- key = CFArrayCreate(kCFAllocatorSystemDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks);
+ CFArrayRef runLoopAndSourceKey = CFArrayCreate(kCFAllocatorSystemDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks);
__CFSpinLock(&sSourceLock);
if (!sSharedSources)
sSharedSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, key);
- if (list) {
- stream->client->rlSource = (CFRunLoopSourceRef)CFRetain(((struct _CFStream*)CFArrayGetValueAtIndex(list, 0))->client->rlSource);
- CFRetain(list);
+ CFMutableArrayRef listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
+ if (listOfStreamsSharingASource) {
+ stream->client->rlSource = (CFRunLoopSourceRef)CFRetain(((struct _CFStream*)CFArrayGetValueAtIndex(listOfStreamsSharingASource, 0))->client->rlSource);
+ CFRetain(listOfStreamsSharingASource);
}
else {
CFRunLoopSourceContext ctxt = {
0,
NULL,
- NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
- NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
+ CFRetain,
+ CFRelease,
(CFStringRef(*)(const void *))CFCopyDescription,
NULL,
NULL,
NULL,
NULL,
- (void(*)(void *))_CFStreamSignalEventSynch
+ (void(*)(void *))_cfstream_shared_signalEventSync
};
- list = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
- CFDictionaryAddValue(sSharedSources, key, list);
+ listOfStreamsSharingASource = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
+ CFDictionaryAddValue(sSharedSources, runLoopAndSourceKey, listOfStreamsSharingASource);
- ctxt.info = list;
+ ctxt.info = listOfStreamsSharingASource;
- stream->client->rlSource = CFRunLoopSourceCreate(CFGetAllocator(stream), 0, &ctxt);
- stream->client->whatToSignal = 0;
+ stream->client->rlSource = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &ctxt);
CFRunLoopAddSource(runLoop, stream->client->rlSource, runLoopMode);
}
- CFArrayAppendValue(list, stream);
- CFDictionaryAddValue(sSharedSources, stream, key);
+ CFArrayAppendValue(listOfStreamsSharingASource, stream);
+ CFDictionaryAddValue(sSharedSources, stream, runLoopAndSourceKey);
- CFRelease(key);
- CFRelease(list);
+ CFRelease(runLoopAndSourceKey);
+ CFRelease(listOfStreamsSharingASource);
__CFBitSet(stream->flags, SHARED_SOURCE);
__CFSpinUnlock(&sSourceLock);
}
else if (__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
+ /* We were sharing, but now we'll get our own source */
- CFArrayRef key;
- CFMutableArrayRef list;
+ CFArrayRef runLoopAndSourceKey;
+ CFMutableArrayRef listOfStreamsSharingASource;
CFIndex c, i;
CFAllocatorRef alloc = CFGetAllocator(stream);
NULL,
NULL,
NULL,
- (void(*)(void *))_CFStreamSignalEventSynch
+ (void(*)(void *))_cfstream_solo_signalEventSync
};
__CFSpinLock(&sSourceLock);
- key = (CFArrayRef)CFRetain((CFTypeRef)CFDictionaryGetValue(sSharedSources, stream));
- list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, key);
+ runLoopAndSourceKey = (CFArrayRef)CFRetain((CFTypeRef)CFDictionaryGetValue(sSharedSources, stream));
+ listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
- c = CFArrayGetCount(list);
- i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, c), stream);
+ c = CFArrayGetCount(listOfStreamsSharingASource);
+ i = CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource, CFRangeMake(0, c), stream);
if (i != kCFNotFound) {
- CFArrayRemoveValueAtIndex(list, i);
+ CFArrayRemoveValueAtIndex(listOfStreamsSharingASource, i);
c--;
}
if (!c) {
- CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(key, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(key, 1));
+ CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
CFRunLoopSourceInvalidate(stream->client->rlSource);
- CFDictionaryRemoveValue(sSharedSources, key);
+ CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
}
CFDictionaryRemoveValue(sSharedSources, stream);
stream->client->rlSource = CFRunLoopSourceCreate(alloc, 0, &ctxt);
- CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(key, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(key, 1));
+ CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
- CFRelease(key);
+ CFRelease(runLoopAndSourceKey);
CFRunLoopAddSource(runLoop, stream->client->rlSource, runLoopMode);
} else {
+ /* We're not sharing, so just add the source to the rl & mode */
CFRunLoopAddSource(runLoop, stream->client->rlSource, runLoopMode);
}
cb->schedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
__CFBitClear(stream->flags, CALLING_CLIENT);
}
+
+ /*
+ * If we've got events pending, we need to wake up and signal
+ */
+ if (stream->client->whatToSignal != 0) {
+ CFRunLoopSourceSignal(stream->client->rlSource);
+ _wakeUpRunLoop(stream);
+ }
}
CF_EXPORT void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
CFRunLoopRemoveSource(runLoop, stream->client->rlSource, runLoopMode);
} else {
- CFArrayRef key;
+ CFArrayRef runLoopAndSourceKey;
CFMutableArrayRef list;
CFIndex c, i;
__CFSpinLock(&sSourceLock);
- key = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
- list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, key);
+ runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
+ list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
c = CFArrayGetCount(list);
i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, c), stream);
if (!c) {
CFRunLoopRemoveSource(runLoop, stream->client->rlSource, runLoopMode);
CFRunLoopSourceInvalidate(stream->client->rlSource);
- CFDictionaryRemoveValue(sSharedSources, key);
+ CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
}
CFDictionaryRemoveValue(sSharedSources, stream);