2 * Copyright (c) 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 2000-2002, Apple, Inc. All rights reserved.
25 Responsibility: Becky Willrich
28 #include <CoreFoundation/CFRuntime.h>
29 #include <CoreFoundation/CFNumber.h>
31 #include "CFStreamInternal.h"
32 #include "CFInternal.h"
37 MIN_STATUS_CODE_BIT
= 0,
39 MAX_STATUS_CODE_BIT
= 4,
41 CONSTANT_CALLBACKS
= 5,
42 CALLING_CLIENT
= 6, // MUST remain 6 since it's value is used elsewhere.
46 // Values above used to be defined and others may rely on their values
48 // Values below should not matter if they are re-ordered or shift
54 /* 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
55 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 */
56 // Used in CFNetwork too
58 /* sSharesSources holds two mappings, one the inverse of the other, between a stream and the
59 RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than
60 one loop or mode, it can't share RunLoopSources with others, and is not in this dict.
62 static CFSpinLock_t sSourceLock
= CFSpinLockInit
;
63 static CFMutableDictionaryRef sSharedSources
= NULL
;
65 static CFTypeID __kCFReadStreamTypeID
= _kCFRuntimeNotATypeID
;
66 static CFTypeID __kCFWriteStreamTypeID
= _kCFRuntimeNotATypeID
;
68 // Just reads the bits, for those cases where we don't want to go through any callback checking
69 #define __CFStreamGetStatus(x) __CFBitfieldGetValue((x)->flags, MAX_STATUS_CODE_BIT, MIN_STATUS_CODE_BIT)
71 static void _CFStreamSignalEventSynch(void* info
);
72 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
);
73 static Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
);
74 static void _wakeUpRunLoop(struct _CFStream
*stream
);
76 CF_INLINE
const struct _CFStreamCallBacks
*_CFStreamGetCallBackPtr(struct _CFStream
*stream
) {
77 return stream
->callBacks
;
80 CF_INLINE
void _CFStreamSetStatusCode(struct _CFStream
*stream
, CFStreamStatus newStatus
) {
81 CFStreamStatus status
= __CFStreamGetStatus(stream
);
82 if (((status
!= kCFStreamStatusClosed
) && (status
!= kCFStreamStatusError
)) ||
83 ((status
== kCFStreamStatusClosed
) && (newStatus
== kCFStreamStatusError
)))
85 __CFBitfieldSetValue(stream
->flags
, MAX_STATUS_CODE_BIT
, MIN_STATUS_CODE_BIT
, newStatus
);
89 CF_INLINE
void _CFStreamScheduleEvent(struct _CFStream
*stream
, CFStreamEventType event
) {
90 if (stream
->client
&& (stream
->client
->when
& event
) && stream
->client
->rlSource
) {
91 stream
->client
->whatToSignal
|= event
;
92 CFRunLoopSourceSignal(stream
->client
->rlSource
);
93 _wakeUpRunLoop(stream
);
97 CF_INLINE
void _CFStreamSetStreamError(struct _CFStream
*stream
, CFStreamError
*err
) {
99 stream
->error
= (CFErrorRef
)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(CFStreamError
), 0);
101 memmove(stream
->error
, err
, sizeof(CFStreamError
));
104 static CFStringRef
__CFStreamCopyDescription(CFTypeRef cf
) {
105 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
106 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
107 CFStringRef contextDescription
;
109 if (cb
->copyDescription
) {
110 if (cb
->version
== 0) {
111 contextDescription
= ((CFStringRef(*)(void *))cb
->copyDescription
)(_CFStreamGetInfoPointer(stream
));
113 contextDescription
= cb
->copyDescription(stream
, _CFStreamGetInfoPointer(stream
));
116 contextDescription
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream
));
118 if (CFGetTypeID(cf
) == __kCFReadStreamTypeID
) {
119 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFReadStream %p>{%@}"), stream
, contextDescription
);
121 desc
= CFStringCreateWithFormat(CFGetAllocator(stream
), NULL
, CFSTR("<CFWriteStream %p>{%@}"), stream
, contextDescription
);
123 CFRelease(contextDescription
);
127 __private_extern__
void _CFStreamClose(struct _CFStream
*stream
) {
128 CFStreamStatus status
= _CFStreamGetStatus(stream
);
129 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
130 if (status
== kCFStreamStatusNotOpen
|| status
== kCFStreamStatusClosed
|| (status
== kCFStreamStatusError
&& __CFBitIsSet(stream
->flags
, HAVE_CLOSED
))) {
131 // Stream is not open from the client's perspective; do not callout and do not update our status to "closed"
134 __CFBitSet(stream
->flags
, HAVE_CLOSED
);
135 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
137 cb
->close(stream
, _CFStreamGetInfoPointer(stream
));
139 if (stream
->client
&& stream
->client
->rlSource
) {
141 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
142 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
143 CFRelease(stream
->client
->rlSource
);
144 stream
->client
->rlSource
= NULL
;
149 CFMutableArrayRef list
;
152 __CFSpinLock(&sSourceLock
);
154 key
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
155 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
157 c
= CFArrayGetCount(list
);
158 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
159 if (i
!= kCFNotFound
) {
160 CFArrayRemoveValueAtIndex(list
, i
);
164 CFAssert(CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, CFArrayGetCount(list
)), stream
) == kCFNotFound
, __kCFLogAssertion
, "CFStreamClose: stream found twice in its shared source's list");
167 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
168 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
169 CFDictionaryRemoveValue(sSharedSources
, key
);
172 CFDictionaryRemoveValue(sSharedSources
, stream
);
174 CFRelease(stream
->client
->rlSource
);
175 stream
->client
->rlSource
= NULL
;
176 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
178 __CFSpinUnlock(&sSourceLock
);
181 _CFStreamSetStatusCode(stream
, kCFStreamStatusClosed
);
182 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
185 //static int numStreamInstances = 0;
187 static void __CFStreamDeallocate(CFTypeRef cf
) {
188 struct _CFStream
*stream
= (struct _CFStream
*)cf
;
189 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
190 CFAllocatorRef alloc
= CFGetAllocator(stream
);
191 // numStreamInstances --;
194 _CFStreamClose(stream
);
196 if (stream
->client
) {
197 CFStreamClientContext
*cbContext
;
198 cbContext
= &(stream
->client
->cbContext
);
199 if (cbContext
->info
&& cbContext
->release
) {
200 cbContext
->release(cbContext
->info
);
202 if (stream
->client
->rlSource
) {
203 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
204 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
205 CFRelease(stream
->client
->rlSource
);
206 stream
->client
->rlSource
= NULL
;
211 CFMutableArrayRef list
;
214 __CFSpinLock(&sSourceLock
);
216 key
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
217 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
219 c
= CFArrayGetCount(list
);
220 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
221 if (i
!= kCFNotFound
) {
222 CFArrayRemoveValueAtIndex(list
, i
);
227 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
228 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
229 CFDictionaryRemoveValue(sSharedSources
, key
);
232 CFDictionaryRemoveValue(sSharedSources
, stream
);
234 CFRelease(stream
->client
->rlSource
);
235 stream
->client
->rlSource
= NULL
;
236 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
238 __CFSpinUnlock(&sSourceLock
);
241 if (stream
->client
->runLoopsAndModes
) {
242 CFRelease(stream
->client
->runLoopsAndModes
);
245 CFAllocatorDeallocate(alloc
, stream
->client
);
246 stream
->client
= NULL
; // Just in case finalize, below, calls back in to us
249 if (cb
->version
== 0) {
250 ((void(*)(void *))cb
->finalize
)(_CFStreamGetInfoPointer(stream
));
252 cb
->finalize(stream
, _CFStreamGetInfoPointer(stream
));
256 if (cb
->version
< 2) {
257 CFAllocatorDeallocate(alloc
, stream
->error
);
259 CFRelease(stream
->error
);
262 if (!__CFBitIsSet(stream
->flags
, CONSTANT_CALLBACKS
)) {
263 CFAllocatorDeallocate(alloc
, (void *)stream
->callBacks
);
267 static const CFRuntimeClass __CFReadStreamClass
= {
272 __CFStreamDeallocate
,
275 NULL
, // copyHumanDesc
276 __CFStreamCopyDescription
279 static const CFRuntimeClass __CFWriteStreamClass
= {
284 __CFStreamDeallocate
,
287 NULL
, // copyHumanDesc
288 __CFStreamCopyDescription
291 CONST_STRING_DECL(kCFStreamPropertySocketNativeHandle
, "kCFStreamPropertySocketNativeHandle")
292 CONST_STRING_DECL(kCFStreamPropertySocketRemoteHostName
, "kCFStreamPropertySocketRemoteHostName")
293 CONST_STRING_DECL(kCFStreamPropertySocketRemotePortNumber
, "kCFStreamPropertySocketRemotePortNumber")
294 CONST_STRING_DECL(kCFStreamPropertyDataWritten
, "kCFStreamPropertyDataWritten")
295 CONST_STRING_DECL(kCFStreamPropertyAppendToFile
, "kCFStreamPropertyAppendToFile")
297 __private_extern__
void __CFStreamInitialize(void) {
298 __kCFReadStreamTypeID
= _CFRuntimeRegisterClass(&__CFReadStreamClass
);
299 __kCFWriteStreamTypeID
= _CFRuntimeRegisterClass(&__CFWriteStreamClass
);
303 CF_EXPORT CFTypeID
CFReadStreamGetTypeID(void) {
304 return __kCFReadStreamTypeID
;
307 CF_EXPORT CFTypeID
CFWriteStreamGetTypeID(void) {
308 return __kCFWriteStreamTypeID
;
311 static struct _CFStream
*_CFStreamCreate(CFAllocatorRef allocator
, Boolean isReadStream
) {
312 struct _CFStream
*newStream
= (struct _CFStream
*)_CFRuntimeCreateInstance(allocator
, isReadStream
? __kCFReadStreamTypeID
: __kCFWriteStreamTypeID
, sizeof(struct _CFStream
) - sizeof(CFRuntimeBase
), NULL
);
314 // numStreamInstances ++;
315 newStream
->flags
= 0;
316 _CFStreamSetStatusCode(newStream
, kCFStreamStatusNotOpen
);
317 newStream
->error
= NULL
;
318 newStream
->client
= NULL
;
319 newStream
->info
= NULL
;
320 newStream
->callBacks
= NULL
;
325 __private_extern__
struct _CFStream
*_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc
, void *info
, const struct _CFStreamCallBacks
*cb
, Boolean isReading
) {
326 struct _CFStream
*newStream
;
327 if (cb
->version
!= 1) return NULL
;
328 newStream
= _CFStreamCreate(alloc
, isReading
);
330 __CFBitSet(newStream
->flags
, CONSTANT_CALLBACKS
);
331 newStream
->callBacks
= cb
;
333 newStream
->info
= cb
->create(newStream
, info
);
335 newStream
->info
= info
;
341 CF_EXPORT
void _CFStreamSetInfoPointer(struct _CFStream
*stream
, void *info
, const struct _CFStreamCallBacks
*cb
) {
342 if (info
!= stream
->info
) {
343 if (stream
->callBacks
->finalize
) {
344 stream
->callBacks
->finalize(stream
, stream
->info
);
347 stream
->info
= cb
->create(stream
, info
);
352 stream
->callBacks
= cb
;
356 CF_EXPORT CFReadStreamRef
CFReadStreamCreate(CFAllocatorRef alloc
, const CFReadStreamCallBacks
*callbacks
, void *info
) {
357 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, TRUE
);
358 struct _CFStreamCallBacks
*cb
;
359 if (!newStream
) return NULL
;
360 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
362 CFRelease(newStream
);
365 if (callbacks
->version
== 0) {
366 CFReadStreamCallBacksV0
*cbV0
= (CFReadStreamCallBacksV0
*)callbacks
;
367 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
368 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
370 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
371 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
372 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
373 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
374 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
375 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV0
->read
;
376 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV0
->getBuffer
;
377 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV0
->canRead
;
380 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
381 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
382 cb
->setProperty
= NULL
;
383 cb
->requestEvents
= NULL
;
384 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
385 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
386 } else if (callbacks
->version
== 1) {
387 CFReadStreamCallBacksV1
*cbV1
= (CFReadStreamCallBacksV1
*)callbacks
;
388 newStream
->info
= cbV1
->create
? cbV1
->create((CFReadStreamRef
)newStream
, info
) : info
;
390 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
391 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
392 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
393 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
394 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
395 cb
->read
= (CFIndex (*)(CFReadStreamRef
, UInt8
*, CFIndex
, CFErrorRef
*, Boolean
*, void *))cbV1
->read
;
396 cb
->getBuffer
= (const UInt8
*(*)(CFReadStreamRef
, CFIndex
, CFIndex
*, CFErrorRef
*, Boolean
*, void *))cbV1
->getBuffer
;
397 cb
->canRead
= (Boolean (*)(CFReadStreamRef
, CFErrorRef
*, void*))cbV1
->canRead
;
400 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
401 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
402 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
403 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
404 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
405 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
407 newStream
->info
= callbacks
->create
? callbacks
->create((CFReadStreamRef
)newStream
, info
) : info
;
409 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
410 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
411 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
412 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
413 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
414 cb
->read
= callbacks
->read
;
415 cb
->getBuffer
= callbacks
->getBuffer
;
416 cb
->canRead
= callbacks
->canRead
;
419 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
420 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
421 cb
->setProperty
= (Boolean(*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
422 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
423 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
424 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
427 newStream
->callBacks
= cb
;
428 return (CFReadStreamRef
)newStream
;
431 CF_EXPORT CFWriteStreamRef
CFWriteStreamCreate(CFAllocatorRef alloc
, const CFWriteStreamCallBacks
*callbacks
, void *info
) {
432 struct _CFStream
*newStream
= _CFStreamCreate(alloc
, FALSE
);
433 struct _CFStreamCallBacks
*cb
;
434 if (!newStream
) return NULL
;
435 cb
= (struct _CFStreamCallBacks
*)CFAllocatorAllocate(alloc
, sizeof(struct _CFStreamCallBacks
), 0);
437 CFRelease(newStream
);
440 if (callbacks
->version
== 0) {
441 CFWriteStreamCallBacksV0
*cbV0
= (CFWriteStreamCallBacksV0
*)callbacks
;
442 CFStreamClientContext
*ctxt
= (CFStreamClientContext
*)info
;
443 newStream
->info
= ctxt
->retain
? (void *)ctxt
->retain(ctxt
->info
) : ctxt
->info
;
445 cb
->create
= (void *(*)(struct _CFStream
*, void *))ctxt
->retain
;
446 cb
->finalize
= (void(*)(struct _CFStream
*, void *))ctxt
->release
;
447 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))ctxt
->copyDescription
;
448 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV0
->open
;
449 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV0
->openCompleted
;
451 cb
->getBuffer
= NULL
;
453 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV0
->write
;
454 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV0
->canWrite
;
455 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV0
->close
;
456 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV0
->copyProperty
;
457 cb
->setProperty
= NULL
;
458 cb
->requestEvents
= NULL
;
459 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->schedule
;
460 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV0
->unschedule
;
461 } else if (callbacks
->version
== 1) {
462 CFWriteStreamCallBacksV1
*cbV1
= (CFWriteStreamCallBacksV1
*)callbacks
;
464 newStream
->info
= cbV1
->create
? cbV1
->create((CFWriteStreamRef
)newStream
, info
) : info
;
465 cb
->create
= (void *(*)(struct _CFStream
*, void *))cbV1
->create
;
466 cb
->finalize
= (void(*)(struct _CFStream
*, void *))cbV1
->finalize
;
467 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))cbV1
->copyDescription
;
468 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))cbV1
->open
;
469 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))cbV1
->openCompleted
;
471 cb
->getBuffer
= NULL
;
473 cb
->write
= (CFIndex(*)(CFWriteStreamRef stream
, const UInt8
*buffer
, CFIndex bufferLength
, CFErrorRef
*error
, void *info
))cbV1
->write
;
474 cb
->canWrite
= (Boolean(*)(CFWriteStreamRef stream
, CFErrorRef
*error
, void *info
))cbV1
->canWrite
;
475 cb
->close
= (void (*)(struct _CFStream
*, void *))cbV1
->close
;
476 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))cbV1
->copyProperty
;
477 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))cbV1
->setProperty
;
478 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))cbV1
->requestEvents
;
479 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->schedule
;
480 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))cbV1
->unschedule
;
482 cb
->version
= callbacks
->version
;
483 newStream
->info
= callbacks
->create
? callbacks
->create((CFWriteStreamRef
)newStream
, info
) : info
;
484 cb
->create
= (void *(*)(struct _CFStream
*, void *))callbacks
->create
;
485 cb
->finalize
= (void(*)(struct _CFStream
*, void *))callbacks
->finalize
;
486 cb
->copyDescription
= (CFStringRef(*)(struct _CFStream
*, void *))callbacks
->copyDescription
;
487 cb
->open
= (Boolean(*)(struct _CFStream
*, CFErrorRef
*, Boolean
*, void *))callbacks
->open
;
488 cb
->openCompleted
= (Boolean (*)(struct _CFStream
*, CFErrorRef
*, void *))callbacks
->openCompleted
;
490 cb
->getBuffer
= NULL
;
492 cb
->write
= callbacks
->write
;
493 cb
->canWrite
= callbacks
->canWrite
;
494 cb
->close
= (void (*)(struct _CFStream
*, void *))callbacks
->close
;
495 cb
->copyProperty
= (CFTypeRef (*)(struct _CFStream
*, CFStringRef
, void *))callbacks
->copyProperty
;
496 cb
->setProperty
= (Boolean (*)(struct _CFStream
*, CFStringRef
, CFTypeRef
, void *))callbacks
->setProperty
;
497 cb
->requestEvents
= (void(*)(struct _CFStream
*, CFOptionFlags
, void *))callbacks
->requestEvents
;
498 cb
->schedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->schedule
;
499 cb
->unschedule
= (void (*)(struct _CFStream
*, CFRunLoopRef
, CFStringRef
, void *))callbacks
->unschedule
;
501 newStream
->callBacks
= cb
;
502 return (CFWriteStreamRef
)newStream
;
505 static void _CFStreamSignalEventSynch(void* info
) {
507 struct _CFStream
*stream
= NULL
;
508 CFOptionFlags eventMask
, whatToSignal
= 0;
510 if (CFGetTypeID((CFTypeRef
)info
) != CFArrayGetTypeID()) {
511 stream
= (struct _CFStream
*)info
;
512 whatToSignal
= stream
->client
->whatToSignal
;
513 stream
->client
->whatToSignal
= 0;
517 CFMutableArrayRef list
= (CFMutableArrayRef
)info
;
520 __CFSpinLock(&sSourceLock
);
522 c
= CFArrayGetCount(list
);
523 for (i
= 0; i
< c
; i
++) {
524 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
525 if (s
->client
->whatToSignal
) {
527 whatToSignal
= stream
->client
->whatToSignal
;
528 s
->client
->whatToSignal
= 0;
534 struct _CFStream
* s
= (struct _CFStream
*)CFArrayGetValueAtIndex(list
, i
);
535 if (s
->client
->whatToSignal
) {
536 CFRunLoopSourceSignal(s
->client
->rlSource
);
542 __CFSpinUnlock(&sSourceLock
);
548 CFRetain(stream
); // In case the client releases the stream while we're still in the for loop....
550 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
552 for (eventMask
= 1; eventMask
<= whatToSignal
; eventMask
= eventMask
<< 1) {
553 if ((eventMask
& whatToSignal
) && (stream
->client
->when
& eventMask
)) {
554 stream
->client
->cb(stream
, eventMask
, stream
->client
->cbContext
.info
);
558 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
563 // 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
564 // are likely to signal the same run loop over and over again. Don't know if we should worry about that.
565 static void _wakeUpRunLoop(struct _CFStream
*stream
) {
566 CFRunLoopRef rl
= NULL
;
569 if (!stream
->client
|| !stream
->client
->runLoopsAndModes
) return;
570 rlArray
= stream
->client
->runLoopsAndModes
;
571 cnt
= CFArrayGetCount(rlArray
);
572 if (cnt
== 0) return;
574 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
576 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
577 for (idx
= 2; NULL
!= rl
&& idx
< cnt
; idx
+=2) {
578 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
579 if (value
!= rl
) rl
= NULL
;
581 if (NULL
== rl
) { /* more than one different rl, so we must pick one */
582 for (idx
= 0; idx
< cnt
; idx
+=2) {
583 CFRunLoopRef value
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, idx
);
584 CFStringRef currentMode
= CFRunLoopCopyCurrentMode(value
);
585 if (NULL
!= currentMode
&& CFEqual(currentMode
, CFArrayGetValueAtIndex(rlArray
, idx
+1)) && CFRunLoopIsWaiting(value
)) {
586 CFRelease(currentMode
);
590 if (NULL
!= currentMode
) CFRelease(currentMode
);
592 if (NULL
== rl
) { /* didn't choose one above, so choose first */
593 rl
= (CFRunLoopRef
)CFArrayGetValueAtIndex(rlArray
, 0);
597 if (NULL
!= rl
&& CFRunLoopIsWaiting(rl
)) CFRunLoopWakeUp(rl
);
600 __private_extern__
void _CFStreamSignalEvent(struct _CFStream
*stream
, CFStreamEventType event
, CFErrorRef error
, Boolean synchronousAllowed
) {
601 // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop.
602 CFStreamStatus status
= __CFStreamGetStatus(stream
);
604 // Sanity check the event
605 if (status
== kCFStreamStatusNotOpen
) {
606 // No events allowed; this is almost certainly a bug in the stream's implementation
607 CFLog(__kCFLogAssertion
, CFSTR("Stream %p is sending an event before being opened"), stream
);
609 } else if (status
== kCFStreamStatusClosed
|| status
== kCFStreamStatusError
) {
610 // no further events are allowed
612 } else if (status
== kCFStreamStatusAtEnd
) {
613 // Only error events are allowed
614 event
&= kCFStreamEventErrorOccurred
;
615 } else if (status
!= kCFStreamStatusOpening
) {
616 // cannot send open completed; that happened already
617 event
&= ~kCFStreamEventOpenCompleted
;
620 // Change status if appropriate
621 if (event
& kCFStreamEventOpenCompleted
&& status
== kCFStreamStatusOpening
) {
622 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
624 if (event
& kCFStreamEventEndEncountered
&& status
< kCFStreamStatusAtEnd
) {
625 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
627 if (event
& kCFStreamEventErrorOccurred
) {
628 if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
629 _CFStreamSetStreamError(stream
, (CFStreamError
*)error
);
631 CFAssert(error
, __kCFLogAssertion
, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!");
633 if (stream
->error
) CFRelease(stream
->error
);
634 stream
->error
= error
;
636 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
639 // Now signal any pertinent event
640 if (stream
->client
&& stream
->client
->rlSource
&& (stream
->client
->when
& event
)) {
642 Boolean signalNow
= FALSE
;
644 stream
->client
->whatToSignal
|= event
;
646 if (synchronousAllowed
&& !__CFBitIsSet(stream
->flags
, CALLING_CLIENT
)) {
648 CFRunLoopRef rl
= CFRunLoopGetCurrent();
649 CFStringRef mode
= CFRunLoopCopyCurrentMode(rl
);
652 if (CFRunLoopContainsSource(rl
, stream
->client
->rlSource
, mode
))
659 // Can call out safely right now
660 _CFStreamSignalEventSynch(stream
);
662 // Schedule for later delivery
663 CFRunLoopSourceSignal(stream
->client
->rlSource
);
664 _wakeUpRunLoop(stream
);
669 __private_extern__ CFStreamStatus
_CFStreamGetStatus(struct _CFStream
*stream
) {
670 CFStreamStatus status
= __CFStreamGetStatus(stream
);
671 // 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.
672 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
673 if (status
== kCFStreamStatusOpening
) {
674 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
675 if (cb
->openCompleted
) {
677 if (cb
->version
< 2) {
678 CFStreamError err
= {0, 0};
679 isComplete
= ((_CFStreamCBOpenCompletedV1
)(cb
->openCompleted
))(stream
, &err
, _CFStreamGetInfoPointer(stream
));
680 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
682 isComplete
= cb
->openCompleted(stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
685 if (!stream
->error
) {
686 status
= kCFStreamStatusOpen
;
688 status
= kCFStreamStatusError
;
690 _CFStreamSetStatusCode(stream
, status
);
691 if (status
== kCFStreamStatusOpen
) {
692 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
694 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
699 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
703 CF_EXPORT CFStreamStatus
CFReadStreamGetStatus(CFReadStreamRef stream
) {
704 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
705 return _CFStreamGetStatus((struct _CFStream
*)stream
);
708 CF_EXPORT CFStreamStatus
CFWriteStreamGetStatus(CFWriteStreamRef stream
) {
709 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamStatus
, stream
, "streamStatus");
710 return _CFStreamGetStatus((struct _CFStream
*)stream
);
713 static CFStreamError
_CFStreamGetStreamError(struct _CFStream
*stream
) {
714 CFStreamError result
;
715 if (!stream
->error
) {
718 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
719 CFStreamError
*streamError
= (CFStreamError
*)(stream
->error
);
720 result
.error
= streamError
->error
;
721 result
.domain
= streamError
->domain
;
723 result
= _CFStreamErrorFromError(stream
->error
);
728 CF_EXPORT CFStreamError
CFReadStreamGetError(CFReadStreamRef stream
) {
729 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
730 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
733 CF_EXPORT CFStreamError
CFWriteStreamGetError(CFWriteStreamRef stream
) {
734 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFStreamError
, stream
, "_cfStreamError");
735 return _CFStreamGetStreamError((struct _CFStream
*)stream
);
738 static CFErrorRef
_CFStreamCopyError(struct _CFStream
*stream
) {
739 if (!stream
->error
) {
741 } else if (_CFStreamGetCallBackPtr(stream
)->version
< 2) {
742 return _CFErrorFromStreamError(CFGetAllocator(stream
), (CFStreamError
*)(stream
->error
));
744 CFRetain(stream
->error
);
745 return stream
->error
;
749 CF_EXPORT CFErrorRef
CFReadStreamCopyError(CFReadStreamRef stream
) {
750 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, CFErrorRef
, stream
, "streamError");
751 return _CFStreamCopyError((struct _CFStream
*)stream
);
754 CF_EXPORT CFErrorRef
CFWriteStreamCopyError(CFWriteStreamRef stream
) {
755 return _CFStreamCopyError((struct _CFStream
*)stream
);
756 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, CFErrorRef
, stream
, "streamError");
759 __private_extern__ Boolean
_CFStreamOpen(struct _CFStream
*stream
) {
760 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
761 Boolean success
, openComplete
;
762 if (_CFStreamGetStatus(stream
) != kCFStreamStatusNotOpen
) {
765 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
766 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpening
);
768 if (cb
->version
< 2) {
769 CFStreamError err
= {0, 0};
770 success
= ((_CFStreamCBOpenV1
)(cb
->open
))(stream
, &err
, &openComplete
, _CFStreamGetInfoPointer(stream
));
771 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
773 success
= cb
->open(stream
, &(stream
->error
), &openComplete
, _CFStreamGetInfoPointer(stream
));
781 // 2957690 - Guard against the possibility that the stream has already signalled itself in to a later state (like AtEnd)
782 if (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
783 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
785 _CFStreamScheduleEvent(stream
, kCFStreamEventOpenCompleted
);
787 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
788 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
791 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
795 CF_EXPORT Boolean
CFReadStreamOpen(CFReadStreamRef stream
) {
796 if(CF_IS_OBJC(__kCFReadStreamTypeID
, stream
)) {
797 CF_OBJC_VOIDCALL0(stream
, "open");
800 return _CFStreamOpen((struct _CFStream
*)stream
);
803 CF_EXPORT Boolean
CFWriteStreamOpen(CFWriteStreamRef stream
) {
804 if(CF_IS_OBJC(__kCFWriteStreamTypeID
, stream
)) {
805 CF_OBJC_VOIDCALL0(stream
, "open");
808 return _CFStreamOpen((struct _CFStream
*)stream
);
811 CF_EXPORT
void CFReadStreamClose(CFReadStreamRef stream
) {
812 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, void, stream
, "close");
813 _CFStreamClose((struct _CFStream
*)stream
);
816 CF_EXPORT
void CFWriteStreamClose(CFWriteStreamRef stream
) {
817 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, void, stream
, "close");
818 _CFStreamClose((struct _CFStream
*)stream
);
821 CF_EXPORT Boolean
CFReadStreamHasBytesAvailable(CFReadStreamRef readStream
) {
822 CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID
, Boolean
, readStream
, "hasBytesAvailable");
823 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
824 CFStreamStatus status
= _CFStreamGetStatus(stream
);
825 const struct _CFStreamCallBacks
*cb
;
826 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
) {
829 cb
= _CFStreamGetCallBackPtr(stream
);
830 if (cb
->canRead
== NULL
) {
831 return TRUE
; // No way to know without trying....
834 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
835 if (cb
->version
< 2) {
836 result
= ((_CFStreamCBCanReadV1
)(cb
->canRead
))((CFReadStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
838 result
= cb
->canRead((CFReadStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
840 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
841 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
844 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
849 static void waitForOpen(struct _CFStream
*stream
);
850 CFIndex
CFReadStreamRead(CFReadStreamRef readStream
, UInt8
*buffer
, CFIndex bufferLength
) {
851 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, CFIndex
, readStream
, "read:maxLength:", buffer
, bufferLength
);
852 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
853 CFStreamStatus status
= _CFStreamGetStatus(stream
);
854 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
855 if (status
== kCFStreamStatusOpening
) {
856 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
858 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
859 status
= _CFStreamGetStatus(stream
);
862 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
864 } else if (status
== kCFStreamStatusAtEnd
) {
869 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
870 if (stream
->client
) {
871 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
873 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
874 if (cb
->version
< 2) {
875 CFStreamError err
= {0, 0};
876 bytesRead
= ((_CFStreamCBReadV1
)(cb
->read
))((CFReadStreamRef
)stream
, buffer
, bufferLength
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
877 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
879 bytesRead
= cb
->read((CFReadStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
883 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
884 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
886 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
887 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
889 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
891 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
896 CF_EXPORT
const UInt8
*CFReadStreamGetBuffer(CFReadStreamRef readStream
, CFIndex maxBytesToRead
, CFIndex
*numBytesRead
) {
897 if (CF_IS_OBJC(__kCFReadStreamTypeID
, readStream
)) {
898 uint8_t *bufPtr
= NULL
;
900 CF_OBJC_CALL2(Boolean
, gotBytes
, readStream
, "getBuffer:length:", &bufPtr
, numBytesRead
);
902 return (const UInt8
*)bufPtr
;
907 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
908 CFStreamStatus status
= _CFStreamGetStatus(stream
);
909 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
911 if (status
== kCFStreamStatusOpening
) {
912 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
914 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
915 status
= _CFStreamGetStatus(stream
);
917 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusReading
&& status
!= kCFStreamStatusAtEnd
) {
920 } else if (status
== kCFStreamStatusAtEnd
|| cb
->getBuffer
== NULL
) {
925 Boolean hadBytes
= stream
->client
&& (stream
->client
->whatToSignal
& kCFStreamEventHasBytesAvailable
);
926 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
928 stream
->client
->whatToSignal
&= ~kCFStreamEventHasBytesAvailable
;
930 _CFStreamSetStatusCode(stream
, kCFStreamStatusReading
);
931 if (cb
->version
< 2) {
932 CFStreamError err
= {0, 0};
933 buffer
= ((_CFStreamCBGetBufferV1
)(cb
->getBuffer
))((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &err
, &atEOF
, _CFStreamGetInfoPointer(stream
));
934 if (err
.error
!= 0) _CFStreamSetStreamError(stream
, &err
);
936 buffer
= cb
->getBuffer((CFReadStreamRef
)stream
, maxBytesToRead
, numBytesRead
, &(stream
->error
), &atEOF
, _CFStreamGetInfoPointer(stream
));
940 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
942 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
944 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
945 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
947 if (!buffer
&& hadBytes
) {
948 stream
->client
->whatToSignal
|= kCFStreamEventHasBytesAvailable
;
950 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
952 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
957 CF_EXPORT Boolean
CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream
) {
958 CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "hasSpaceAvailable");
959 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
960 CFStreamStatus status
= _CFStreamGetStatus(stream
);
961 const struct _CFStreamCallBacks
*cb
;
962 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
965 cb
= _CFStreamGetCallBackPtr(stream
);
966 if (cb
->canWrite
== NULL
) {
967 return TRUE
; // No way to know without trying....
970 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
971 if (cb
->version
< 2) {
972 result
= ((_CFStreamCBCanWriteV1
)(cb
->canWrite
))((CFWriteStreamRef
)stream
, _CFStreamGetInfoPointer(stream
));
974 result
= cb
->canWrite((CFWriteStreamRef
)stream
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
976 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
977 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
980 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
985 CF_EXPORT CFIndex
CFWriteStreamWrite(CFWriteStreamRef writeStream
, const UInt8
*buffer
, CFIndex bufferLength
) {
986 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, CFIndex
, writeStream
, "write:maxLength:", buffer
, bufferLength
);
987 struct _CFStream
*stream
= (struct _CFStream
*)writeStream
;
988 CFStreamStatus status
= _CFStreamGetStatus(stream
);
989 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
990 if (status
== kCFStreamStatusOpening
) {
991 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
993 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
994 status
= _CFStreamGetStatus(stream
);
996 if (status
!= kCFStreamStatusOpen
&& status
!= kCFStreamStatusWriting
) {
1000 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1001 _CFStreamSetStatusCode(stream
, kCFStreamStatusWriting
);
1002 if (stream
->client
) {
1003 stream
->client
->whatToSignal
&= ~kCFStreamEventCanAcceptBytes
;
1005 if (cb
->version
< 2) {
1006 CFStreamError err
= {0, 0};
1007 result
= ((_CFStreamCBWriteV1
)(cb
->write
))((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &err
, _CFStreamGetInfoPointer(stream
));
1008 if (err
.error
) _CFStreamSetStreamError(stream
, &err
);
1010 result
= cb
->write((CFWriteStreamRef
)stream
, buffer
, bufferLength
, &(stream
->error
), _CFStreamGetInfoPointer(stream
));
1012 if (stream
->error
) {
1013 _CFStreamSetStatusCode(stream
, kCFStreamStatusError
);
1014 _CFStreamScheduleEvent(stream
, kCFStreamEventErrorOccurred
);
1015 } else if (result
== 0) {
1016 _CFStreamSetStatusCode(stream
, kCFStreamStatusAtEnd
);
1017 _CFStreamScheduleEvent(stream
, kCFStreamEventEndEncountered
);
1019 _CFStreamSetStatusCode(stream
, kCFStreamStatusOpen
);
1021 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1026 __private_extern__ CFTypeRef
_CFStreamCopyProperty(struct _CFStream
*stream
, CFStringRef propertyName
) {
1027 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1028 if (cb
->copyProperty
== NULL
) {
1032 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1033 result
= cb
->copyProperty(stream
, propertyName
, _CFStreamGetInfoPointer(stream
));
1034 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1039 CF_EXPORT CFTypeRef
CFReadStreamCopyProperty(CFReadStreamRef stream
, CFStringRef propertyName
) {
1040 CF_OBJC_FUNCDISPATCH1(__kCFReadStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1041 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1044 CF_EXPORT CFTypeRef
CFWriteStreamCopyProperty(CFWriteStreamRef stream
, CFStringRef propertyName
) {
1045 CF_OBJC_FUNCDISPATCH1(__kCFWriteStreamTypeID
, CFTypeRef
, stream
, "propertyForKey:", propertyName
);
1046 return _CFStreamCopyProperty((struct _CFStream
*)stream
, propertyName
);
1049 __private_extern__ Boolean
_CFStreamSetProperty(struct _CFStream
*stream
, CFStringRef prop
, CFTypeRef val
) {
1050 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1051 if (cb
->setProperty
== NULL
) {
1055 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1056 result
= cb
->setProperty(stream
, prop
, val
, _CFStreamGetInfoPointer(stream
));
1057 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1063 Boolean
CFReadStreamSetProperty(CFReadStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1064 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1065 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1069 Boolean
CFWriteStreamSetProperty(CFWriteStreamRef stream
, CFStringRef propertyName
, CFTypeRef propertyValue
) {
1070 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, Boolean
, stream
, "setProperty:forKey:", propertyValue
, propertyName
);
1071 return _CFStreamSetProperty((struct _CFStream
*)stream
, propertyName
, propertyValue
);
1074 static void _initializeClient(struct _CFStream
*stream
) {
1075 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1076 if (!cb
->schedule
) return; // Do we wish to allow this?
1077 stream
->client
= (struct _CFStreamClient
*)CFAllocatorAllocate(CFGetAllocator(stream
), sizeof(struct _CFStreamClient
), 0);
1078 memset(stream
->client
, 0, sizeof(struct _CFStreamClient
));
1081 /* If we add a setClient callback to the concrete stream callbacks, we must set/clear CALLING_CLIENT around it */
1082 __private_extern__ Boolean
_CFStreamSetClient(struct _CFStream
*stream
, CFOptionFlags streamEvents
, void (*clientCB
)(struct _CFStream
*, CFStreamEventType
, void *), CFStreamClientContext
*clientCallBackContext
) {
1084 Boolean removingClient
= (streamEvents
== kCFStreamEventNone
|| clientCB
== NULL
|| clientCallBackContext
== NULL
);
1085 if (removingClient
) {
1087 streamEvents
= kCFStreamEventNone
;
1088 clientCallBackContext
= NULL
;
1090 if (!stream
->client
) {
1091 if (removingClient
) {
1092 // We have no client now, and we've been asked to add none???
1095 _initializeClient(stream
);
1096 if (!stream
->client
) {
1097 // Asynch not supported
1101 if (stream
->client
->cb
&& stream
->client
->cbContext
.release
) {
1102 stream
->client
->cbContext
.release(stream
->client
->cbContext
.info
);
1104 stream
->client
->cb
= clientCB
;
1105 if (clientCallBackContext
) {
1106 stream
->client
->cbContext
.version
= clientCallBackContext
->version
;
1107 stream
->client
->cbContext
.retain
= clientCallBackContext
->retain
;
1108 stream
->client
->cbContext
.release
= clientCallBackContext
->release
;
1109 stream
->client
->cbContext
.copyDescription
= clientCallBackContext
->copyDescription
;
1110 stream
->client
->cbContext
.info
= (clientCallBackContext
->retain
&& clientCallBackContext
->info
) ? clientCallBackContext
->retain(clientCallBackContext
->info
) : clientCallBackContext
->info
;
1112 stream
->client
->cbContext
.retain
= NULL
;
1113 stream
->client
->cbContext
.release
= NULL
;
1114 stream
->client
->cbContext
.copyDescription
= NULL
;
1115 stream
->client
->cbContext
.info
= NULL
;
1117 if (stream
->client
->when
!= streamEvents
) {
1118 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1119 stream
->client
->when
= streamEvents
;
1120 if (cb
->requestEvents
) {
1121 cb
->requestEvents(stream
, streamEvents
, _CFStreamGetInfoPointer(stream
));
1127 CF_EXPORT Boolean
CFReadStreamSetClient(CFReadStreamRef readStream
, CFOptionFlags streamEvents
, CFReadStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1128 CF_OBJC_FUNCDISPATCH3(__kCFReadStreamTypeID
, Boolean
, readStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
1129 streamEvents
&= ~kCFStreamEventCanAcceptBytes
;
1130 return _CFStreamSetClient((struct _CFStream
*)readStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1133 CF_EXPORT Boolean
CFWriteStreamSetClient(CFWriteStreamRef writeStream
, CFOptionFlags streamEvents
, CFWriteStreamClientCallBack clientCB
, CFStreamClientContext
*clientContext
) {
1134 CF_OBJC_FUNCDISPATCH3(__kCFWriteStreamTypeID
, Boolean
, writeStream
, "_setCFClientFlags:callback:context:", streamEvents
, clientCB
, clientContext
);
1135 streamEvents
&= ~kCFStreamEventHasBytesAvailable
;
1136 return _CFStreamSetClient((struct _CFStream
*)writeStream
, streamEvents
, (void (*)(struct _CFStream
*, CFStreamEventType
, void *))clientCB
, clientContext
);
1139 CF_INLINE
void *_CFStreamGetClient(struct _CFStream
*stream
) {
1140 if (stream
->client
) return stream
->client
->cbContext
.info
;
1144 CF_EXPORT
void *_CFReadStreamGetClient(CFReadStreamRef readStream
) {
1145 return _CFStreamGetClient((struct _CFStream
*)readStream
);
1148 CF_EXPORT
void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream
) {
1149 return _CFStreamGetClient((struct _CFStream
*)writeStream
);
1153 __private_extern__
void _CFStreamScheduleWithRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1154 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1156 if (!stream
->client
) {
1157 _initializeClient(stream
);
1158 if (!stream
->client
) return; // we don't support asynch.
1161 if (!stream
->client
->rlSource
) {
1164 CFMutableArrayRef list
;
1170 key
= CFArrayCreate(kCFAllocatorSystemDefault
, a
, sizeof(a
) / sizeof(a
[0]), &kCFTypeArrayCallBacks
);
1172 __CFSpinLock(&sSourceLock
);
1174 if (!sSharedSources
)
1175 sSharedSources
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1177 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
1179 stream
->client
->rlSource
= (CFRunLoopSourceRef
)CFRetain(((struct _CFStream
*)CFArrayGetValueAtIndex(list
, 0))->client
->rlSource
);
1183 CFRunLoopSourceContext ctxt
= {
1186 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1187 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1188 (CFStringRef(*)(const void *))CFCopyDescription
,
1193 (void(*)(void *))_CFStreamSignalEventSynch
1196 list
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1197 CFDictionaryAddValue(sSharedSources
, key
, list
);
1201 stream
->client
->rlSource
= CFRunLoopSourceCreate(CFGetAllocator(stream
), 0, &ctxt
);
1202 stream
->client
->whatToSignal
= 0;
1204 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1207 CFArrayAppendValue(list
, stream
);
1208 CFDictionaryAddValue(sSharedSources
, stream
, key
);
1213 __CFBitSet(stream
->flags
, SHARED_SOURCE
);
1215 __CFSpinUnlock(&sSourceLock
);
1217 else if (__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1220 CFMutableArrayRef list
;
1223 CFAllocatorRef alloc
= CFGetAllocator(stream
);
1224 CFRunLoopSourceContext ctxt
= {
1227 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1228 NULL
, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop
1229 (CFStringRef(*)(const void *))CFCopyDescription
,
1234 (void(*)(void *))_CFStreamSignalEventSynch
1237 __CFSpinLock(&sSourceLock
);
1239 key
= (CFArrayRef
)CFRetain((CFTypeRef
)CFDictionaryGetValue(sSharedSources
, stream
));
1240 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
1242 c
= CFArrayGetCount(list
);
1243 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
1244 if (i
!= kCFNotFound
) {
1245 CFArrayRemoveValueAtIndex(list
, i
);
1250 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
1251 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
1252 CFDictionaryRemoveValue(sSharedSources
, key
);
1255 CFDictionaryRemoveValue(sSharedSources
, stream
);
1257 CFRelease(stream
->client
->rlSource
);
1258 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1260 __CFSpinUnlock(&sSourceLock
);
1262 stream
->client
->rlSource
= CFRunLoopSourceCreate(alloc
, 0, &ctxt
);
1264 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(key
, 0), stream
->client
->rlSource
, (CFStringRef
)CFArrayGetValueAtIndex(key
, 1));
1268 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1270 CFRunLoopAddSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1273 if (!stream
->client
->runLoopsAndModes
) {
1274 stream
->client
->runLoopsAndModes
= CFArrayCreateMutable(CFGetAllocator(stream
), 0, &kCFTypeArrayCallBacks
);
1276 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoop
);
1277 CFArrayAppendValue(stream
->client
->runLoopsAndModes
, runLoopMode
);
1280 __CFBitSet(stream
->flags
, CALLING_CLIENT
);
1281 cb
->schedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1282 __CFBitClear(stream
->flags
, CALLING_CLIENT
);
1286 CF_EXPORT
void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1287 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1288 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1291 CF_EXPORT
void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1292 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_scheduleInCFRunLoop:forMode:", runLoop
, runLoopMode
);
1293 _CFStreamScheduleWithRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1297 __private_extern__
void _CFStreamUnscheduleFromRunLoop(struct _CFStream
*stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1298 const struct _CFStreamCallBacks
*cb
= _CFStreamGetCallBackPtr(stream
);
1299 if (!stream
->client
) return;
1300 if (!stream
->client
->rlSource
) return;
1302 if (!__CFBitIsSet(stream
->flags
, SHARED_SOURCE
)) {
1303 CFRunLoopRemoveSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1306 CFMutableArrayRef list
;
1309 __CFSpinLock(&sSourceLock
);
1311 key
= (CFArrayRef
)CFDictionaryGetValue(sSharedSources
, stream
);
1312 list
= (CFMutableArrayRef
)CFDictionaryGetValue(sSharedSources
, key
);
1314 c
= CFArrayGetCount(list
);
1315 i
= CFArrayGetFirstIndexOfValue(list
, CFRangeMake(0, c
), stream
);
1316 if (i
!= kCFNotFound
) {
1317 CFArrayRemoveValueAtIndex(list
, i
);
1322 CFRunLoopRemoveSource(runLoop
, stream
->client
->rlSource
, runLoopMode
);
1323 CFRunLoopSourceInvalidate(stream
->client
->rlSource
);
1324 CFDictionaryRemoveValue(sSharedSources
, key
);
1327 CFDictionaryRemoveValue(sSharedSources
, stream
);
1329 CFRelease(stream
->client
->rlSource
);
1330 stream
->client
->rlSource
= NULL
;
1331 __CFBitClear(stream
->flags
, SHARED_SOURCE
);
1333 __CFSpinUnlock(&sSourceLock
);
1336 _CFStreamRemoveRunLoopAndModeFromArray(stream
->client
->runLoopsAndModes
, runLoop
, runLoopMode
);
1338 if (cb
->unschedule
) {
1339 cb
->unschedule(stream
, runLoop
, runLoopMode
, _CFStreamGetInfoPointer(stream
));
1343 CF_EXPORT
void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1344 CF_OBJC_FUNCDISPATCH2(__kCFReadStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1345 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1348 void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
) {
1349 CF_OBJC_FUNCDISPATCH2(__kCFWriteStreamTypeID
, void, stream
, "_unscheduleFromCFRunLoop:forMode:", runLoop
, runLoopMode
);
1350 _CFStreamUnscheduleFromRunLoop((struct _CFStream
*)stream
, runLoop
, runLoopMode
);
1353 static void waitForOpen(struct _CFStream
*stream
) {
1354 CFRunLoopRef runLoop
= CFRunLoopGetCurrent();
1355 CFStringRef privateMode
= CFSTR("_kCFStreamBlockingOpenMode");
1356 _CFStreamScheduleWithRunLoop(stream
, runLoop
, privateMode
);
1357 // 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....
1358 while (__CFStreamGetStatus(stream
) == kCFStreamStatusOpening
) {
1359 CFRunLoopRunInMode(privateMode
, 1e+20, TRUE
);
1361 _CFStreamUnscheduleFromRunLoop(stream
, runLoop
, privateMode
);
1364 CF_INLINE CFArrayRef
_CFStreamGetRunLoopsAndModes(struct _CFStream
*stream
) {
1365 if (stream
->client
) return stream
->client
->runLoopsAndModes
;
1369 CF_EXPORT CFArrayRef
_CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream
) {
1370 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)readStream
);
1373 CF_EXPORT CFArrayRef
_CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream
) {
1374 return _CFStreamGetRunLoopsAndModes((struct _CFStream
*)writeStream
);
1377 CF_EXPORT
void CFReadStreamSignalEvent(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1378 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1381 CF_EXPORT
void CFWriteStreamSignalEvent(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1382 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, TRUE
);
1385 CF_EXPORT
void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream
, CFStreamEventType event
, const void *error
) {
1386 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1389 CF_EXPORT
void _CFReadStreamClearEvent(CFReadStreamRef readStream
, CFStreamEventType event
) {
1390 struct _CFStream
*stream
= (struct _CFStream
*)readStream
;
1391 if (stream
->client
) {
1392 stream
->client
->whatToSignal
&= ~event
;
1396 CF_EXPORT
void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream
, CFStreamEventType event
, const void *error
) {
1397 _CFStreamSignalEvent((struct _CFStream
*)stream
, event
, (CFErrorRef
)error
, FALSE
);
1400 CF_EXPORT
void *CFReadStreamGetInfoPointer(CFReadStreamRef stream
) {
1401 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1404 CF_EXPORT
void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream
) {
1405 return _CFStreamGetInfoPointer((struct _CFStream
*)stream
);
1409 void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1414 count
= CFArrayGetCount(runLoopsAndModes
);
1415 range
= CFRangeMake(0, count
);
1417 while (range
.length
) {
1419 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1421 if (i
== kCFNotFound
)
1424 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
))
1427 range
.location
= i
+ 2;
1428 range
.length
= count
- range
.location
;
1431 // Add the new values.
1432 CFArrayAppendValue(runLoopsAndModes
, runLoop
);
1433 CFArrayAppendValue(runLoopsAndModes
, runLoopMode
);
1435 // Schedule the source on the new loop and mode.
1437 CFRunLoopAddSource(runLoop
, source
, runLoopMode
);
1442 void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source
, CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef runLoop
, CFStringRef runLoopMode
)
1447 count
= CFArrayGetCount(runLoopsAndModes
);
1448 range
= CFRangeMake(0, count
);
1450 while (range
.length
) {
1452 CFIndex i
= CFArrayGetFirstIndexOfValue(runLoopsAndModes
, range
, runLoop
);
1454 // If not found, it's not scheduled on it.
1455 if (i
== kCFNotFound
)
1458 // Make sure it is scheduled in this mode.
1459 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1), runLoopMode
)) {
1461 // Remove mode and runloop from the list.
1462 CFArrayReplaceValues(runLoopsAndModes
, CFRangeMake(i
, 2), NULL
, 0);
1464 // Remove it from the runloop.
1466 CFRunLoopRemoveSource(runLoop
, source
, runLoopMode
);
1471 range
.location
= i
+ 2;
1472 range
.length
= count
- range
.location
;
1478 void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1480 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1485 for (i
= 0; i
< count
; i
+= 2) {
1487 // Make sure it's scheduled on all the right loops and modes.
1488 // Go through the array adding the source to all loops and modes.
1489 CFRunLoopAddSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1491 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1497 void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source
, CFArrayRef runLoopsAndModes
)
1499 CFIndex i
, count
= CFArrayGetCount(runLoopsAndModes
);
1504 for (i
= 0; i
< count
; i
+= 2) {
1506 // Go through the array removing the source from all loops and modes.
1507 CFRunLoopRemoveSource((CFRunLoopRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
),
1509 (CFStringRef
)CFArrayGetValueAtIndex(runLoopsAndModes
, i
+ 1));
1513 Boolean
_CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes
, CFRunLoopRef rl
, CFStringRef mode
) {
1515 Boolean found
= FALSE
;
1517 if (!runLoopsAndModes
) return FALSE
;
1519 cnt
= CFArrayGetCount(runLoopsAndModes
);
1520 for (idx
= 0; idx
+ 1 < cnt
; idx
+= 2) {
1521 if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
), rl
) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes
, idx
+ 1), mode
)) {
1522 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1523 CFArrayRemoveValueAtIndex(runLoopsAndModes
, idx
);
1531 // Used by NSStream to properly allocate the bridged objects
1532 CF_EXPORT CFIndex
_CFStreamInstanceSize(void) {
1533 return sizeof(struct _CFStream
);