1/*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*	CFStream.c
25	Copyright (c) 2000-2013, Apple Inc. All rights reserved.
26	Responsibility: John Iarocci
27*/
28
29#include <CoreFoundation/CFRuntime.h>
30#include <CoreFoundation/CFNumber.h>
31#include <string.h>
32#include "CFStreamInternal.h"
33#include "CFInternal.h"
34#include <stdio.h>
35
36#if defined(DEBUG)
37#include <assert.h>
38#endif
39
40struct _CFStream {
41    CFRuntimeBase _cfBase;
42    CFOptionFlags flags;
43    CFErrorRef error; // if callBacks->version < 2, this is actually a pointer to a CFStreamError
44    struct _CFStreamClient *client;
45    /* NOTE: CFNetwork is still using _CFStreamGetInfoPointer, and so this slot needs to stay in this position (as the fifth field in the structure) */
46    /* NOTE: This can be taken out once CFNetwork rebuilds */
47    /* NOTE: <rdar://problem/13678879> Remove comment once CFNetwork has been rebuilt */
48    void *info;
49    const struct _CFStreamCallBacks *callBacks;  // This will not exist (will not be allocated) if the callbacks are from our known, "blessed" set.
50
51    CFSpinLock_t streamLock;
52    CFArrayRef previousRunloopsAndModes;
53    dispatch_queue_t queue;
54};
55
56
57enum {
58	MIN_STATUS_CODE_BIT	= 0,
59        // ..status bits...
60	MAX_STATUS_CODE_BIT	= 4,
61
62	CONSTANT_CALLBACKS	= 5,
63	CALLING_CLIENT		= 6,	// MUST remain 6 since it's value is used elsewhere.
64
65    HAVE_CLOSED			= 7,
66
67    // Values above used to be defined and others may rely on their values
68
69    // Values below should not matter if they are re-ordered or shift
70
71    SHARED_SOURCE
72};
73
74
75/* CALLING_CLIENT really determines whether stream events will be sent to the client immediately, or posted for the next time through the runloop.  Since the client may not be prepared for re-entrancy, we must always set/clear this bit around public entry points. -- REW, 9/5/2001
76    Also, CALLING_CLIENT is now used from CFFilteredStream.c (which has a copy of the #define above).  Really gross.  We should find a way to avoid that.... -- REW, 3/27/2002  */
77// Used in CFNetwork too
78
79/* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
80   RunLoop+RunLoopMode pair that it's scheduled in.  If the stream is scheduled in more than
81   one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
82*/
83static CFSpinLock_t sSourceLock = CFSpinLockInit;
84static CFMutableDictionaryRef sSharedSources = NULL;
85
86static CFTypeID __kCFReadStreamTypeID = _kCFRuntimeNotATypeID;
87static CFTypeID __kCFWriteStreamTypeID = _kCFRuntimeNotATypeID;
88
89// Just reads the bits, for those cases where we don't want to go through any callback checking
90#define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
91
92CF_PRIVATE CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream);
93static Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode);
94static void _wakeUpRunLoop(struct _CFStream *stream);
95
96CF_INLINE void checkRLMArray(CFArrayRef arr)
97{
98#if defined(DEBUG)
99    assert(arr == NULL || (CFArrayGetCount(arr) % 2) == 0);
100#endif
101}
102
103CF_INLINE void _CFStreamLock(struct _CFStream* stream) {
104	__CFSpinLock(&stream->streamLock);
105}
106
107CF_INLINE void _CFStreamUnlock(struct _CFStream* stream) {
108	__CFSpinUnlock(&stream->streamLock);
109}
110
111CF_INLINE CFRunLoopSourceRef _CFStreamCopySource(struct _CFStream* stream) {
112    CFRunLoopSourceRef source = NULL;
113
114    if (stream) {
115        _CFStreamLock(stream);
116
117        if (stream->client)
118            source = stream->client->rlSource;
119
120        if (source)
121            CFRetain(source);
122
123        _CFStreamUnlock(stream);
124    }
125
126    return source;
127}
128
129CF_INLINE void _CFStreamSetSource(struct _CFStream* stream, CFRunLoopSourceRef source, Boolean invalidateOldSource) {
130	CFRunLoopSourceRef oldSource = NULL;
131
132	if (stream) {
133		_CFStreamLock(stream);
134		if (stream->client) {
135			oldSource = stream->client->rlSource;
136			if (oldSource != NULL)
137				CFRetain(oldSource);
138
139			stream->client->rlSource = source;
140			if (source != NULL)
141				CFRetain(source);
142		}
143		_CFStreamUnlock(stream);
144	}
145
146	if (oldSource) {
147		// Lose our extra retain
148		CFRelease(oldSource);
149
150		if (invalidateOldSource)
151			CFRunLoopSourceInvalidate(oldSource);
152
153		// And lose the one that held it in our stream as well
154		CFRelease(oldSource);
155	}
156}
157
158CF_INLINE const struct _CFStreamCallBacks *_CFStreamGetCallBackPtr(struct _CFStream *stream) {
159    return stream->callBacks;
160}
161
162CF_INLINE void _CFStreamSetStatusCode(struct _CFStream *stream, CFStreamStatus newStatus) {
163    CFStreamStatus status = __CFStreamGetStatus(stream);
164    if (((status != kCFStreamStatusClosed) && (status != kCFStreamStatusError)) ||
165        ((status == kCFStreamStatusClosed) && (newStatus == kCFStreamStatusError)))
166    {
167        __CFBitfieldSetValue(stream->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT, newStatus);
168    }
169}
170
171CF_INLINE void _CFStreamScheduleEvent(struct _CFStream *stream, CFStreamEventType event) {
172    if (stream->client && (stream->client->when & event)) {
173		CFRunLoopSourceRef source = _CFStreamCopySource(stream);
174        if (source) {
175            stream->client->whatToSignal |= event;
176
177			CFRunLoopSourceSignal(source);
178			CFRelease(source);
179	        _wakeUpRunLoop(stream);
180	    }
181	}
182}
183
184CF_INLINE void _CFStreamSetStreamError(struct _CFStream *stream, CFStreamError *err) {
185    if (!stream->error) {
186        stream->error = (CFErrorRef)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(CFStreamError), 0);
187    }
188    memmove(stream->error, err, sizeof(CFStreamError));
189}
190
191static CFStringRef __CFStreamCopyDescription(CFTypeRef cf) {
192    struct _CFStream *stream = (struct _CFStream *)cf;
193    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
194    CFStringRef contextDescription;
195    CFStringRef desc;
196    if (cb->copyDescription) {
197        if (cb->version == 0) {
198            contextDescription = ((CFStringRef(*)(void *))cb->copyDescription)(_CFStreamGetInfoPointer(stream));
199        } else {
200            contextDescription = cb->copyDescription(stream, _CFStreamGetInfoPointer(stream));
201        }
202    } else {
203        contextDescription = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream));
204    }
205    if (CFGetTypeID(cf) == __kCFReadStreamTypeID) {
206        desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("<CFReadStream %p>{%@}"), stream, contextDescription);
207    } else {
208        desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("<CFWriteStream %p>{%@}"), stream, contextDescription);
209    }
210    CFRelease(contextDescription);
211    return desc;
212}
213
214static void _CFStreamDetachSource(struct _CFStream* stream) {
215	if (stream && stream->client && stream->client->rlSource) {
216        if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
217			_CFStreamSetSource(stream, NULL, TRUE);
218        }
219        else {
220
221            CFArrayRef runLoopAndSourceKey;
222            CFMutableArrayRef list;
223			CFIndex count;
224			CFIndex i;
225
226            __CFSpinLock(&sSourceLock);
227
228            runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
229            list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
230
231			count = CFArrayGetCount(list);
232			i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, count), stream);
233            if (i != kCFNotFound) {
234                CFArrayRemoveValueAtIndex(list, i);
235				count--;
236            }
237
238            CFAssert(CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, CFArrayGetCount(list)), stream) == kCFNotFound, __kCFLogAssertion, "CFStreamClose: stream found twice in its shared source's list");
239
240			if (count == 0) {
241				CFRunLoopSourceRef source = _CFStreamCopySource(stream);
242				if (source) {
243					CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), source, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
244					CFRelease(source);
245				}
246                CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
247            }
248
249            CFDictionaryRemoveValue(sSharedSources, stream);
250
251			_CFStreamSetSource(stream, NULL, count == 0);
252
253            __CFBitClear(stream->flags, SHARED_SOURCE);
254
255            __CFSpinUnlock(&sSourceLock);
256        }
257    }
258}
259
260CF_PRIVATE void _CFStreamClose(struct _CFStream *stream) {
261    CFStreamStatus status = _CFStreamGetStatus(stream);
262    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
263    if (status == kCFStreamStatusNotOpen || status == kCFStreamStatusClosed || (status == kCFStreamStatusError && __CFBitIsSet(stream->flags, HAVE_CLOSED))) {
264        // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
265        return;
266    }
267    if (! __CFBitIsSet(stream->flags, HAVE_CLOSED)) {
268        __CFBitSet(stream->flags, HAVE_CLOSED);
269        __CFBitSet(stream->flags, CALLING_CLIENT);
270        if (cb->close) {
271            cb->close(stream, _CFStreamGetInfoPointer(stream));
272        }
273        if (stream->client) {
274            _CFStreamDetachSource(stream);
275        }
276        _CFStreamSetStatusCode(stream, kCFStreamStatusClosed);
277        __CFBitClear(stream->flags, CALLING_CLIENT);
278    }
279}
280
281//static int numStreamInstances = 0;
282
283static void __CFStreamDeallocate(CFTypeRef cf) {
284    struct _CFStream *stream = (struct _CFStream *)cf;
285    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
286    CFAllocatorRef alloc = CFGetAllocator(stream);
287//    numStreamInstances --;
288
289    // Close the stream
290    _CFStreamClose(stream);
291
292    if (stream->client) {
293        CFStreamClientContext *cbContext;
294        cbContext = &(stream->client->cbContext);
295        if (cbContext->info && cbContext->release) {
296            cbContext->release(cbContext->info);
297        }
298
299        if (stream->client->runLoopsAndModes) {
300            CFRelease(stream->client->runLoopsAndModes);
301        }
302
303        CFAllocatorDeallocate(alloc, stream->client);
304        stream->client = NULL; // Just in case finalize, below, calls back in to us
305    }
306    if (cb->finalize) {
307        if (cb->version == 0) {
308            ((void(*)(void *))cb->finalize)(_CFStreamGetInfoPointer(stream));
309        } else {
310            cb->finalize(stream, _CFStreamGetInfoPointer(stream));
311        }
312    }
313    if (stream->error) {
314        if (cb->version < 2) {
315            CFAllocatorDeallocate(alloc, stream->error);
316        } else {
317            CFRelease(stream->error);
318        }
319    }
320    if (!__CFBitIsSet(stream->flags, CONSTANT_CALLBACKS)) {
321        CFAllocatorDeallocate(alloc, (void *)stream->callBacks);
322    }
323    if (stream->previousRunloopsAndModes) {
324        CFRelease(stream->previousRunloopsAndModes);
325        stream->previousRunloopsAndModes = NULL;
326    }
327    if (stream->queue) {
328        dispatch_release(stream->queue);
329        stream->queue = NULL;
330    }
331}
332
333static const CFRuntimeClass __CFReadStreamClass = {
334    0,
335    "CFReadStream",
336    NULL,      // init
337    NULL,      // copy
338    __CFStreamDeallocate,
339    NULL,
340    NULL,
341    NULL,      // copyHumanDesc
342    __CFStreamCopyDescription
343};
344
345static const CFRuntimeClass __CFWriteStreamClass = {
346    0,
347    "CFWriteStream",
348    NULL,      // init
349    NULL,      // copy
350    __CFStreamDeallocate,
351    NULL,
352    NULL,
353    NULL,      // copyHumanDesc
354    __CFStreamCopyDescription
355};
356
357CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle, "kCFStreamPropertySocketNativeHandle")
358CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName, "kCFStreamPropertySocketRemoteHostName")
359CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber, "kCFStreamPropertySocketRemotePortNumber")
360CONST_STRING_DECL(kCFStreamPropertyDataWritten, "kCFStreamPropertyDataWritten")
361CONST_STRING_DECL(kCFStreamPropertyAppendToFile, "kCFStreamPropertyAppendToFile")
362
363CF_PRIVATE void __CFStreamInitialize(void) {
364    __kCFReadStreamTypeID = _CFRuntimeRegisterClass(&__CFReadStreamClass);
365    __kCFWriteStreamTypeID = _CFRuntimeRegisterClass(&__CFWriteStreamClass);
366}
367
368
369CF_EXPORT CFTypeID CFReadStreamGetTypeID(void) {
370    return __kCFReadStreamTypeID;
371}
372
373CF_EXPORT CFTypeID CFWriteStreamGetTypeID(void) {
374    return __kCFWriteStreamTypeID;
375}
376
377static struct _CFStream *_CFStreamCreate(CFAllocatorRef allocator, Boolean isReadStream) {
378    struct _CFStream *newStream = (struct _CFStream *)_CFRuntimeCreateInstance(allocator, isReadStream ? __kCFReadStreamTypeID : __kCFWriteStreamTypeID, sizeof(struct _CFStream) - sizeof(CFRuntimeBase), NULL);
379    if (newStream) {
380//        numStreamInstances ++;
381        newStream->flags = 0;
382        _CFStreamSetStatusCode(newStream, kCFStreamStatusNotOpen);
383        newStream->error = NULL;
384        newStream->client = NULL;
385        newStream->info = NULL;
386        newStream->callBacks = NULL;
387
388        newStream->streamLock = CFSpinLockInit;
389        newStream->previousRunloopsAndModes = NULL;
390        newStream->queue = NULL;
391    }
392    return newStream;
393}
394
395CF_EXPORT void* _CFStreamGetInfoPointer(struct _CFStream* stream) {
396    return stream == NULL? NULL : stream->info;
397}
398
399CF_PRIVATE struct _CFStream *_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc, void *info,  const struct _CFStreamCallBacks *cb, Boolean isReading) {
400    struct _CFStream *newStream;
401    if (cb->version != 1) return NULL;
402    newStream = _CFStreamCreate(alloc, isReading);
403    if (newStream) {
404        __CFBitSet(newStream->flags, CONSTANT_CALLBACKS);
405        newStream->callBacks = cb;
406        if (cb->create) {
407            newStream->info = cb->create(newStream, info);
408        } else {
409            newStream->info = info;
410        }
411    }
412    return newStream;
413}
414
415CF_EXPORT void _CFStreamSetInfoPointer(struct _CFStream *stream, void *info, const struct _CFStreamCallBacks *cb) {
416    if (info != stream->info) {
417        if (stream->callBacks->finalize) {
418            stream->callBacks->finalize(stream, stream->info);
419        }
420        if (cb->create) {
421            stream->info = cb->create(stream, info);
422        } else {
423            stream->info = info;
424        }
425    }
426    stream->callBacks = cb;
427}
428
429
430CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadStreamCallBacks *callbacks, void *info) {
431    struct _CFStream *newStream = _CFStreamCreate(alloc, TRUE);
432    struct _CFStreamCallBacks *cb;
433    if (!newStream) return NULL;
434    cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0);
435    if (!cb) {
436        CFRelease(newStream);
437        return NULL;
438    }
439    if (callbacks->version == 0) {
440        CFReadStreamCallBacksV0 *cbV0 = (CFReadStreamCallBacksV0 *)callbacks;
441        CFStreamClientContext *ctxt = (CFStreamClientContext *)info;
442        newStream->info = ctxt->retain ? (void *)ctxt->retain(ctxt->info) : ctxt->info;
443        cb->version = 0;
444        cb->create = (void *(*)(struct _CFStream *, void *))ctxt->retain;
445        cb->finalize = (void(*)(struct _CFStream *, void *))ctxt->release;
446        cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))ctxt->copyDescription;
447        cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open;
448        cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted;
449        cb->read = (CFIndex (*)(CFReadStreamRef, UInt8 *, CFIndex, CFErrorRef *, Boolean *, void *))cbV0->read;
450        cb->getBuffer = (const UInt8 *(*)(CFReadStreamRef, CFIndex, CFIndex *, CFErrorRef *, Boolean *, void *))cbV0->getBuffer;
451        cb->canRead = (Boolean (*)(CFReadStreamRef, CFErrorRef*, void*))cbV0->canRead;
452        cb->write = NULL;
453        cb->canWrite = NULL;
454        cb->close = (void (*)(struct _CFStream *, void *))cbV0->close;
455        cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV0->copyProperty;
456        cb->setProperty = NULL;
457        cb->requestEvents = NULL;
458        cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->schedule;
459        cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->unschedule;
460    } else if (callbacks->version == 1) {
461        CFReadStreamCallBacksV1 *cbV1 = (CFReadStreamCallBacksV1 *)callbacks;
462        newStream->info = cbV1->create ? cbV1->create((CFReadStreamRef)newStream, info) : info;
463        cb->version = 1;
464        cb->create = (void *(*)(struct _CFStream *, void *))cbV1->create;
465        cb->finalize = (void(*)(struct _CFStream *, void *))cbV1->finalize;
466        cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))cbV1->copyDescription;
467        cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV1->open;
468        cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV1->openCompleted;
469        cb->read = (CFIndex (*)(CFReadStreamRef, UInt8 *, CFIndex, CFErrorRef *, Boolean *, void *))cbV1->read;
470        cb->getBuffer = (const UInt8 *(*)(CFReadStreamRef, CFIndex, CFIndex *, CFErrorRef *, Boolean *, void *))cbV1->getBuffer;
471        cb->canRead = (Boolean (*)(CFReadStreamRef, CFErrorRef*, void*))cbV1->canRead;
472        cb->write = NULL;
473        cb->canWrite = NULL;
474        cb->close = (void (*)(struct _CFStream *, void *))cbV1->close;
475        cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV1->copyProperty;
476        cb->setProperty = (Boolean(*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))cbV1->setProperty;
477        cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))cbV1->requestEvents;
478        cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->schedule;
479        cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->unschedule;
480    } else {
481        newStream->info = callbacks->create ? callbacks->create((CFReadStreamRef)newStream, info) : info;
482        cb->version = 2;
483        cb->create = (void *(*)(struct _CFStream *, void *))callbacks->create;
484        cb->finalize = (void(*)(struct _CFStream *, void *))callbacks->finalize;
485        cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))callbacks->copyDescription;
486        cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open;
487        cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted;
488        cb->read = callbacks->read;
489        cb->getBuffer = callbacks->getBuffer;
490        cb->canRead = callbacks->canRead;
491        cb->write = NULL;
492        cb->canWrite = NULL;
493        cb->close = (void (*)(struct _CFStream *, void *))callbacks->close;
494        cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))callbacks->copyProperty;
495        cb->setProperty = (Boolean(*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))callbacks->setProperty;
496        cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))callbacks->requestEvents;
497        cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->schedule;
498        cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->unschedule;
499   }
500
501    newStream->callBacks = cb;
502    return (CFReadStreamRef)newStream;
503}
504
505CF_EXPORT CFWriteStreamRef CFWriteStreamCreate(CFAllocatorRef alloc, const CFWriteStreamCallBacks *callbacks, void *info) {
506    struct _CFStream *newStream = _CFStreamCreate(alloc, FALSE);
507    struct _CFStreamCallBacks *cb;
508    if (!newStream) return NULL;
509    cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0);
510    if (!cb) {
511        CFRelease(newStream);
512        return NULL;
513    }
514    if (callbacks->version == 0) {
515        CFWriteStreamCallBacksV0 *cbV0 = (CFWriteStreamCallBacksV0 *)callbacks;
516        CFStreamClientContext *ctxt = (CFStreamClientContext *)info;
517        newStream->info = ctxt->retain ? (void *)ctxt->retain(ctxt->info) : ctxt->info;
518        cb->version = 0;
519        cb->create = (void *(*)(struct _CFStream *, void *))ctxt->retain;
520        cb->finalize = (void(*)(struct _CFStream *, void *))ctxt->release;
521        cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))ctxt->copyDescription;
522        cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open;
523        cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted;
524        cb->read = NULL;
525        cb->getBuffer = NULL;
526        cb->canRead = NULL;
527        cb->write = (CFIndex(*)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info))cbV0->write;
528        cb->canWrite = (Boolean(*)(CFWriteStreamRef stream, CFErrorRef *error, void *info))cbV0->canWrite;
529        cb->close = (void (*)(struct _CFStream *, void *))cbV0->close;
530        cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV0->copyProperty;
531        cb->setProperty = NULL;
532        cb->requestEvents = NULL;
533        cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->schedule;
534        cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->unschedule;
535    } else if (callbacks->version == 1) {
536        CFWriteStreamCallBacksV1 *cbV1 = (CFWriteStreamCallBacksV1 *)callbacks;
537        cb->version = 1;
538        newStream->info = cbV1->create ? cbV1->create((CFWriteStreamRef)newStream, info) : info;
539        cb->create = (void *(*)(struct _CFStream *, void *))cbV1->create;
540        cb->finalize = (void(*)(struct _CFStream *, void *))cbV1->finalize;
541        cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))cbV1->copyDescription;
542        cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV1->open;
543        cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV1->openCompleted;
544        cb->read = NULL;
545        cb->getBuffer = NULL;
546        cb->canRead = NULL;
547        cb->write = (CFIndex(*)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info))cbV1->write;
548        cb->canWrite = (Boolean(*)(CFWriteStreamRef stream, CFErrorRef *error, void *info))cbV1->canWrite;
549        cb->close = (void (*)(struct _CFStream *, void *))cbV1->close;
550        cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV1->copyProperty;
551        cb->setProperty = (Boolean (*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))cbV1->setProperty;
552        cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))cbV1->requestEvents;
553        cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->schedule;
554        cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->unschedule;
555    } else {
556        cb->version = callbacks->version;
557        newStream->info = callbacks->create ? callbacks->create((CFWriteStreamRef)newStream, info) : info;
558        cb->create = (void *(*)(struct _CFStream *, void *))callbacks->create;
559        cb->finalize = (void(*)(struct _CFStream *, void *))callbacks->finalize;
560        cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))callbacks->copyDescription;
561        cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open;
562        cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted;
563        cb->read = NULL;
564        cb->getBuffer = NULL;
565        cb->canRead = NULL;
566        cb->write = callbacks->write;
567        cb->canWrite = callbacks->canWrite;
568        cb->close = (void (*)(struct _CFStream *, void *))callbacks->close;
569        cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))callbacks->copyProperty;
570        cb->setProperty = (Boolean (*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))callbacks->setProperty;
571        cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))callbacks->requestEvents;
572        cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->schedule;
573        cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->unschedule;
574    }
575    newStream->callBacks = cb;
576    return (CFWriteStreamRef)newStream;
577}
578
579static void _signalEventSync(struct _CFStream* stream, CFOptionFlags whatToSignal)
580{
581    CFOptionFlags eventMask;
582
583    __CFBitSet(stream->flags, CALLING_CLIENT);
584
585    _CFStreamLock(stream);
586
587    struct _CFStreamClient* client = stream->client;
588    if (client == NULL) {
589        _CFStreamUnlock(stream);
590    } else {
591        void* info = NULL;
592        void (*release) (void*) = NULL;
593        void (*cb)(struct _CFStream *, CFStreamEventType, void *) = client == NULL? NULL : client->cb;
594
595        if (stream->client->cbContext.retain == NULL)
596            info = stream->client->cbContext.info;
597        else {
598            info = stream->client->cbContext.retain(stream->client->cbContext.info);
599            release = stream->client->cbContext.release;
600        }
601        _CFStreamUnlock(stream);
602
603        for (eventMask = 1; eventMask <= whatToSignal; eventMask = eventMask << 1) {
604            _CFStreamLock(stream);
605            Boolean shouldSignal = ((eventMask & whatToSignal) && stream->client && (stream->client->when & eventMask));
606            _CFStreamUnlock(stream);
607
608            if (shouldSignal && client) {
609                cb(stream, eventMask, info);
610
611                /* What happens if the callback sets the client to NULL?  We're in a loop here... Hmm. */
612                /* After writing that comment, I see: <rdar://problem/6793636> CFReadStreamSetClient(..., NULL) unsafely releases info pointer immediately */
613                /* Of note, when the stream callbacks are set to to NULL, we're re-initalized so as not to receive more events, so we
614                 * should break pout of this loop */
615            }
616        }
617
618        if (release)
619            (*release) (info);
620    }
621    __CFBitClear(stream->flags, CALLING_CLIENT);
622}
623
624static void _signalEventQueue(dispatch_queue_t q, struct _CFStream* stream, CFOptionFlags whatToSignal)
625{
626    CFRetain(stream);
627    dispatch_async(q, ^{
628        _signalEventSync(stream, whatToSignal);
629        CFRelease(stream);
630    });
631}
632
633static void _cfstream_solo_signalEventSync(void* info)
634{
635    CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
636
637    if (typeID != CFReadStreamGetTypeID() && typeID != CFWriteStreamGetTypeID()) {
638	CFLog(__kCFLogAssertion, CFSTR("Expected a read or write stream for %p"), info);
639#if defined(DEBUG)
640	abort();
641#endif
642    } else {
643	struct _CFStream* stream = (struct _CFStream*) info;
644        _CFStreamLock(stream);
645	CFOptionFlags whatToSignal = stream->client->whatToSignal;
646	stream->client->whatToSignal = 0;
647        dispatch_queue_t queue = stream->queue;
648        if (queue) dispatch_retain(queue);
649        CFRetain(stream);
650        _CFStreamUnlock(stream);
651
652	/* Since the array version holds a retain, we do it here as well, as opposed to taking a second retain in the client callback */
653        if (queue == 0)
654            _signalEventSync(stream, whatToSignal);
655        else {
656            _signalEventQueue(queue, stream, whatToSignal);
657            dispatch_release(queue);
658        }
659	CFRelease(stream);
660    }
661}
662
663static void _cfstream_shared_signalEventSync(void* info)
664{
665    CFTypeID typeID = CFGetTypeID((CFTypeRef) info);
666
667    if (typeID != CFArrayGetTypeID()) {
668	CFLog(__kCFLogAssertion, CFSTR("Expected an array for %p"), info);
669#if defined(DEBUG)
670	abort();
671#endif
672    } else {
673	CFMutableArrayRef list = (CFMutableArrayRef) info;
674	CFIndex c, i;
675	CFOptionFlags whatToSignal = 0;
676        dispatch_queue_t queue = 0;
677	struct _CFStream* stream = NULL;
678
679	__CFSpinLock(&sSourceLock);
680
681	/* Looks like, we grab the first stream that wants an event... */
682	/* Note that I grab an extra retain when I pull out the stream here... */
683	c = CFArrayGetCount(list);
684	for (i = 0; i < c; i++) {
685	    struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
686
687	    if (s->client->whatToSignal) {
688		stream = s;
689		CFRetain(stream);
690		whatToSignal = stream->client->whatToSignal;
691		s->client->whatToSignal = 0;
692                queue = stream->queue;
693                if (queue) dispatch_retain(queue);
694		break;
695	    }
696	}
697
698	/* And then we also signal any other streams in this array so that we get them next go? */
699	for (; i < c;  i++) {
700	    struct _CFStream* s = (struct _CFStream*)CFArrayGetValueAtIndex(list, i);
701	    if (s->client->whatToSignal) {
702                CFRunLoopSourceRef source = _CFStreamCopySource(s);
703                if (source) {
704                    CFRunLoopSourceSignal(source);
705                    CFRelease(source);
706                }
707                break;
708	    }
709	}
710
711	__CFSpinUnlock(&sSourceLock);
712
713	/* We're sitting here now, possibly with a stream that needs to be processed by the common routine */
714	if (stream) {
715            if (queue == 0)
716                _signalEventSync(stream, whatToSignal);
717            else {
718                _signalEventQueue(queue, stream, whatToSignal);
719                dispatch_release(queue);
720            }
721
722	    /* Lose our extra retain */
723	    CFRelease(stream);
724	}
725    }
726}
727
728/* This routine is to be considered unsafe... */
729static CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream)
730{
731    CFArrayRef result = NULL;
732    if (stream && stream->client) {
733        _CFStreamLock(stream);
734        if (stream->previousRunloopsAndModes) {
735            CFRelease(stream->previousRunloopsAndModes);
736            stream->previousRunloopsAndModes = NULL;
737        }
738        if (stream->client->runLoopsAndModes) {
739            stream->previousRunloopsAndModes = CFArrayCreateCopy(CFGetAllocator(stream), stream->client->runLoopsAndModes);
740        }
741        result = stream->previousRunloopsAndModes;
742        checkRLMArray(result);
743        _CFStreamUnlock(stream);
744    }
745    return result;
746}
747
748static CFArrayRef _CFStreamCopyRunLoopsAndModes(struct _CFStream *stream)
749{
750    CFArrayRef result = NULL;
751    if (stream && stream->client) {
752        _CFStreamLock(stream);
753        if (stream->client->runLoopsAndModes) {
754            result = CFArrayCreateCopy(CFGetAllocator(stream), stream->client->runLoopsAndModes);
755        }
756        checkRLMArray(result);
757        _CFStreamUnlock(stream);
758    }
759    return result;
760}
761
762static void _wakeUpRunLoop(struct _CFStream *stream) {
763    CFArrayRef rlArray = _CFStreamCopyRunLoopsAndModes(stream);
764    if (rlArray) {
765        CFIndex cnt = CFArrayGetCount(rlArray);
766        CFRunLoopRef rl = NULL;
767
768        if (cnt == 2) {
769            rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
770        } else if (cnt > 2) {
771            CFIndex idx;
772            rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
773            for (idx = 2; NULL != rl && idx < cnt; idx+=2) {
774                CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx);
775                if (value != rl) rl = NULL;
776            }
777            if (NULL == rl) {	/* more than one different rl, so we must pick one */
778                for (idx = 0; idx < cnt; idx+=2) {
779                    CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx);
780                    CFStringRef currentMode = CFRunLoopCopyCurrentMode(value);
781                    if (NULL != currentMode && CFEqual(currentMode, CFArrayGetValueAtIndex(rlArray, idx+1)) && CFRunLoopIsWaiting(value)) {
782                        CFRelease(currentMode);
783                        rl = value;
784                        break;
785                    }
786                    if (NULL != currentMode) CFRelease(currentMode);
787                }
788                if (NULL == rl) {	/* didn't choose one above, so choose first */
789                    rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0);
790                }
791            }
792        }
793        if (NULL != rl && CFRunLoopIsWaiting(rl))
794            CFRunLoopWakeUp(rl);
795        CFRelease(rlArray);
796    }
797}
798
799CF_PRIVATE void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType event, CFErrorRef error, Boolean synchronousAllowed) {
800    // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
801    CFStreamStatus status = __CFStreamGetStatus(stream);
802
803    // Sanity check the event
804    if (status == kCFStreamStatusNotOpen) {
805        // No events allowed; this is almost certainly a bug in the stream's implementation
806        CFLog(__kCFLogAssertion, CFSTR("Stream %p is sending an event before being opened"), stream);
807        event = 0;
808    } else if (status == kCFStreamStatusClosed || status == kCFStreamStatusError) {
809        // no further events are allowed
810        event = 0;
811    } else if (status == kCFStreamStatusAtEnd) {
812        // Only error events are allowed
813        event &= kCFStreamEventErrorOccurred;
814    } else if (status != kCFStreamStatusOpening) {
815        // cannot send open completed; that happened already
816        event &= ~kCFStreamEventOpenCompleted;
817    }
818
819    // Change status if appropriate
820    if (event & kCFStreamEventOpenCompleted && status == kCFStreamStatusOpening) {
821        _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
822    }
823    if (event & kCFStreamEventEndEncountered && status < kCFStreamStatusAtEnd) {
824        _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
825    }
826    if (event & kCFStreamEventErrorOccurred) {
827        if (_CFStreamGetCallBackPtr(stream)->version < 2) {
828            _CFStreamSetStreamError(stream, (CFStreamError *)error);
829        } else {
830            CFAssert(error, __kCFLogAssertion, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
831            CFRetain(error);
832            if (stream->error) CFRelease(stream->error);
833            stream->error = error;
834        }
835        _CFStreamSetStatusCode(stream, kCFStreamStatusError);
836    }
837
838    // Now signal any pertinent event
839    if (stream->client && (stream->client->when & event) != 0) {
840        CFRunLoopSourceRef source = _CFStreamCopySource(stream);
841
842        if (source) {
843            Boolean signalNow = FALSE;
844
845            stream->client->whatToSignal |= event;
846
847            if (synchronousAllowed && !__CFBitIsSet(stream->flags, CALLING_CLIENT)) {
848
849                CFRunLoopRef rl = CFRunLoopGetCurrent();
850                CFStringRef mode = CFRunLoopCopyCurrentMode(rl);
851
852                if (mode) {
853                    if (CFRunLoopContainsSource(rl, source, mode))
854                        signalNow = TRUE;
855                }
856                if (mode)
857                    CFRelease(mode);
858            }
859
860            if (signalNow) {
861                // Can call out safely right now
862                _cfstream_solo_signalEventSync(stream);
863            } else {
864                // Schedule for later delivery
865                if (source) {
866                    CFRunLoopSourceSignal(source);
867                }
868                _wakeUpRunLoop(stream);
869            }
870
871            CFRelease(source);
872        }
873    }
874}
875
876CF_PRIVATE CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream) {
877  CFStreamStatus status = __CFStreamGetStatus(stream);
878  // Status code just represents the value when last we checked; if we were in the middle of doing work at that time, we need to find out if the work has completed, now.  If we find out about a status change, we need to inform the client as well, so we call _CFStreamSignalEvent.  This will take care of updating our internal status correctly, too.
879  __CFBitSet(stream->flags, CALLING_CLIENT);
880  if (status == kCFStreamStatusOpening) {
881    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
882    if (cb->openCompleted) {
883      Boolean isComplete;
884      if (cb->version < 2) {
885	CFStreamError err = {0, 0};
886	isComplete = ((_CFStreamCBOpenCompletedV1)(cb->openCompleted))(stream, &err, _CFStreamGetInfoPointer(stream));
887	if (err.error != 0) _CFStreamSetStreamError(stream, &err);
888      } else {
889	isComplete = cb->openCompleted(stream, &(stream->error), _CFStreamGetInfoPointer(stream));
890      }
891      if (isComplete) {
892	if (!stream->error) {
893	  status = kCFStreamStatusOpen;
894	} else {
895	  status = kCFStreamStatusError;
896	}
897	_CFStreamSetStatusCode(stream, status);
898	if (status == kCFStreamStatusOpen) {
899	  _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted);
900	} else {
901	  _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
902	}
903      }
904    }
905  }
906  __CFBitClear(stream->flags, CALLING_CLIENT);
907  return status;
908}
909
910CF_EXPORT CFStreamStatus CFReadStreamGetStatus(CFReadStreamRef stream) {
911    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFStreamStatus, (NSInputStream *)stream, streamStatus);
912    return _CFStreamGetStatus((struct _CFStream *)stream);
913}
914
915CF_EXPORT CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream) {
916    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFStreamStatus, (NSOutputStream *)stream, streamStatus);
917    return _CFStreamGetStatus((struct _CFStream *)stream);
918}
919
920static CFStreamError _CFStreamGetStreamError(struct _CFStream *stream) {
921    CFStreamError result;
922    if (!stream->error) {
923        result.error = 0;
924        result.domain = 0;
925    } else if (_CFStreamGetCallBackPtr(stream)->version < 2) {
926        CFStreamError *streamError = (CFStreamError *)(stream->error);
927        result.error = streamError->error;
928        result.domain = streamError->domain;
929    } else {
930        result = _CFStreamErrorFromError(stream->error);
931    }
932    return result;
933}
934
935CF_EXPORT CFStreamError CFReadStreamGetError(CFReadStreamRef stream) {
936    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFStreamError, (NSInputStream *)stream, _cfStreamError);
937    return _CFStreamGetStreamError((struct _CFStream *)stream);
938}
939
940CF_EXPORT CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream) {
941    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFStreamError, (NSOutputStream *)stream, _cfStreamError);
942    return _CFStreamGetStreamError((struct _CFStream *)stream);
943}
944
945static CFErrorRef _CFStreamCopyError(struct _CFStream *stream) {
946    if (!stream->error) {
947        return NULL;
948    } else if (_CFStreamGetCallBackPtr(stream)->version < 2) {
949        return _CFErrorFromStreamError(CFGetAllocator(stream), (CFStreamError *)(stream->error));
950    } else {
951        CFRetain(stream->error);
952        return stream->error;
953    }
954}
955
956CF_EXPORT CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) {
957    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFErrorRef, (NSInputStream *)stream, streamError);
958    return _CFStreamCopyError((struct _CFStream *)stream);
959}
960
961CF_EXPORT CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) {
962    return _CFStreamCopyError((struct _CFStream *)stream);
963    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFErrorRef, (NSOutputStream *)stream, streamError);
964}
965
966CF_PRIVATE Boolean _CFStreamOpen(struct _CFStream *stream) {
967    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
968    Boolean success, openComplete;
969    if (_CFStreamGetStatus(stream) != kCFStreamStatusNotOpen) {
970        return FALSE;
971    }
972    __CFBitSet(stream->flags, CALLING_CLIENT);
973    _CFStreamSetStatusCode(stream, kCFStreamStatusOpening);
974    if (cb->open) {
975        if (cb->version < 2) {
976            CFStreamError err = {0, 0};
977            success = ((_CFStreamCBOpenV1)(cb->open))(stream, &err, &openComplete, _CFStreamGetInfoPointer(stream));
978            if (err.error != 0) _CFStreamSetStreamError(stream, &err);
979        } else {
980            success = cb->open(stream, &(stream->error), &openComplete, _CFStreamGetInfoPointer(stream));
981        }
982    } else {
983        success = TRUE;
984        openComplete = TRUE;
985    }
986    if (openComplete) {
987        if (success) {
988            // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
989            if (__CFStreamGetStatus(stream) == kCFStreamStatusOpening) {
990                _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
991            }
992            _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted);
993        } else {
994#if DEPLOYMENT_TARGET_WINDOWS
995            _CFStreamClose(stream);
996#endif
997            _CFStreamSetStatusCode(stream, kCFStreamStatusError);
998            _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
999        }
1000    }
1001    __CFBitClear(stream->flags, CALLING_CLIENT);
1002    return success;
1003}
1004
1005CF_EXPORT Boolean CFReadStreamOpen(CFReadStreamRef stream) {
1006    if(CF_IS_OBJC(__kCFReadStreamTypeID, stream)) {
1007        (void)CF_OBJC_CALLV((NSInputStream *)stream, open);
1008        return TRUE;
1009    }
1010    return _CFStreamOpen((struct _CFStream *)stream);
1011}
1012
1013CF_EXPORT Boolean CFWriteStreamOpen(CFWriteStreamRef stream) {
1014    if(CF_IS_OBJC(__kCFWriteStreamTypeID, stream)) {
1015        (void)CF_OBJC_CALLV((NSOutputStream *)stream, open);
1016        return TRUE;
1017    }
1018    return _CFStreamOpen((struct _CFStream *)stream);
1019}
1020
1021CF_EXPORT void CFReadStreamClose(CFReadStreamRef stream) {
1022    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, void, (NSInputStream *)stream, close);
1023    _CFStreamClose((struct _CFStream *)stream);
1024}
1025
1026CF_EXPORT void CFWriteStreamClose(CFWriteStreamRef stream) {
1027    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, void, (NSOutputStream *)stream, close);
1028    _CFStreamClose((struct _CFStream *)stream);
1029}
1030
1031CF_EXPORT Boolean CFReadStreamHasBytesAvailable(CFReadStreamRef readStream) {
1032    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, Boolean, (NSInputStream *)readStream, hasBytesAvailable);
1033    struct _CFStream *stream = (struct _CFStream *)readStream;
1034    CFStreamStatus status = _CFStreamGetStatus(stream);
1035    const struct _CFStreamCallBacks *cb;
1036    if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading) {
1037        return FALSE;
1038    }
1039    cb  = _CFStreamGetCallBackPtr(stream);
1040    if (cb->canRead == NULL) {
1041        return TRUE;  // No way to know without trying....
1042    } else {
1043        Boolean result;
1044        __CFBitSet(stream->flags, CALLING_CLIENT);
1045        if (cb->version < 2) {
1046            result = ((_CFStreamCBCanReadV1)(cb->canRead))((CFReadStreamRef)stream, _CFStreamGetInfoPointer(stream));
1047        } else {
1048            result = cb->canRead((CFReadStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream));
1049            if (stream->error) {
1050                _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1051                _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1052            }
1053        }
1054        __CFBitClear(stream->flags, CALLING_CLIENT);
1055        return result;
1056    }
1057}
1058
1059static void waitForOpen(struct _CFStream *stream);
1060CFIndex CFReadStreamRead(CFReadStreamRef readStream, UInt8 *buffer, CFIndex bufferLength) {
1061    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFIndex, (NSInputStream *)readStream, read:(uint8_t *)buffer maxLength:(NSUInteger)bufferLength);
1062    struct _CFStream *stream = (struct _CFStream *)readStream;
1063    CFStreamStatus status = _CFStreamGetStatus(stream);
1064    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1065    if (status == kCFStreamStatusOpening) {
1066        __CFBitSet(stream->flags, CALLING_CLIENT);
1067        waitForOpen(stream);
1068        __CFBitClear(stream->flags, CALLING_CLIENT);
1069        status = _CFStreamGetStatus(stream);
1070    }
1071
1072    if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading && status != kCFStreamStatusAtEnd) {
1073        return -1;
1074    } else  if (status == kCFStreamStatusAtEnd) {
1075        return 0;
1076    } else {
1077        Boolean atEOF;
1078        CFIndex bytesRead;
1079        __CFBitSet(stream->flags, CALLING_CLIENT);
1080        if (stream->client) {
1081            stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable;
1082        }
1083        _CFStreamSetStatusCode(stream, kCFStreamStatusReading);
1084        if (cb->version < 2) {
1085            CFStreamError err = {0, 0};
1086            bytesRead = ((_CFStreamCBReadV1)(cb->read))((CFReadStreamRef)stream, buffer, bufferLength, &err, &atEOF, _CFStreamGetInfoPointer(stream));
1087            if (err.error != 0) _CFStreamSetStreamError(stream, &err);
1088        } else {
1089            bytesRead = cb->read((CFReadStreamRef)stream, buffer, bufferLength, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream));
1090        }
1091        if (stream->error) {
1092            bytesRead = -1;
1093            _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1094            _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1095        } else if (atEOF) {
1096            _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1097            _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1098        } else {
1099            _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1100        }
1101        __CFBitClear(stream->flags, CALLING_CLIENT);
1102        return bytesRead;
1103    }
1104}
1105
1106CF_EXPORT const UInt8 *CFReadStreamGetBuffer(CFReadStreamRef readStream, CFIndex maxBytesToRead, CFIndex *numBytesRead) {
1107    if (CF_IS_OBJC(__kCFReadStreamTypeID, readStream)) {
1108        uint8_t *bufPtr = NULL;
1109        Boolean gotBytes = (Boolean) CF_OBJC_CALLV((NSInputStream *)readStream, getBuffer:&bufPtr length:(NSUInteger *)numBytesRead);
1110        if(gotBytes) {
1111            return (const UInt8 *)bufPtr;
1112        } else {
1113            return NULL;
1114        }
1115    }
1116    struct _CFStream *stream = (struct _CFStream *)readStream;
1117    CFStreamStatus status = _CFStreamGetStatus(stream);
1118    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1119    const UInt8 *buffer;
1120    if (status == kCFStreamStatusOpening) {
1121        __CFBitSet(stream->flags, CALLING_CLIENT);
1122        waitForOpen(stream);
1123        __CFBitClear(stream->flags, CALLING_CLIENT);
1124        status = _CFStreamGetStatus(stream);
1125    }
1126    if (status != kCFStreamStatusOpen && status != kCFStreamStatusReading && status != kCFStreamStatusAtEnd) {
1127        *numBytesRead = -1;
1128        buffer = NULL;
1129    } else  if (status == kCFStreamStatusAtEnd || cb->getBuffer == NULL) {
1130        *numBytesRead = 0;
1131        buffer = NULL;
1132    } else {
1133        Boolean atEOF;
1134        Boolean hadBytes = stream->client && (stream->client->whatToSignal & kCFStreamEventHasBytesAvailable);
1135        __CFBitSet(stream->flags, CALLING_CLIENT);
1136        if (hadBytes) {
1137            stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable;
1138        }
1139        _CFStreamSetStatusCode(stream, kCFStreamStatusReading);
1140        if (cb->version < 2) {
1141            CFStreamError err = {0, 0};
1142            buffer = ((_CFStreamCBGetBufferV1)(cb->getBuffer))((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &err, &atEOF, _CFStreamGetInfoPointer(stream));
1143            if (err.error != 0) _CFStreamSetStreamError(stream, &err);
1144        } else {
1145            buffer = cb->getBuffer((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream));
1146        }
1147        if (stream->error) {
1148            *numBytesRead = -1;
1149            _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1150            buffer = NULL;
1151            _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1152        } else if (atEOF) {
1153            _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1154            _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1155        } else {
1156            if (!buffer && hadBytes) {
1157                stream->client->whatToSignal |= kCFStreamEventHasBytesAvailable;
1158            }
1159            _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1160        }
1161        __CFBitClear(stream->flags, CALLING_CLIENT);
1162    }
1163    return buffer;
1164}
1165
1166CF_EXPORT Boolean CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream) {
1167    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, Boolean, (NSOutputStream *)writeStream, hasSpaceAvailable);
1168    struct _CFStream *stream = (struct _CFStream *)writeStream;
1169    CFStreamStatus status = _CFStreamGetStatus(stream);
1170    const struct _CFStreamCallBacks *cb;
1171    if (status != kCFStreamStatusOpen && status != kCFStreamStatusWriting) {
1172        return FALSE;
1173    }
1174    cb  = _CFStreamGetCallBackPtr(stream);
1175    if (cb->canWrite == NULL) {
1176        return TRUE;  // No way to know without trying....
1177    } else {
1178        Boolean result;
1179        __CFBitSet(stream->flags, CALLING_CLIENT);
1180        if (cb->version < 2) {
1181            result = ((_CFStreamCBCanWriteV1)(cb->canWrite))((CFWriteStreamRef)stream, _CFStreamGetInfoPointer(stream));
1182        } else {
1183            result = cb->canWrite((CFWriteStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream));
1184            if (stream->error) {
1185                _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1186                _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1187            }
1188        }
1189        __CFBitClear(stream->flags, CALLING_CLIENT);
1190        return result;
1191    }
1192}
1193
1194CF_EXPORT CFIndex CFWriteStreamWrite(CFWriteStreamRef writeStream, const UInt8 *buffer, CFIndex bufferLength) {
1195    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFIndex, (NSOutputStream *)writeStream, write:(const uint8_t *)buffer maxLength:(NSUInteger)bufferLength);
1196    struct _CFStream *stream = (struct _CFStream *)writeStream;
1197    CFStreamStatus status = _CFStreamGetStatus(stream);
1198    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1199    if (status == kCFStreamStatusOpening) {
1200        __CFBitSet(stream->flags, CALLING_CLIENT);
1201        waitForOpen(stream);
1202        __CFBitClear(stream->flags, CALLING_CLIENT);
1203        status = _CFStreamGetStatus(stream);
1204    }
1205    if (status != kCFStreamStatusOpen && status != kCFStreamStatusWriting) {
1206        return -1;
1207    } else {
1208        CFIndex result;
1209        __CFBitSet(stream->flags, CALLING_CLIENT);
1210        _CFStreamSetStatusCode(stream, kCFStreamStatusWriting);
1211        if (stream->client) {
1212            stream->client->whatToSignal &= ~kCFStreamEventCanAcceptBytes;
1213        }
1214        if (cb->version < 2) {
1215            CFStreamError err = {0, 0};
1216            result = ((_CFStreamCBWriteV1)(cb->write))((CFWriteStreamRef)stream, buffer, bufferLength, &err, _CFStreamGetInfoPointer(stream));
1217            if (err.error) _CFStreamSetStreamError(stream, &err);
1218        } else {
1219            result = cb->write((CFWriteStreamRef)stream, buffer, bufferLength, &(stream->error), _CFStreamGetInfoPointer(stream));
1220        }
1221        if (stream->error) {
1222            _CFStreamSetStatusCode(stream, kCFStreamStatusError);
1223            _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred);
1224        } else if (result == 0) {
1225            _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd);
1226            _CFStreamScheduleEvent(stream, kCFStreamEventEndEncountered);
1227        } else {
1228            _CFStreamSetStatusCode(stream, kCFStreamStatusOpen);
1229        }
1230        __CFBitClear(stream->flags, CALLING_CLIENT);
1231        return result;
1232    }
1233}
1234
1235CF_PRIVATE CFTypeRef _CFStreamCopyProperty(struct _CFStream *stream, CFStringRef propertyName) {
1236    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1237    if (cb->copyProperty == NULL) {
1238        return NULL;
1239    } else {
1240        CFTypeRef result;
1241        __CFBitSet(stream->flags, CALLING_CLIENT);
1242        result = cb->copyProperty(stream, propertyName, _CFStreamGetInfoPointer(stream));
1243        __CFBitClear(stream->flags, CALLING_CLIENT);
1244        return result;
1245    }
1246}
1247
1248CF_EXPORT CFTypeRef CFReadStreamCopyProperty(CFReadStreamRef stream, CFStringRef propertyName) {
1249    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, CFTypeRef, (NSInputStream *)stream, propertyForKey:(NSString *)propertyName);
1250    return _CFStreamCopyProperty((struct _CFStream *)stream, propertyName);
1251}
1252
1253CF_EXPORT CFTypeRef CFWriteStreamCopyProperty(CFWriteStreamRef stream, CFStringRef propertyName) {
1254    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, CFTypeRef, (NSOutputStream *)stream, propertyForKey:(NSString *)propertyName);
1255    return _CFStreamCopyProperty((struct _CFStream *)stream, propertyName);
1256}
1257
1258CF_PRIVATE Boolean _CFStreamSetProperty(struct _CFStream *stream, CFStringRef prop, CFTypeRef val) {
1259    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1260    if (cb->setProperty == NULL) {
1261        return FALSE;
1262    } else {
1263        Boolean result;
1264        __CFBitSet(stream->flags, CALLING_CLIENT);
1265        result = cb->setProperty(stream, prop, val, _CFStreamGetInfoPointer(stream));
1266        __CFBitClear(stream->flags, CALLING_CLIENT);
1267        return result;
1268    }
1269}
1270
1271CF_EXPORT
1272Boolean CFReadStreamSetProperty(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue) {
1273    CF_OBJC_FUNCDISPATCHV(__kCFReadStreamTypeID, Boolean, (NSInputStream *)stream, setProperty:(id)propertyValue forKey:(NSString *)propertyName);
1274    return _CFStreamSetProperty((struct _CFStream *)stream, propertyName, propertyValue);
1275}
1276
1277CF_EXPORT
1278Boolean CFWriteStreamSetProperty(CFWriteStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue) {
1279    CF_OBJC_FUNCDISPATCHV(__kCFWriteStreamTypeID, Boolean, (NSOutputStream *)stream, setProperty:(id)propertyValue forKey:(NSString *)propertyName);
1280    return _CFStreamSetProperty((struct _CFStream *)stream, propertyName, propertyValue);
1281}
1282
1283static void _initializeClient(struct _CFStream *stream) {
1284    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1285    if (!cb->schedule) return; // Do we wish to allow this?
1286    stream->client = (struct _CFStreamClient *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(struct _CFStreamClient), 0);
1287    memset(stream->client, 0, sizeof(struct _CFStreamClient));
1288}
1289
1290/* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1291CF_PRIVATE Boolean _CFStreamSetClient(struct _CFStream *stream, CFOptionFlags streamEvents, void (*clientCB)(struct _CFStream *, CFStreamEventType, void *), CFStreamClientContext *clientCallBackContext) {
1292
1293    Boolean removingClient = (streamEvents == kCFStreamEventNone || clientCB == NULL || clientCallBackContext == NULL);
1294
1295    if (removingClient) {
1296        clientCB = NULL;
1297        streamEvents = kCFStreamEventNone;
1298        clientCallBackContext = NULL;
1299    }
1300    if (!stream->client) {
1301        if (removingClient) {
1302            // We have no client now, and we've been asked to add none???
1303            return TRUE;
1304        }
1305        _initializeClient(stream);
1306        if (!stream->client) {
1307            // Asynch not supported
1308            return FALSE;
1309        }
1310    }
1311    if (stream->client->cb && stream->client->cbContext.release) {
1312        stream->client->cbContext.release(stream->client->cbContext.info);
1313    }
1314    stream->client->cb = clientCB;
1315    if (clientCallBackContext) {
1316        stream->client->cbContext.version = clientCallBackContext->version;
1317        stream->client->cbContext.retain = clientCallBackContext->retain;
1318        stream->client->cbContext.release = clientCallBackContext->release;
1319        stream->client->cbContext.copyDescription = clientCallBackContext->copyDescription;
1320        stream->client->cbContext.info = (clientCallBackContext->retain && clientCallBackContext->info) ? clientCallBackContext->retain(clientCallBackContext->info) : clientCallBackContext->info;
1321    } else {
1322        stream->client->cbContext.retain = NULL;
1323        stream->client->cbContext.release = NULL;
1324        stream->client->cbContext.copyDescription = NULL;
1325        stream->client->cbContext.info = NULL;
1326    }
1327    if (stream->client->when != streamEvents) {
1328        const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1329        stream->client->when = streamEvents;
1330        if (cb->requestEvents) {
1331            cb->requestEvents(stream, streamEvents, _CFStreamGetInfoPointer(stream));
1332        }
1333    }
1334    return TRUE;
1335}
1336
1337CF_EXPORT Boolean CFReadStreamSetClient(CFReadStreamRef readStream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
1338#if defined(CFSTREAM_SUPPORTS_BRIDGING)
1339    if (CF_IS_OBJC(__kCFReadStreamTypeID, (const void *)(NSInputStream *)readStream)) {
1340        NSInputStream* is = (NSInputStream*) readStream;
1341
1342        if ([is respondsToSelector:@selector(_setCFClientFlags:callback:context:)])
1343            return [is _setCFClientFlags:streamEvents callback:clientCB context:clientContext];
1344        else {
1345            if (clientCB == NULL)
1346                [is setDelegate:nil];
1347            else {
1348                _CFStreamDelegate* d = [[_CFStreamDelegate alloc] initWithStreamEvents:streamEvents callback:(void*) clientCB context:clientContext];
1349                [is setDelegate:d];
1350            }
1351            return true;
1352        }
1353    }
1354#endif
1355
1356    streamEvents &= ~kCFStreamEventCanAcceptBytes;
1357    return _CFStreamSetClient((struct _CFStream *)readStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext);
1358}
1359
1360CF_EXPORT Boolean CFWriteStreamSetClient(CFWriteStreamRef writeStream, CFOptionFlags streamEvents, CFWriteStreamClientCallBack clientCB, CFStreamClientContext *clientContext) {
1361#if defined(CFSTREAM_SUPPORTS_BRIDGING)
1362    if (CF_IS_OBJC(__kCFWriteStreamTypeID, (const void *)(NSInputStream *)writeStream)) {
1363        NSOutputStream* os = (NSOutputStream*) writeStream;
1364
1365        if ([os respondsToSelector:@selector(_setCFClientFlags:callback:context:)])
1366            return [os _setCFClientFlags:streamEvents callback:clientCB context:clientContext];
1367        else {
1368            if (clientCB == NULL)
1369                [os setDelegate:nil];
1370            else {
1371                _CFStreamDelegate* d = [[_CFStreamDelegate alloc] initWithStreamEvents:streamEvents callback:(void*) clientCB context:clientContext];
1372                [os setDelegate:d];
1373            }
1374            return true;
1375        }
1376    }
1377#endif
1378
1379    streamEvents &= ~kCFStreamEventHasBytesAvailable;
1380    return _CFStreamSetClient((struct _CFStream *)writeStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext);
1381}
1382
1383CF_INLINE void *_CFStreamGetClient(struct _CFStream *stream) {
1384    if (stream->client) return stream->client->cbContext.info;
1385    else return NULL;
1386}
1387
1388CF_EXPORT void *_CFReadStreamGetClient(CFReadStreamRef readStream) {
1389    return _CFStreamGetClient((struct _CFStream *)readStream);
1390}
1391
1392CF_EXPORT void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream) {
1393    return _CFStreamGetClient((struct _CFStream *)writeStream);
1394}
1395
1396
1397CF_PRIVATE void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1398    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1399
1400    if (! stream->client) {
1401        _initializeClient(stream);
1402        if (!stream->client) return; // we don't support asynch.
1403    }
1404
1405    if (! stream->client->rlSource) {
1406	/* No source, so we join the shared source group */
1407        CFTypeRef a[] = { runLoop, runLoopMode };
1408
1409        CFArrayRef runLoopAndSourceKey = CFArrayCreate(kCFAllocatorSystemDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks);
1410
1411        __CFSpinLock(&sSourceLock);
1412
1413        if (!sSharedSources)
1414            sSharedSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1415
1416        CFMutableArrayRef listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1417        if (listOfStreamsSharingASource) {
1418			struct _CFStream* aStream = (struct _CFStream*) CFArrayGetValueAtIndex(listOfStreamsSharingASource, 0);
1419			CFRunLoopSourceRef source = _CFStreamCopySource(aStream);
1420			if (source) {
1421				_CFStreamSetSource(stream, source, FALSE);
1422				CFRelease(source);
1423			}
1424            CFRetain(listOfStreamsSharingASource);
1425        }
1426        else {
1427            CFRunLoopSourceContext ctxt = {
1428                0,
1429                NULL,
1430                CFRetain,
1431                CFRelease,
1432                (CFStringRef(*)(const void *))CFCopyDescription,
1433                NULL,
1434                NULL,
1435                NULL,
1436                NULL,
1437                (void(*)(void *))_cfstream_shared_signalEventSync
1438            };
1439
1440            listOfStreamsSharingASource = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1441            CFDictionaryAddValue(sSharedSources, runLoopAndSourceKey, listOfStreamsSharingASource);
1442
1443            ctxt.info = listOfStreamsSharingASource;
1444
1445			CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &ctxt);
1446			_CFStreamSetSource(stream, source, FALSE);
1447            CFRunLoopAddSource(runLoop, source, runLoopMode);
1448			CFRelease(source);
1449        }
1450
1451        CFArrayAppendValue(listOfStreamsSharingASource, stream);
1452        CFDictionaryAddValue(sSharedSources, stream, runLoopAndSourceKey);
1453
1454        CFRelease(runLoopAndSourceKey);
1455        CFRelease(listOfStreamsSharingASource);
1456
1457        __CFBitSet(stream->flags, SHARED_SOURCE);
1458
1459        __CFSpinUnlock(&sSourceLock);
1460    }
1461    else if (__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
1462        /* We were sharing, but now we'll get our own source */
1463
1464        CFArrayRef runLoopAndSourceKey;
1465        CFMutableArrayRef listOfStreamsSharingASource;
1466        CFIndex count, i;
1467
1468        CFAllocatorRef alloc = CFGetAllocator(stream);
1469        CFRunLoopSourceContext ctxt = {
1470            0,
1471            (void *)stream,
1472            NULL,														// Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1473            NULL,														// Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1474            (CFStringRef(*)(const void *))CFCopyDescription,
1475            NULL,
1476            NULL,
1477            NULL,
1478            NULL,
1479            (void(*)(void *))_cfstream_solo_signalEventSync
1480        };
1481
1482        __CFSpinLock(&sSourceLock);
1483
1484        runLoopAndSourceKey = (CFArrayRef)CFRetain((CFTypeRef)CFDictionaryGetValue(sSharedSources, stream));
1485        listOfStreamsSharingASource = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1486
1487        count = CFArrayGetCount(listOfStreamsSharingASource);
1488        i = CFArrayGetFirstIndexOfValue(listOfStreamsSharingASource, CFRangeMake(0, count), stream);
1489        if (i != kCFNotFound) {
1490            CFArrayRemoveValueAtIndex(listOfStreamsSharingASource, i);
1491            count--;
1492        }
1493
1494        if (count == 0) {
1495			CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1496			if (source) {
1497				CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), source, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
1498				CFRelease(source);
1499			}
1500            CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
1501        }
1502
1503        CFDictionaryRemoveValue(sSharedSources, stream);
1504
1505		_CFStreamSetSource(stream, NULL, count == 0);
1506
1507        __CFBitClear(stream->flags, SHARED_SOURCE);
1508
1509        __CFSpinUnlock(&sSourceLock);
1510
1511		CFRunLoopSourceRef source = CFRunLoopSourceCreate(alloc, 0, &ctxt);
1512		_CFStreamSetSource(stream, source, FALSE);
1513        CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 0), source, (CFStringRef)CFArrayGetValueAtIndex(runLoopAndSourceKey, 1));
1514        CFRelease(runLoopAndSourceKey);
1515
1516        CFRunLoopAddSource(runLoop, source, runLoopMode);
1517
1518		CFRelease(source);
1519    } else {
1520	/* We're not sharing, so just add the source to the rl & mode */
1521		CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1522		if (source) {
1523			CFRunLoopAddSource(runLoop, source, runLoopMode);
1524			CFRelease(source);
1525		}
1526    }
1527
1528    _CFStreamLock(stream);
1529    if (!stream->client->runLoopsAndModes) {
1530        stream->client->runLoopsAndModes = CFArrayCreateMutable(CFGetAllocator(stream), 0, &kCFTypeArrayCallBacks);
1531    }
1532    CFArrayAppendValue(stream->client->runLoopsAndModes, runLoop);
1533    CFArrayAppendValue(stream->client->runLoopsAndModes, runLoopMode);
1534    checkRLMArray(stream->client->runLoopsAndModes);
1535    _CFStreamUnlock(stream);
1536
1537    if (cb->schedule) {
1538        __CFBitSet(stream->flags, CALLING_CLIENT);
1539        cb->schedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
1540        __CFBitClear(stream->flags, CALLING_CLIENT);
1541    }
1542
1543    /*
1544     * If we've got events pending, we need to wake up and signal
1545     */
1546    if (stream->client && stream->client->whatToSignal != 0) {
1547		CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1548		if (source) {
1549			CFRunLoopSourceSignal(source);
1550			CFRelease(source);
1551            _wakeUpRunLoop(stream);
1552        }
1553    }
1554}
1555
1556CF_EXPORT void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1557#if defined(CFSTREAM_SUPPORTS_BRIDGING)
1558    if (CF_IS_OBJC(__kCFReadStreamTypeID, (const void *)(NSInputStream *)stream)) {
1559        NSInputStream* is  = (NSInputStream*) stream;
1560        if ([is respondsToSelector:@selector(_scheduleInCFRunLoop:forMode:)])
1561            [is _scheduleInCFRunLoop:runLoop forMode:runLoopMode];
1562        else
1563            [is scheduleInRunLoop:cfToNSRL(runLoop) forMode:(id) runLoopMode];
1564        return;
1565    }
1566#endif
1567
1568    _CFStreamScheduleWithRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1569}
1570
1571CF_EXPORT void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1572#if defined(CFSTREAM_SUPPORTS_BRIDGING)
1573    if (CF_IS_OBJC(__kCFWriteStreamTypeID, (const void *)(NSOutputStream *)stream)) {
1574        NSOutputStream* os  = (NSOutputStream*) stream;
1575        if ([os respondsToSelector:@selector(_scheduleInCFRunLoop:forMode:)])
1576            [os _scheduleInCFRunLoop:runLoop forMode:runLoopMode];
1577        else
1578            [os scheduleInRunLoop:cfToNSRL(runLoop) forMode:(id) runLoopMode];
1579        return;
1580    }
1581#endif
1582
1583    _CFStreamScheduleWithRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1584}
1585
1586
1587CF_PRIVATE void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1588    const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream);
1589    if (!stream->client) return;
1590    if (!stream->client->rlSource) return;
1591
1592    if (!__CFBitIsSet(stream->flags, SHARED_SOURCE)) {
1593		CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1594		if (source) {
1595			CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1596			CFRelease(source);
1597		}
1598    } else {
1599        CFArrayRef runLoopAndSourceKey;
1600        CFMutableArrayRef list;
1601        CFIndex count, i;
1602
1603        __CFSpinLock(&sSourceLock);
1604
1605        runLoopAndSourceKey = (CFArrayRef)CFDictionaryGetValue(sSharedSources, stream);
1606        list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, runLoopAndSourceKey);
1607
1608        count = CFArrayGetCount(list);
1609        i = CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, count), stream);
1610        if (i != kCFNotFound) {
1611            CFArrayRemoveValueAtIndex(list, i);
1612            count--;
1613        }
1614
1615        if (count == 0) {
1616			CFRunLoopSourceRef source = _CFStreamCopySource(stream);
1617			if (source) {
1618				CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1619				CFRelease(source);
1620			}
1621            CFDictionaryRemoveValue(sSharedSources, runLoopAndSourceKey);
1622        }
1623
1624        CFDictionaryRemoveValue(sSharedSources, stream);
1625
1626        _CFStreamSetSource(stream, NULL, count == 0);
1627
1628        __CFBitClear(stream->flags, SHARED_SOURCE);
1629
1630        __CFSpinUnlock(&sSourceLock);
1631    }
1632
1633    _CFStreamLock(stream);
1634    _CFStreamRemoveRunLoopAndModeFromArray(stream->client->runLoopsAndModes, runLoop, runLoopMode);
1635    checkRLMArray(stream->client->runLoopsAndModes);
1636    _CFStreamUnlock(stream);
1637
1638    if (cb->unschedule) {
1639        cb->unschedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream));
1640    }
1641}
1642
1643CF_EXPORT void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1644#if defined(CFSTREAM_SUPPORTS_BRIDGING)
1645    if (CF_IS_OBJC(__kCFReadStreamTypeID, (const void *)(NSInputStream *)stream)) {
1646        NSInputStream* is  = (NSInputStream*) stream;
1647        if ([is respondsToSelector:@selector(_unscheduleFromCFRunLoop:forMode:)])
1648            [is _unscheduleFromCFRunLoop:runLoop forMode:runLoopMode];
1649        else
1650            [is removeFromRunLoop:cfToNSRL(runLoop) forMode:(id) runLoopMode];
1651        return;
1652    }
1653#endif
1654
1655    _CFStreamUnscheduleFromRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1656}
1657
1658void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode) {
1659#if defined(CFSTREAM_SUPPORTS_BRIDGING)
1660    if (CF_IS_OBJC(__kCFWriteStreamTypeID, (const void *)(NSOutputStream *)stream)) {
1661        NSOutputStream* os  = (NSOutputStream*) stream;
1662        if ([os respondsToSelector:@selector(_unscheduleFromCFRunLoop:forMode:)])
1663            [os _unscheduleFromCFRunLoop:runLoop forMode:runLoopMode];
1664        else
1665            [os removeFromRunLoop:cfToNSRL(runLoop) forMode:(id) runLoopMode];
1666        return;
1667    }
1668#endif
1669
1670    _CFStreamUnscheduleFromRunLoop((struct _CFStream *)stream, runLoop, runLoopMode);
1671}
1672
1673static CFRunLoopRef sLegacyRL = NULL;
1674
1675static void _perform(void* info)
1676{
1677}
1678
1679static void* _legacyStreamRunLoop_workThread(void* arg)
1680{
1681    sLegacyRL = CFRunLoopGetCurrent();
1682
1683#if defined(LOG_STREAM)
1684    fprintf(stderr, "Creating Schedulingset emulation thread.  Runloop: %p\n", sLegacyRL);
1685#endif
1686
1687    CFStringRef s = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<< CFStreamLegacySource for Runloop %p >>"), sLegacyRL);
1688
1689    CFRunLoopSourceContext ctxt = {
1690        0,
1691        (void*) s,
1692        CFRetain,
1693        CFRelease,
1694        CFCopyDescription,
1695        CFEqual,
1696        CFHash,
1697        NULL,
1698        NULL,
1699        _perform
1700    };
1701
1702    CFRunLoopSourceRef rls = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &ctxt);
1703    CFRelease(s);
1704
1705    CFRunLoopAddSource(sLegacyRL, rls, kCFRunLoopDefaultMode);
1706    CFRelease(rls);
1707
1708    dispatch_semaphore_signal(*(dispatch_semaphore_t*) arg);
1709    arg = NULL;
1710
1711    while (true) {
1712        SInt32 why = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1E30, true);
1713
1714        (void) why;
1715#if defined(LOG_STREAM)
1716        switch (why) {
1717            case kCFRunLoopRunFinished:
1718                fprintf(stderr, "WOKE: kCFRunLoopRunFinished\n");
1719                break;
1720            case kCFRunLoopRunStopped:
1721                fprintf(stderr, "WOKE: kCFRunLoopRunStopped\n");
1722                break;
1723            case kCFRunLoopRunTimedOut:
1724                fprintf(stderr, "WOKE: kCFRunLoopRunTimedOut\n");
1725                break;
1726            case kCFRunLoopRunHandledSource:
1727                fprintf(stderr, "WOKE: kCFRunLoopRunHandledSource\n");
1728                break;
1729        }
1730#endif
1731    }
1732
1733    return NULL;
1734}
1735static CFRunLoopRef _legacyStreamRunLoop()
1736{
1737    static dispatch_once_t sOnce = 0;
1738
1739    dispatch_once(&sOnce, ^{
1740
1741        if (sLegacyRL == NULL) {
1742            dispatch_semaphore_t sem = dispatch_semaphore_create(0);
1743
1744            pthread_attr_t attr;
1745            pthread_attr_init(&attr);
1746            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1747            pthread_t workThread;
1748            (void) pthread_create(&workThread, &attr, _legacyStreamRunLoop_workThread, &sem);
1749            pthread_attr_destroy(&attr);
1750
1751            dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
1752            dispatch_release(sem);
1753        }
1754    });
1755
1756    return sLegacyRL;
1757}
1758
1759static dispatch_queue_t _CFStreamCopyDispatchQueue(struct _CFStream* stream)
1760{
1761    dispatch_queue_t result = NULL;
1762
1763    _CFStreamLock(stream);
1764    if (stream->client) {
1765        result = stream->queue;
1766        if (result)
1767            dispatch_retain(result);
1768    }
1769    _CFStreamUnlock(stream);
1770
1771    return result;
1772}
1773
1774static void _CFStreamSetDispatchQueue(struct _CFStream* stream, dispatch_queue_t q)
1775{
1776    CFArrayRef rlm = _CFStreamCopyRunLoopsAndModes(stream);
1777    if (rlm) {
1778        CFIndex count = CFArrayGetCount(rlm);
1779        for (CFIndex i = 0;  i < count;  i += 2) {
1780            CFRunLoopRef rl = (CFRunLoopRef) CFArrayGetValueAtIndex(rlm, i);
1781            CFStringRef mode = (CFStringRef) CFArrayGetValueAtIndex(rlm, i + 1);
1782            _CFStreamUnscheduleFromRunLoop(stream, rl, mode);
1783        }
1784        CFRelease(rlm);
1785    }
1786
1787    if (q == NULL) {
1788        _CFStreamLock(stream);
1789        if (stream->client) {
1790            if (stream->queue)
1791                dispatch_release(stream->queue);
1792            stream->queue = NULL;
1793        }
1794        _CFStreamUnlock(stream);
1795    } else {
1796        _CFStreamScheduleWithRunLoop(stream, _legacyStreamRunLoop(), kCFRunLoopDefaultMode);
1797
1798        _CFStreamLock(stream);
1799        if (stream->client) {
1800            if (stream->queue != q) {
1801                if (stream->queue)
1802                    dispatch_release(stream->queue);
1803                stream->queue = q;
1804                if (stream->queue)
1805                    dispatch_retain(stream->queue);
1806            }
1807        }
1808
1809        _CFStreamUnlock(stream);
1810    }
1811}
1812
1813void CFReadStreamSetDispatchQueue(CFReadStreamRef stream, dispatch_queue_t q)
1814{
1815    _CFStreamSetDispatchQueue((struct _CFStream*) stream, q);
1816}
1817
1818void CFWriteStreamSetDispatchQueue(CFWriteStreamRef stream, dispatch_queue_t q)
1819{
1820    _CFStreamSetDispatchQueue((struct _CFStream*) stream, q);
1821}
1822
1823dispatch_queue_t CFReadStreamCopyDispatchQueue(CFReadStreamRef stream)
1824{
1825    return _CFStreamCopyDispatchQueue((struct _CFStream*) stream);
1826}
1827
1828dispatch_queue_t CFWriteStreamCopyDispatchQueue(CFWriteStreamRef stream)
1829{
1830    return _CFStreamCopyDispatchQueue((struct _CFStream*) stream);
1831}
1832
1833
1834static void waitForOpen(struct _CFStream *stream) {
1835    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
1836    CFStringRef privateMode = CFSTR("_kCFStreamBlockingOpenMode");
1837    _CFStreamScheduleWithRunLoop(stream, runLoop, privateMode);
1838    // We cannot call _CFStreamGetStatus, because that tries to set/clear CALLING_CLIENT, which should be set around this entire call (we're within a call from the client).  This should be o.k., because we're running the run loop, so our status code should be being updated in a timely fashion....
1839    while (__CFStreamGetStatus(stream) == kCFStreamStatusOpening) {
1840        CFRunLoopRunInMode(privateMode, 1e+20, TRUE);
1841    }
1842    _CFStreamUnscheduleFromRunLoop(stream, runLoop, privateMode);
1843}
1844
1845CF_EXPORT CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream) {
1846    return _CFStreamGetRunLoopsAndModes((struct _CFStream *)readStream);
1847}
1848
1849CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream) {
1850    return _CFStreamGetRunLoopsAndModes((struct _CFStream *)writeStream);
1851}
1852
1853CF_EXPORT CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream) {
1854    return _CFStreamCopyRunLoopsAndModes((struct _CFStream *)readStream);
1855}
1856
1857CF_EXPORT CFArrayRef _CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream) {
1858    return _CFStreamCopyRunLoopsAndModes((struct _CFStream *)writeStream);
1859}
1860
1861CF_EXPORT void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error) {
1862    _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE);
1863}
1864
1865CF_EXPORT void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, const void *error) {
1866    _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE);
1867}
1868
1869CF_EXPORT void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, const void *error) {
1870    _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE);
1871}
1872
1873CF_EXPORT void _CFReadStreamClearEvent(CFReadStreamRef readStream, CFStreamEventType event) {
1874    struct _CFStream *stream = (struct _CFStream *)readStream;
1875    if (stream->client) {
1876        stream->client->whatToSignal &= ~event;
1877    }
1878}
1879
1880CF_EXPORT void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, const void *error) {
1881    _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE);
1882}
1883
1884CF_EXPORT void *CFReadStreamGetInfoPointer(CFReadStreamRef stream) {
1885    return _CFStreamGetInfoPointer((struct _CFStream *)stream);
1886}
1887
1888CF_EXPORT void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream) {
1889    return _CFStreamGetInfoPointer((struct _CFStream *)stream);
1890}
1891
1892/* CF_EXPORT */
1893void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode)
1894{
1895    CFIndex count;
1896    CFRange range;
1897
1898    checkRLMArray(runLoopsAndModes);
1899
1900    count = CFArrayGetCount(runLoopsAndModes);
1901    range = CFRangeMake(0, count);
1902
1903    while (range.length) {
1904
1905        CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop);
1906
1907        if (i == kCFNotFound)
1908            break;
1909
1910        if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, i + 1), runLoopMode))
1911            return;
1912
1913        range.location = i + 2;
1914        range.length = count - range.location;
1915    }
1916
1917	// Add the new values.
1918    CFArrayAppendValue(runLoopsAndModes, runLoop);
1919    CFArrayAppendValue(runLoopsAndModes, runLoopMode);
1920
1921	// Schedule the source on the new loop and mode.
1922    if (source)
1923        CFRunLoopAddSource(runLoop, source, runLoopMode);
1924}
1925
1926
1927/* CF_EXPORT */
1928void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode)
1929{
1930    CFIndex count;
1931	CFRange range;
1932
1933    count = CFArrayGetCount(runLoopsAndModes);
1934    range = CFRangeMake(0, count);
1935
1936    checkRLMArray(runLoopsAndModes);
1937
1938	while (range.length) {
1939
1940		CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop);
1941
1942		// If not found, it's not scheduled on it.
1943		if (i == kCFNotFound)
1944			return;
1945
1946		// Make sure it is scheduled in this mode.
1947		if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, i + 1), runLoopMode)) {
1948
1949			// Remove mode and runloop from the list.
1950            CFArrayReplaceValues(runLoopsAndModes, CFRangeMake(i, 2), NULL, 0);
1951
1952            // Remove it from the runloop.
1953            if (source)
1954                CFRunLoopRemoveSource(runLoop, source, runLoopMode);
1955
1956			return;
1957		}
1958
1959        range.location = i + 2;
1960        range.length = count - range.location;
1961	}
1962}
1963
1964
1965/* CF_EXPORT */
1966void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes)
1967{
1968    CFIndex i, count = CFArrayGetCount(runLoopsAndModes);
1969
1970    if (!source)
1971        return;
1972
1973    checkRLMArray(runLoopsAndModes);
1974
1975    for (i = 0; i < count; i += 2) {
1976
1977        // Make sure it's scheduled on all the right loops and modes.
1978        // Go through the array adding the source to all loops and modes.
1979        CFRunLoopAddSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopsAndModes, i),
1980                            source,
1981                            (CFStringRef)CFArrayGetValueAtIndex(runLoopsAndModes, i + 1));
1982	}
1983}
1984
1985
1986/* CF_EXPORT */
1987void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes)
1988{
1989    CFIndex i, count = CFArrayGetCount(runLoopsAndModes);
1990
1991    if (!source)
1992        return;
1993
1994    checkRLMArray(runLoopsAndModes);
1995
1996    for (i = 0; i < count; i += 2) {
1997
1998        // Go through the array removing the source from all loops and modes.
1999        CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(runLoopsAndModes, i),
2000                              source,
2001                              (CFStringRef)CFArrayGetValueAtIndex(runLoopsAndModes, i + 1));
2002	}
2003}
2004
2005Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode) {
2006    CFIndex idx, cnt;
2007    Boolean found = FALSE;
2008
2009    if (!runLoopsAndModes) return FALSE;
2010
2011    checkRLMArray(runLoopsAndModes);
2012
2013    cnt = CFArrayGetCount(runLoopsAndModes);
2014    for (idx = 0; idx + 1 < cnt; idx += 2) {
2015        if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx), rl) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx + 1), mode)) {
2016            CFArrayRemoveValueAtIndex(runLoopsAndModes, idx);
2017            CFArrayRemoveValueAtIndex(runLoopsAndModes, idx);
2018            found = TRUE;
2019            break;
2020        }
2021    }
2022    return found;
2023}
2024
2025// Used by NSStream to properly allocate the bridged objects
2026CF_EXPORT CFIndex _CFStreamInstanceSize(void) {
2027    return sizeof(struct _CFStream);
2028}
2029
2030#if DEPLOYMENT_TARGET_WINDOWS
2031void __CFStreamCleanup(void) {
2032    __CFSpinLock(&sSourceLock);
2033    if (sSharedSources) {
2034        CFIndex count = CFDictionaryGetCount(sSharedSources);
2035        if (count == 0) {
2036            // Only release if empty.  If it's still holding streams (which would be a client
2037            // bug leak), freeing this dict would free the streams, which then need to access the
2038            // dict to remove themselves, which leads to a deadlock.
2039            CFRelease(sSharedSources);
2040            sSharedSources = NULL;
2041        } else {
2042            const void ** keys = (const void **)malloc(sizeof(const void *) * count);
2043#if defined(DEBUG)
2044            int i;
2045#endif
2046            CFDictionaryGetKeysAndValues(sSharedSources, keys, NULL);
2047             fprintf(stderr, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count);
2048#if defined(DEBUG)
2049            for (i = 0; i < count;i ++) {
2050                if ((CFGetTypeID(keys[i]) == __kCFReadStreamTypeID) || (CFGetTypeID(keys[i]) == __kCFWriteStreamTypeID)) {
2051                    CFShow(keys[i]);
2052                }
2053            }
2054#endif
2055        }
2056    }
2057    __CFSpinUnlock(&sSourceLock);
2058}
2059#endif
2060
2061