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 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #if (DEPLOYMENT_TARGET_MACOSX) || defined(__WIN32__)
30 #include <CoreFoundation/CFRunLoop.h>
31 #include <CoreFoundation/CFSet.h>
32 #include <CoreFoundation/CFBag.h>
33 #include "CFInternal.h"
37 #if DEPLOYMENT_TARGET_MACOSX
38 #include <mach/mach.h>
39 #include <mach/clock_types.h>
40 #include <mach/clock.h>
44 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
45 // With the MS headers, turning off Standard-C gets you macros for stat vs _stat.
46 // Strictly speaking, this is supposed to control traditional vs ANSI C features.
52 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
57 static int _LogCFRunLoop
= 0;
60 static pthread_t kNilPthreadT
= { nil
, nil
};
61 #define pthreadPointer(a) a.p
62 #define lockCount(a) a.LockCount
64 static pthread_t kNilPthreadT
= (pthread_t
)0;
65 #define pthreadPointer(a) a
66 #define lockCount(a) a
70 #if DEPLOYMENT_TARGET_MACOSX
71 #include <sys/types.h>
72 #include <sys/event.h>
77 const void *(*retain
)(const void *info
);
78 void (*release
)(const void *info
);
79 CFStringRef (*copyDescription
)(const void *info
);
80 Boolean (*equal
)(const void *info1
, const void *info2
);
81 CFHashCode (*hash
)(const void *info
);
82 void (*perform
)(const struct kevent
*kev
, void *info
);
84 } CFRunLoopSourceContext2
;
86 // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR.
87 // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop.
88 // There is no way to EV_ENABLE or EV_DISABLE a kevent.
89 // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet.
90 // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet.
91 // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos).
94 extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict
, const void *key
, const void **actualkey
);
96 // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a
97 // simple abstraction layer spanning Mach ports and Windows HANDLES
98 #if DEPLOYMENT_TARGET_MACOSX
100 typedef mach_port_t __CFPort
;
101 #define CFPORT_NULL MACH_PORT_NULL
102 typedef mach_port_t __CFPortSet
;
104 static __CFPort
__CFPortAllocate(void) {
107 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &result
);
108 if (KERN_SUCCESS
== ret
) {
109 ret
= mach_port_insert_right(mach_task_self(), result
, result
, MACH_MSG_TYPE_MAKE_SEND
);
111 if (KERN_SUCCESS
== ret
) {
112 mach_port_limits_t limits
;
113 limits
.mpl_qlimit
= 1;
114 ret
= mach_port_set_attributes(mach_task_self(), result
, MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, MACH_PORT_LIMITS_INFO_COUNT
);
116 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
119 CF_INLINE
void __CFPortFree(__CFPort port
) {
120 mach_port_destroy(mach_task_self(), port
);
123 CF_INLINE __CFPortSet
__CFPortSetAllocate(void) {
125 kern_return_t ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET
, &result
);
126 return (KERN_SUCCESS
== ret
) ? result
: CFPORT_NULL
;
129 CF_INLINE Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
130 kern_return_t ret
= mach_port_insert_member(mach_task_self(), port
, portSet
);
131 return (KERN_SUCCESS
== ret
);
134 CF_INLINE Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
135 kern_return_t ret
= mach_port_extract_member(mach_task_self(), port
, portSet
);
136 return (KERN_SUCCESS
== ret
);
139 CF_INLINE
void __CFPortSetFree(__CFPortSet portSet
) {
141 mach_port_name_array_t array
;
142 mach_msg_type_number_t idx
, number
;
144 ret
= mach_port_get_set_status(mach_task_self(), portSet
, &array
, &number
);
145 if (KERN_SUCCESS
== ret
) {
146 for (idx
= 0; idx
< number
; idx
++) {
147 mach_port_extract_member(mach_task_self(), array
[idx
], portSet
);
149 vm_deallocate(mach_task_self(), (vm_address_t
)array
, number
* sizeof(mach_port_name_t
));
151 mach_port_destroy(mach_task_self(), portSet
);
154 #elif defined(__WIN32__)
156 typedef HANDLE __CFPort
;
157 #define CFPORT_NULL NULL
159 // A simple dynamic array of HANDLEs, which grows to a high-water mark
160 typedef struct ___CFPortSet
{
164 CFSpinLock_t lock
; // insert and remove must be thread safe, like the Mach calls
167 CF_INLINE __CFPort
__CFPortAllocate(void) {
168 return CreateEvent(NULL
, true, false, NULL
);
171 CF_INLINE
void __CFPortFree(__CFPort port
) {
175 static __CFPortSet
__CFPortSetAllocate(void) {
176 __CFPortSet result
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct ___CFPortSet
), 0);
179 result
->handles
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, result
->size
* sizeof(HANDLE
), 0);
180 CF_SPINLOCK_INIT_FOR_STRUCTS(result
->lock
);
184 static void __CFPortSetFree(__CFPortSet portSet
) {
185 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
->handles
);
186 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, portSet
);
189 // Returns portBuf if ports fit in that space, else returns another ptr that must be freed
190 static __CFPort
*__CFPortSetGetPorts(__CFPortSet portSet
, __CFPort
*portBuf
, uint32_t bufSize
, uint32_t *portsUsed
) {
191 __CFSpinLock(&(portSet
->lock
));
192 __CFPort
*result
= portBuf
;
193 if (bufSize
> portSet
->used
)
194 result
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, portSet
->used
* sizeof(HANDLE
), 0);
195 memmove(result
, portSet
->handles
, portSet
->used
* sizeof(HANDLE
));
196 *portsUsed
= portSet
->used
;
197 __CFSpinUnlock(&(portSet
->lock
));
201 static Boolean
__CFPortSetInsert(__CFPort port
, __CFPortSet portSet
) {
202 __CFSpinLock(&(portSet
->lock
));
203 if (portSet
->used
>= portSet
->size
) {
205 portSet
->handles
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, portSet
->handles
, portSet
->size
* sizeof(HANDLE
), 0);
207 if (portSet
->used
>= MAXIMUM_WAIT_OBJECTS
)
208 CFLog(kCFLogLevelWarning
, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS
);
209 portSet
->handles
[portSet
->used
++] = port
;
210 __CFSpinUnlock(&(portSet
->lock
));
214 static Boolean
__CFPortSetRemove(__CFPort port
, __CFPortSet portSet
) {
216 __CFSpinLock(&(portSet
->lock
));
217 for (i
= 0; i
< portSet
->used
; i
++) {
218 if (portSet
->handles
[i
] == port
) {
219 for (j
= i
+1; j
< portSet
->used
; j
++) {
220 portSet
->handles
[j
-1] = portSet
->handles
[j
];
223 __CFSpinUnlock(&(portSet
->lock
));
227 __CFSpinUnlock(&(portSet
->lock
));
233 #if DEPLOYMENT_TARGET_MACOSX
234 extern mach_port_name_t
mk_timer_create(void);
235 extern kern_return_t
mk_timer_destroy(mach_port_name_t name
);
236 extern kern_return_t
mk_timer_arm(mach_port_name_t name
, AbsoluteTime expire_time
);
237 extern kern_return_t
mk_timer_cancel(mach_port_name_t name
, AbsoluteTime
*result_time
);
239 CF_INLINE AbsoluteTime
__CFUInt64ToAbsoluteTime(int64_t x
) {
242 a
.lo
= x
& (int64_t)0xFFFFFFFF;
246 static uint32_t __CFSendTrivialMachMessage(mach_port_t port
, uint32_t msg_id
, CFOptionFlags options
, uint32_t timeout
) {
247 kern_return_t result
;
248 mach_msg_header_t header
;
249 header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
250 header
.msgh_size
= sizeof(mach_msg_header_t
);
251 header
.msgh_remote_port
= port
;
252 header
.msgh_local_port
= MACH_PORT_NULL
;
253 header
.msgh_id
= msg_id
;
254 result
= mach_msg(&header
, MACH_SEND_MSG
|options
, header
.msgh_size
, 0, MACH_PORT_NULL
, timeout
, MACH_PORT_NULL
);
255 if (result
== MACH_SEND_TIMED_OUT
) mach_msg_destroy(&header
);
260 /* unlock a run loop and modes before doing callouts/sleeping */
261 /* never try to take the run loop lock with a mode locked */
262 /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */
263 /* run loop mode structures should never be deallocated, even if they become empty */
265 static CFTypeID __kCFRunLoopModeTypeID
= _kCFRuntimeNotATypeID
;
266 static CFTypeID __kCFRunLoopTypeID
= _kCFRuntimeNotATypeID
;
267 static CFTypeID __kCFRunLoopSourceTypeID
= _kCFRuntimeNotATypeID
;
268 static CFTypeID __kCFRunLoopObserverTypeID
= _kCFRuntimeNotATypeID
;
269 static CFTypeID __kCFRunLoopTimerTypeID
= _kCFRuntimeNotATypeID
;
271 typedef struct __CFRunLoopMode
*CFRunLoopModeRef
;
273 struct __CFRunLoopMode
{
275 CFSpinLock_t _lock
; /* must have the run loop locked before locking this */
279 CFMutableSetRef _sources
;
280 CFMutableSetRef _observers
;
281 CFMutableSetRef _timers
;
282 CFMutableArrayRef _submodes
; // names of the submodes
283 __CFPortSet _portSet
;
284 #if DEPLOYMENT_TARGET_MACOSX
289 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
);
291 CF_INLINE
void __CFRunLoopModeLock(CFRunLoopModeRef rlm
) {
292 __CFSpinLock(&(rlm
->_lock
));
295 CF_INLINE
void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm
) {
296 __CFSpinUnlock(&(rlm
->_lock
));
299 static Boolean
__CFRunLoopModeEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
300 CFRunLoopModeRef rlm1
= (CFRunLoopModeRef
)cf1
;
301 CFRunLoopModeRef rlm2
= (CFRunLoopModeRef
)cf2
;
302 return CFEqual(rlm1
->_name
, rlm2
->_name
);
305 static CFHashCode
__CFRunLoopModeHash(CFTypeRef cf
) {
306 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
307 return CFHash(rlm
->_name
);
310 static CFStringRef
__CFRunLoopModeCopyDescription(CFTypeRef cf
) {
311 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
312 CFMutableStringRef result
;
313 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
314 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm
, CFGetAllocator(rlm
), rlm
->_name
, lockCount(rlm
->_lock
) ? "true" : "false");
315 CFStringAppendFormat(result
, NULL
, CFSTR("port set = %p,"), rlm
->_portSet
);
316 CFStringAppendFormat(result
, NULL
, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm
->_sources
, rlm
->_observers
, rlm
->_timers
);
320 static void __CFRunLoopModeDeallocate(CFTypeRef cf
) {
321 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)cf
;
322 if (NULL
!= rlm
->_sources
) CFRelease(rlm
->_sources
);
323 if (NULL
!= rlm
->_observers
) CFRelease(rlm
->_observers
);
324 if (NULL
!= rlm
->_timers
) CFRelease(rlm
->_timers
);
325 if (NULL
!= rlm
->_submodes
) CFRelease(rlm
->_submodes
);
326 CFRelease(rlm
->_name
);
327 __CFPortSetFree(rlm
->_portSet
);
328 #if DEPLOYMENT_TARGET_MACOSX
329 if (-1 != rlm
->_kq
) close(rlm
->_kq
);
335 CFSpinLock_t _lock
; /* locked for accessing mode list */
336 __CFPort _wakeUpPort
; // used for CFRunLoopWakeUp
337 volatile uint32_t *_stopped
;
338 CFMutableSetRef _commonModes
;
339 CFMutableSetRef _commonModeItems
;
340 CFRunLoopModeRef _currentMode
;
341 CFMutableSetRef _modes
;
345 /* Bit 0 of the base reserved bits is used for stopped state */
346 /* Bit 1 of the base reserved bits is used for sleeping state */
347 /* Bit 2 of the base reserved bits is used for deallocating state */
349 CF_INLINE Boolean
__CFRunLoopIsStopped(CFRunLoopRef rl
) {
350 return (rl
->_stopped
&& rl
->_stopped
[2]) ? true : false;
353 CF_INLINE
void __CFRunLoopSetStopped(CFRunLoopRef rl
) {
354 if (rl
->_stopped
) rl
->_stopped
[2] = 0x53544F50; // 'STOP'
357 CF_INLINE
void __CFRunLoopUnsetStopped(CFRunLoopRef rl
) {
358 if (rl
->_stopped
) rl
->_stopped
[2] = 0x0;
361 CF_INLINE Boolean
__CFRunLoopIsSleeping(CFRunLoopRef rl
) {
362 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
365 CF_INLINE
void __CFRunLoopSetSleeping(CFRunLoopRef rl
) {
366 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
369 CF_INLINE
void __CFRunLoopUnsetSleeping(CFRunLoopRef rl
) {
370 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
373 CF_INLINE Boolean
__CFRunLoopIsDeallocating(CFRunLoopRef rl
) {
374 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2);
377 CF_INLINE
void __CFRunLoopSetDeallocating(CFRunLoopRef rl
) {
378 __CFBitfieldSetValue(((CFRuntimeBase
*)rl
)->_cfinfo
[CF_INFO_BITS
], 2, 2, 1);
381 CF_INLINE
void __CFRunLoopLock(CFRunLoopRef rl
) {
382 __CFSpinLock(&(((CFRunLoopRef
)rl
)->_lock
));
385 CF_INLINE
void __CFRunLoopUnlock(CFRunLoopRef rl
) {
386 __CFSpinUnlock(&(((CFRunLoopRef
)rl
)->_lock
));
389 static CFStringRef
__CFRunLoopCopyDescription(CFTypeRef cf
) {
390 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
391 CFMutableStringRef result
;
392 result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
393 CFStringAppendFormat(result
, NULL
, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf
, CFGetAllocator(cf
), lockCount(rl
->_lock
) ? "true" : "false", rl
->_wakeUpPort
, (rl
->_stopped
&& (rl
->_stopped
[2] == 0x53544F50)) ? "true" : "false", rl
->_currentMode
? rl
->_currentMode
->_name
: CFSTR("(none)"));
394 CFStringAppendFormat(result
, NULL
, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl
->_commonModes
, rl
->_commonModeItems
, rl
->_modes
);
398 /* call with rl locked */
399 static CFRunLoopModeRef
__CFRunLoopFindMode(CFRunLoopRef rl
, CFStringRef modeName
, Boolean create
) {
401 CFRunLoopModeRef rlm
;
402 struct __CFRunLoopMode srlm
;
403 srlm
._base
._cfisa
= __CFISAForTypeID(__kCFRunLoopModeTypeID
);
404 srlm
._base
._cfinfo
[CF_INFO_BITS
] = 0;
405 _CFRuntimeSetInstanceTypeID(&srlm
, __kCFRunLoopModeTypeID
);
406 srlm
._name
= modeName
;
407 rlm
= (CFRunLoopModeRef
)CFSetGetValue(rl
->_modes
, &srlm
);
409 __CFRunLoopModeLock(rlm
);
415 rlm
= (CFRunLoopModeRef
)_CFRuntimeCreateInstance(CFGetAllocator(rl
), __kCFRunLoopModeTypeID
, sizeof(struct __CFRunLoopMode
) - sizeof(CFRuntimeBase
), NULL
);
419 CF_SPINLOCK_INIT_FOR_STRUCTS(rlm
->_lock
);
420 rlm
->_name
= CFStringCreateCopy(CFGetAllocator(rlm
), modeName
);
421 rlm
->_stopped
= false;
422 rlm
->_sources
= NULL
;
423 rlm
->_observers
= NULL
;
425 rlm
->_submodes
= NULL
;
426 rlm
->_portSet
= __CFPortSetAllocate();
427 if (CFPORT_NULL
== rlm
->_portSet
) HALT
;
428 if (!__CFPortSetInsert(rl
->_wakeUpPort
, rlm
->_portSet
)) HALT
;
429 #if DEPLOYMENT_TARGET_MACOSX
432 CFSetAddValue(rl
->_modes
, rlm
);
434 __CFRunLoopModeLock(rlm
); /* return mode locked */
439 // expects rl and rlm locked
440 static Boolean
__CFRunLoopModeIsEmpty(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
442 if (NULL
== rlm
) return true;
443 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) return false;
444 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) return false;
445 if (NULL
!= rlm
->_submodes
) {
447 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
448 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
449 CFRunLoopModeRef subrlm
;
451 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
452 subIsEmpty
= (NULL
!= subrlm
) ? __CFRunLoopModeIsEmpty(rl
, subrlm
) : true;
453 if (NULL
!= subrlm
) __CFRunLoopModeUnlock(subrlm
);
454 if (!subIsEmpty
) return false;
460 /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */
462 CF_INLINE Boolean
__CFIsValid(const void *cf
) {
463 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3);
466 CF_INLINE
void __CFSetValid(void *cf
) {
467 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 1);
470 CF_INLINE
void __CFUnsetValid(void *cf
) {
471 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 3, 3, 0);
474 struct __CFRunLoopSource
{
478 CFIndex _order
; /* immutable */
479 CFMutableBagRef _runLoops
;
481 CFRunLoopSourceContext version0
; /* immutable, except invalidation */
482 CFRunLoopSourceContext1 version1
; /* immutable, except invalidation */
486 /* Bit 1 of the base reserved bits is used for signalled state */
488 CF_INLINE Boolean
__CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls
) {
489 return (Boolean
)__CFBitfieldGetValue(rls
->_bits
, 1, 1);
492 CF_INLINE
void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls
) {
493 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 1);
496 CF_INLINE
void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls
) {
497 __CFBitfieldSetValue(rls
->_bits
, 1, 1, 0);
500 CF_INLINE
void __CFRunLoopSourceLock(CFRunLoopSourceRef rls
) {
501 __CFSpinLock(&(rls
->_lock
));
504 CF_INLINE
void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls
) {
505 __CFSpinUnlock(&(rls
->_lock
));
508 /* rlm is not locked */
509 static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
510 __CFRunLoopSourceLock(rls
);
511 if (NULL
== rls
->_runLoops
) {
512 rls
->_runLoops
= CFBagCreateMutable(CFGetAllocator(rls
), 0, NULL
);
514 CFBagAddValue(rls
->_runLoops
, rl
);
515 __CFRunLoopSourceUnlock(rls
); // have to unlock before the callout -- cannot help clients with safety
516 if (0 == rls
->_context
.version0
.version
) {
517 if (NULL
!= rls
->_context
.version0
.schedule
) {
518 rls
->_context
.version0
.schedule(rls
->_context
.version0
.info
, rl
, rlm
->_name
);
520 } else if (1 == rls
->_context
.version0
.version
) {
521 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
522 if (CFPORT_NULL
!= port
) {
523 __CFPortSetInsert(port
, rlm
->_portSet
);
528 /* rlm is not locked */
529 static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) { /* DOES CALLOUT */
530 if (0 == rls
->_context
.version0
.version
) {
531 if (NULL
!= rls
->_context
.version0
.cancel
) {
532 rls
->_context
.version0
.cancel(rls
->_context
.version0
.info
, rl
, rlm
->_name
); /* CALLOUT */
534 } else if (1 == rls
->_context
.version0
.version
) {
535 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
536 if (CFPORT_NULL
!= port
) {
537 __CFPortSetRemove(port
, rlm
->_portSet
);
540 __CFRunLoopSourceLock(rls
);
541 if (NULL
!= rls
->_runLoops
) {
542 CFBagRemoveValue(rls
->_runLoops
, rl
);
544 __CFRunLoopSourceUnlock(rls
);
547 struct __CFRunLoopObserver
{
550 CFRunLoopRef _runLoop
;
552 CFOptionFlags _activities
; /* immutable */
553 CFIndex _order
; /* immutable */
554 CFRunLoopObserverCallBack _callout
; /* immutable */
555 CFRunLoopObserverContext _context
; /* immutable, except invalidation */
558 /* Bit 0 of the base reserved bits is used for firing state */
559 /* Bit 1 of the base reserved bits is used for repeats state */
561 CF_INLINE Boolean
__CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo
) {
562 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
565 CF_INLINE
void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo
) {
566 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
569 CF_INLINE
void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo
) {
570 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
573 CF_INLINE Boolean
__CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo
) {
574 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
577 CF_INLINE
void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo
) {
578 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
581 CF_INLINE
void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo
) {
582 __CFBitfieldSetValue(((CFRuntimeBase
*)rlo
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
585 CF_INLINE
void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo
) {
586 __CFSpinLock(&(rlo
->_lock
));
589 CF_INLINE
void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo
) {
590 __CFSpinUnlock(&(rlo
->_lock
));
593 static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
594 __CFRunLoopObserverLock(rlo
);
595 if (0 == rlo
->_rlCount
) {
599 __CFRunLoopObserverUnlock(rlo
);
602 static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
603 __CFRunLoopObserverLock(rlo
);
605 if (0 == rlo
->_rlCount
) {
606 rlo
->_runLoop
= NULL
;
608 __CFRunLoopObserverUnlock(rlo
);
611 struct __CFRunLoopTimer
{
614 CFRunLoopRef _runLoop
;
616 #if DEPLOYMENT_TARGET_MACOSX
617 mach_port_name_t _port
;
619 CFIndex _order
; /* immutable */
620 int64_t _fireTSR
; /* TSR units */
621 int64_t _intervalTSR
; /* immutable; 0 means non-repeating; TSR units */
622 CFRunLoopTimerCallBack _callout
; /* immutable */
623 CFRunLoopTimerContext _context
; /* immutable, except invalidation */
626 /* Bit 0 of the base reserved bits is used for firing state */
627 /* Bit 1 of the base reserved bits is used for fired-during-callout state */
629 CF_INLINE Boolean
__CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt
) {
630 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0);
633 CF_INLINE
void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt
) {
634 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 1);
637 CF_INLINE
void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt
) {
638 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 0, 0, 0);
641 CF_INLINE Boolean
__CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt
) {
642 return (Boolean
)__CFBitfieldGetValue(((const CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1);
645 CF_INLINE
void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt
) {
646 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 1);
649 CF_INLINE
void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt
) {
650 __CFBitfieldSetValue(((CFRuntimeBase
*)rlt
)->_cfinfo
[CF_INFO_BITS
], 1, 1, 0);
653 CF_INLINE
void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt
) {
654 __CFSpinLock(&(rlt
->_lock
));
657 CF_INLINE
void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt
) {
658 __CFSpinUnlock(&(rlt
->_lock
));
661 static CFSpinLock_t __CFRLTFireTSRLock
= CFSpinLockInit
;
663 CF_INLINE
void __CFRunLoopTimerFireTSRLock(void) {
664 __CFSpinLock(&__CFRLTFireTSRLock
);
667 CF_INLINE
void __CFRunLoopTimerFireTSRUnlock(void) {
668 __CFSpinUnlock(&__CFRLTFireTSRLock
);
671 #if DEPLOYMENT_TARGET_MACOSX
672 static CFMutableDictionaryRef __CFRLTPortMap
= NULL
;
673 static CFSpinLock_t __CFRLTPortMapLock
= CFSpinLockInit
;
675 CF_INLINE
void __CFRunLoopTimerPortMapLock(void) {
676 __CFSpinLock(&__CFRLTPortMapLock
);
679 CF_INLINE
void __CFRunLoopTimerPortMapUnlock(void) {
680 __CFSpinUnlock(&__CFRLTPortMapLock
);
684 static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
685 #if DEPLOYMENT_TARGET_MACOSX
686 __CFRunLoopTimerLock(rlt
);
687 if (0 == rlt
->_rlCount
) {
689 if (MACH_PORT_NULL
== rlt
->_port
) {
690 rlt
->_port
= mk_timer_create();
692 __CFRunLoopTimerPortMapLock();
693 if (NULL
== __CFRLTPortMap
) {
694 __CFRLTPortMap
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
696 CFDictionarySetValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
, rlt
);
697 __CFRunLoopTimerPortMapUnlock();
700 mach_port_insert_member(mach_task_self(), rlt
->_port
, rlm
->_portSet
);
701 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
702 __CFRunLoopTimerUnlock(rlt
);
706 static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
707 #if DEPLOYMENT_TARGET_MACOSX
708 __CFRunLoopTimerLock(rlt
);
709 __CFPortSetRemove(rlt
->_port
, rlm
->_portSet
);
711 if (0 == rlt
->_rlCount
) {
712 __CFRunLoopTimerPortMapLock();
713 if (NULL
!= __CFRLTPortMap
) {
714 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
);
716 __CFRunLoopTimerPortMapUnlock();
717 rlt
->_runLoop
= NULL
;
718 mk_timer_cancel(rlt
->_port
, NULL
);
720 __CFRunLoopTimerUnlock(rlt
);
724 // Caller must hold the Timer lock for safety
725 static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt
, CFRunLoopRef rl
) {
726 #if DEPLOYMENT_TARGET_MACOSX
727 mk_timer_arm(rlt
->_port
, __CFUInt64ToAbsoluteTime(rlt
->_fireTSR
));
733 CONST_STRING_DECL(kCFRunLoopDefaultMode
, "kCFRunLoopDefaultMode")
734 CONST_STRING_DECL(kCFRunLoopCommonModes
, "kCFRunLoopCommonModes")
738 CFRunLoopSourceRef result
;
741 static void __CFRunLoopFindSource(const void *value
, void *ctx
) {
742 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
743 struct _findsource
*context
= (struct _findsource
*)ctx
;
745 if (NULL
!= context
->result
) return;
746 if (1 != rls
->_context
.version0
.version
) return;
747 __CFRunLoopSourceLock(rls
);
748 port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
);
749 if (port
== context
->port
) {
750 context
->result
= rls
;
752 __CFRunLoopSourceUnlock(rls
);
755 // call with rl and rlm locked
756 static CFRunLoopSourceRef
__CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPort port
) { /* DOES CALLOUT */
758 struct _findsource context
= {port
, NULL
};
759 if (NULL
!= rlm
->_sources
) {
760 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopFindSource
), &context
);
762 if (NULL
== context
.result
&& NULL
!= rlm
->_submodes
) {
764 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
765 CFRunLoopSourceRef source
= NULL
;
766 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
767 CFRunLoopModeRef subrlm
;
768 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
769 if (NULL
!= subrlm
) {
770 source
= __CFRunLoopModeFindSourceForMachPort(rl
, subrlm
, port
);
771 __CFRunLoopModeUnlock(subrlm
);
773 if (NULL
!= source
) {
774 context
.result
= source
;
779 return context
.result
;
782 #if DEPLOYMENT_TARGET_MACOSX
783 // call with rl and rlm locked
784 static CFRunLoopTimerRef
__CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm
, __CFPort port
) {
786 CFRunLoopTimerRef result
= NULL
;
787 __CFRunLoopTimerPortMapLock();
788 if (NULL
!= __CFRLTPortMap
) {
789 result
= (CFRunLoopTimerRef
)CFDictionaryGetValue(__CFRLTPortMap
, (void *)(uintptr_t)port
);
791 __CFRunLoopTimerPortMapUnlock();
796 static void __CFRunLoopDeallocateSources(const void *value
, void *context
) {
797 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
798 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
800 const void **list
, *buffer
[256];
801 if (NULL
== rlm
->_sources
) return;
802 cnt
= CFSetGetCount(rlm
->_sources
);
803 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
804 CFSetGetValues(rlm
->_sources
, list
);
805 for (idx
= 0; idx
< cnt
; idx
++) {
808 CFSetRemoveAllValues(rlm
->_sources
);
809 for (idx
= 0; idx
< cnt
; idx
++) {
810 __CFRunLoopSourceCancel((CFRunLoopSourceRef
)list
[idx
], rl
, rlm
);
811 CFRelease(list
[idx
]);
813 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
816 static void __CFRunLoopDeallocateObservers(const void *value
, void *context
) {
817 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
818 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
820 const void **list
, *buffer
[256];
821 if (NULL
== rlm
->_observers
) return;
822 cnt
= CFSetGetCount(rlm
->_observers
);
823 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
824 CFSetGetValues(rlm
->_observers
, list
);
825 for (idx
= 0; idx
< cnt
; idx
++) {
828 CFSetRemoveAllValues(rlm
->_observers
);
829 for (idx
= 0; idx
< cnt
; idx
++) {
830 __CFRunLoopObserverCancel((CFRunLoopObserverRef
)list
[idx
], rl
, rlm
);
831 CFRelease(list
[idx
]);
833 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
836 static void __CFRunLoopDeallocateTimers(const void *value
, void *context
) {
837 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
838 CFRunLoopRef rl
= (CFRunLoopRef
)context
;
840 const void **list
, *buffer
[256];
841 if (NULL
== rlm
->_timers
) return;
842 cnt
= CFSetGetCount(rlm
->_timers
);
843 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
844 CFSetGetValues(rlm
->_timers
, list
);
845 for (idx
= 0; idx
< cnt
; idx
++) {
848 CFSetRemoveAllValues(rlm
->_timers
);
849 for (idx
= 0; idx
< cnt
; idx
++) {
850 __CFRunLoopTimerCancel((CFRunLoopTimerRef
)list
[idx
], rl
, rlm
);
851 CFRelease(list
[idx
]);
853 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
856 static void __CFRunLoopDeallocate(CFTypeRef cf
) {
857 CFRunLoopRef rl
= (CFRunLoopRef
)cf
;
858 /* We try to keep the run loop in a valid state as long as possible,
859 since sources may have non-retained references to the run loop.
860 Another reason is that we don't want to lock the run loop for
861 callback reasons, if we can get away without that. We start by
862 eliminating the sources, since they are the most likely to call
863 back into the run loop during their "cancellation". Common mode
864 items will be removed from the mode indirectly by the following
866 __CFRunLoopSetDeallocating(rl
);
867 if (NULL
!= rl
->_modes
) {
868 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateSources
), rl
);
869 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateObservers
), rl
);
870 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopDeallocateTimers
), rl
);
873 if (NULL
!= rl
->_commonModeItems
) {
874 CFRelease(rl
->_commonModeItems
);
876 if (NULL
!= rl
->_commonModes
) {
877 CFRelease(rl
->_commonModes
);
879 if (NULL
!= rl
->_modes
) {
880 CFRelease(rl
->_modes
);
882 __CFPortFree(rl
->_wakeUpPort
);
883 rl
->_wakeUpPort
= CFPORT_NULL
;
884 __CFRunLoopUnlock(rl
);
887 static const CFRuntimeClass __CFRunLoopModeClass
= {
892 __CFRunLoopModeDeallocate
,
893 __CFRunLoopModeEqual
,
896 __CFRunLoopModeCopyDescription
899 static const CFRuntimeClass __CFRunLoopClass
= {
904 __CFRunLoopDeallocate
,
908 __CFRunLoopCopyDescription
911 __private_extern__
void __CFRunLoopInitialize(void) {
912 __kCFRunLoopTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopClass
);
913 __kCFRunLoopModeTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopModeClass
);
916 CFTypeID
CFRunLoopGetTypeID(void) {
917 return __kCFRunLoopTypeID
;
920 static CFRunLoopRef
__CFRunLoopCreate(void) {
921 CFRunLoopRef loop
= NULL
;
922 CFRunLoopModeRef rlm
;
923 uint32_t size
= sizeof(struct __CFRunLoop
) - sizeof(CFRuntimeBase
);
924 loop
= (CFRunLoopRef
)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, __kCFRunLoopTypeID
, size
, NULL
);
928 loop
->_stopped
= NULL
;
929 CF_SPINLOCK_INIT_FOR_STRUCTS(loop
->_lock
);
930 loop
->_wakeUpPort
= __CFPortAllocate();
931 if (CFPORT_NULL
== loop
->_wakeUpPort
) HALT
;
932 loop
->_commonModes
= CFSetCreateMutable(CFGetAllocator(loop
), 0, &kCFTypeSetCallBacks
);
933 CFSetAddValue(loop
->_commonModes
, kCFRunLoopDefaultMode
);
934 loop
->_commonModeItems
= NULL
;
935 loop
->_currentMode
= NULL
;
936 loop
->_modes
= CFSetCreateMutable(CFGetAllocator(loop
), 0, &kCFTypeSetCallBacks
);
937 _CFSetSetCapacity(loop
->_modes
, 10);
938 loop
->_counterpart
= NULL
;
939 rlm
= __CFRunLoopFindMode(loop
, kCFRunLoopDefaultMode
, true);
940 if (NULL
!= rlm
) __CFRunLoopModeUnlock(rlm
);
944 static CFMutableDictionaryRef runLoops
= NULL
;
945 static char setMainLoop
= 0;
946 static CFSpinLock_t loopsLock
= CFSpinLockInit
;
948 // If this is called on a non-main thread, and the main thread pthread_t is passed in,
949 // and this has not yet beed called on the main thread (since the last fork(), this will
950 // produce a different run loop that will probably be tossed away eventually, than the
951 // main thread run loop. There's nothing much we can do about that, without a call to
952 // fetch the main thread's pthread_t from the pthreads subsystem.
954 // t==0 is a synonym for "main thread" that always works
955 __private_extern__ CFRunLoopRef
_CFRunLoop0(pthread_t t
) {
956 CFRunLoopRef loop
= NULL
;
957 __CFSpinLock(&loopsLock
);
959 __CFSpinUnlock(&loopsLock
);
960 CFMutableDictionaryRef dict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
961 CFRunLoopRef mainLoop
= __CFRunLoopCreate();
962 CFDictionarySetValue(dict
, 0, mainLoop
);
963 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, dict
, (void * volatile *)&runLoops
)) {
967 __CFSpinLock(&loopsLock
);
969 if (pthread_main_np() && pthread_equal(t
, pthread_self())) {
972 loop
= (CFRunLoopRef
)CFDictionaryGetValue(runLoops
, pthreadPointer(t
));
974 __CFSpinUnlock(&loopsLock
);
975 CFRunLoopRef newLoop
= __CFRunLoopCreate();
976 __CFGetThreadSpecificData(); // just cause the thread finalizer to be called as a side effect
977 __CFSpinLock(&loopsLock
);
978 loop
= (CFRunLoopRef
)CFDictionaryGetValue(runLoops
, pthreadPointer(t
));
982 CFDictionarySetValue(runLoops
, pthreadPointer(t
), newLoop
);
986 if (!setMainLoop
&& pthread_main_np()) {
987 if (pthread_equal(t
, kNilPthreadT
)) {
988 CFDictionarySetValue(runLoops
, pthreadPointer(pthread_self()), loop
);
990 CFRunLoopRef mainLoop
= (CFRunLoopRef
)CFDictionaryGetValue(runLoops
, pthreadPointer(kNilPthreadT
));
991 CFDictionarySetValue(runLoops
, pthreadPointer(pthread_self()), mainLoop
);
995 __CFSpinUnlock(&loopsLock
);
999 __private_extern__
void _CFRunLoop1(void) {
1000 __CFSpinLock(&loopsLock
);
1002 pthread_t t
= pthread_self();
1003 CFRunLoopRef currentLoop
= (CFRunLoopRef
)CFDictionaryGetValue(runLoops
, pthreadPointer(t
));
1004 CFRunLoopRef mainLoop
= (CFRunLoopRef
)CFDictionaryGetValue(runLoops
, pthreadPointer(kNilPthreadT
));
1005 if (currentLoop
&& mainLoop
!= currentLoop
) {
1006 CFDictionaryRemoveValue(runLoops
, pthreadPointer(t
));
1007 CFRelease(currentLoop
);
1010 __CFSpinUnlock(&loopsLock
);
1013 CFRunLoopRef
CFRunLoopGetMain(void) {
1015 return _CFRunLoop0(kNilPthreadT
);
1018 CFRunLoopRef
CFRunLoopGetCurrent(void) {
1020 return _CFRunLoop0(pthread_self());
1023 void _CFRunLoopSetCurrent(CFRunLoopRef rl
) {
1024 __CFSpinLock(&loopsLock
);
1025 CFRunLoopRef currentLoop
= runLoops
? (CFRunLoopRef
)CFDictionaryGetValue(runLoops
, pthreadPointer(pthread_self())) : NULL
;
1026 if (rl
!= currentLoop
) {
1027 // intentionally leak currentLoop so we don't kill any ports in the child
1028 // if (currentLoop) CFRelease(currentLoop);
1031 runLoops
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
1032 CFRunLoopRef mainLoop
= __CFRunLoopCreate();
1033 CFDictionarySetValue(runLoops
, pthreadPointer(kNilPthreadT
), mainLoop
);
1036 CFDictionarySetValue(runLoops
, pthreadPointer(pthread_self()), rl
);
1038 CFDictionaryRemoveValue(runLoops
, pthreadPointer(pthread_self()));
1041 __CFSpinUnlock(&loopsLock
);
1044 CFStringRef
CFRunLoopCopyCurrentMode(CFRunLoopRef rl
) {
1046 CFStringRef result
= NULL
;
1047 __CFRunLoopLock(rl
);
1048 if (NULL
!= rl
->_currentMode
) {
1049 result
= CFRetain(rl
->_currentMode
->_name
);
1051 __CFRunLoopUnlock(rl
);
1055 static void __CFRunLoopGetModeName(const void *value
, void *context
) {
1056 CFRunLoopModeRef rlm
= (CFRunLoopModeRef
)value
;
1057 CFMutableArrayRef array
= (CFMutableArrayRef
)context
;
1058 CFArrayAppendValue(array
, rlm
->_name
);
1061 CFArrayRef
CFRunLoopCopyAllModes(CFRunLoopRef rl
) {
1063 CFMutableArrayRef array
;
1064 __CFRunLoopLock(rl
);
1065 array
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(rl
->_modes
), &kCFTypeArrayCallBacks
);
1066 CFSetApplyFunction(rl
->_modes
, (__CFRunLoopGetModeName
), array
);
1067 __CFRunLoopUnlock(rl
);
1071 static void __CFRunLoopAddItemsToCommonMode(const void *value
, void *ctx
) {
1072 CFTypeRef item
= (CFTypeRef
)value
;
1073 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1074 CFStringRef modeName
= (CFStringRef
)(((CFTypeRef
*)ctx
)[1]);
1075 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1076 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1077 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1078 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1079 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1080 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1084 static void __CFRunLoopAddItemToCommonModes(const void *value
, void *ctx
) {
1085 CFStringRef modeName
= (CFStringRef
)value
;
1086 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1087 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1088 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1089 CFRunLoopAddSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1090 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1091 CFRunLoopAddObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1092 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1093 CFRunLoopAddTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1097 static void __CFRunLoopRemoveItemFromCommonModes(const void *value
, void *ctx
) {
1098 CFStringRef modeName
= (CFStringRef
)value
;
1099 CFRunLoopRef rl
= (CFRunLoopRef
)(((CFTypeRef
*)ctx
)[0]);
1100 CFTypeRef item
= (CFTypeRef
)(((CFTypeRef
*)ctx
)[1]);
1101 if (CFGetTypeID(item
) == __kCFRunLoopSourceTypeID
) {
1102 CFRunLoopRemoveSource(rl
, (CFRunLoopSourceRef
)item
, modeName
);
1103 } else if (CFGetTypeID(item
) == __kCFRunLoopObserverTypeID
) {
1104 CFRunLoopRemoveObserver(rl
, (CFRunLoopObserverRef
)item
, modeName
);
1105 } else if (CFGetTypeID(item
) == __kCFRunLoopTimerTypeID
) {
1106 CFRunLoopRemoveTimer(rl
, (CFRunLoopTimerRef
)item
, modeName
);
1110 Boolean
_CFRunLoop01(CFRunLoopRef rl
, CFStringRef modeName
) {
1111 __CFRunLoopLock(rl
);
1112 Boolean present
= CFSetContainsValue(rl
->_commonModes
, modeName
);
1113 __CFRunLoopUnlock(rl
);
1117 void *_CFRunLoop02(CFRunLoopRef rl
) {
1118 return rl
->_counterpart
;
1121 void _CFRunLoop03(CFRunLoopRef rl
, void *ns
) {
1122 rl
->_counterpart
= ns
;
1125 void CFRunLoopAddCommonMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1127 if (__CFRunLoopIsDeallocating(rl
)) return;
1128 __CFRunLoopLock(rl
);
1129 if (!CFSetContainsValue(rl
->_commonModes
, modeName
)) {
1130 CFSetRef set
= rl
->_commonModeItems
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModeItems
) : NULL
;
1131 CFSetAddValue(rl
->_commonModes
, modeName
);
1132 __CFRunLoopUnlock(rl
);
1134 CFTypeRef context
[2] = {rl
, modeName
};
1135 /* add all common-modes items to new mode */
1136 CFSetApplyFunction(set
, (__CFRunLoopAddItemsToCommonMode
), (void *)context
);
1140 __CFRunLoopUnlock(rl
);
1144 static CFComparisonResult
__CFRunLoopObserverQSortComparator(const void *val1
, const void *val2
, void *context
) {
1145 CFRunLoopObserverRef o1
= *((CFRunLoopObserverRef
*)val1
);
1146 CFRunLoopObserverRef o2
= *((CFRunLoopObserverRef
*)val2
);
1148 return (!o2
) ? kCFCompareEqualTo
: kCFCompareLessThan
;
1151 return kCFCompareGreaterThan
;
1153 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1154 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1155 return kCFCompareEqualTo
;
1159 /* rl is unlocked, rlm is locked on entrance and exit */
1160 /* ALERT: this should collect all the candidate observers from the top level
1161 * and all submodes, recursively, THEN start calling them, in order to obey
1162 * the ordering parameter. */
1163 static void __CFRunLoopDoObservers(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopActivity activity
) { /* DOES CALLOUT */
1166 CFArrayRef submodes
;
1168 /* Fire the observers */
1169 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
1170 if (NULL
!= rlm
->_observers
) {
1171 cnt
= CFSetGetCount(rlm
->_observers
);
1173 CFRunLoopObserverRef buffer
[(cnt
<= 1024) ? cnt
: 1];
1174 CFRunLoopObserverRef
*collectedObservers
= (cnt
<= 1024) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(CFRunLoopObserverRef
), 0);
1175 CFSetGetValues(rlm
->_observers
, (const void **)collectedObservers
);
1176 for (idx
= 0; idx
< cnt
; idx
++) {
1177 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1178 if (0 != (rlo
->_activities
& activity
) && __CFIsValid(rlo
) && !__CFRunLoopObserverIsFiring(rlo
)) {
1181 /* We're not interested in this one - set it to NULL so we don't process it later */
1182 collectedObservers
[idx
] = NULL
;
1185 __CFRunLoopModeUnlock(rlm
);
1186 CFQSortArray(collectedObservers
, cnt
, sizeof(CFRunLoopObserverRef
), __CFRunLoopObserverQSortComparator
, NULL
);
1187 for (idx
= 0; idx
< cnt
; idx
++) {
1188 CFRunLoopObserverRef rlo
= collectedObservers
[idx
];
1190 __CFRunLoopObserverLock(rlo
);
1191 if (__CFIsValid(rlo
)) {
1192 __CFRunLoopObserverUnlock(rlo
);
1193 __CFRunLoopObserverSetFiring(rlo
);
1194 rlo
->_callout(rlo
, activity
, rlo
->_context
.info
); /* CALLOUT */
1195 __CFRunLoopObserverUnsetFiring(rlo
);
1196 if (!__CFRunLoopObserverRepeats(rlo
)) {
1197 CFRunLoopObserverInvalidate(rlo
);
1200 __CFRunLoopObserverUnlock(rlo
);
1205 __CFRunLoopModeLock(rlm
);
1206 if (collectedObservers
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, collectedObservers
);
1209 if (NULL
!= submodes
) {
1210 __CFRunLoopModeUnlock(rlm
);
1211 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
1212 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
1213 CFRunLoopModeRef subrlm
;
1214 __CFRunLoopLock(rl
);
1215 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1216 __CFRunLoopUnlock(rl
);
1217 if (NULL
!= subrlm
) {
1218 __CFRunLoopDoObservers(rl
, subrlm
, activity
);
1219 __CFRunLoopModeUnlock(subrlm
);
1222 CFRelease(submodes
);
1223 __CFRunLoopModeLock(rlm
);
1227 static CFComparisonResult
__CFRunLoopSourceComparator(const void *val1
, const void *val2
, void *context
) {
1228 CFRunLoopSourceRef o1
= (CFRunLoopSourceRef
)val1
;
1229 CFRunLoopSourceRef o2
= (CFRunLoopSourceRef
)val2
;
1230 if (o1
->_order
< o2
->_order
) return kCFCompareLessThan
;
1231 if (o2
->_order
< o1
->_order
) return kCFCompareGreaterThan
;
1232 return kCFCompareEqualTo
;
1235 static void __CFRunLoopCollectSources0(const void *value
, void *context
) {
1236 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)value
;
1237 CFTypeRef
*sources
= (CFTypeRef
*)context
;
1238 if (0 == rls
->_context
.version0
.version
&& __CFIsValid(rls
) && __CFRunLoopSourceIsSignaled(rls
)) {
1239 if (NULL
== *sources
) {
1240 *sources
= CFRetain(rls
);
1241 } else if (CFGetTypeID(*sources
) == __kCFRunLoopSourceTypeID
) {
1242 CFTypeRef oldrls
= *sources
;
1243 *sources
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1244 CFArrayAppendValue((CFMutableArrayRef
)*sources
, oldrls
);
1245 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1248 CFArrayAppendValue((CFMutableArrayRef
)*sources
, rls
);
1253 /* rl is unlocked, rlm is locked on entrance and exit */
1254 static Boolean
__CFRunLoopDoSources0(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, Boolean stopAfterHandle
) { /* DOES CALLOUT */
1256 CFTypeRef sources
= NULL
;
1257 Boolean sourceHandled
= false;
1260 __CFRunLoopModeUnlock(rlm
); // locks have to be taken in order
1261 __CFRunLoopLock(rl
);
1262 __CFRunLoopModeLock(rlm
);
1263 /* Fire the version 0 sources */
1264 if (NULL
!= rlm
->_sources
&& 0 < CFSetGetCount(rlm
->_sources
)) {
1265 CFSetApplyFunction(rlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1267 for (idx
= 0, cnt
= (NULL
!= rlm
->_submodes
) ? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1268 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1269 CFRunLoopModeRef subrlm
;
1270 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1271 if (NULL
!= subrlm
) {
1272 if (NULL
!= subrlm
->_sources
&& 0 < CFSetGetCount(subrlm
->_sources
)) {
1273 CFSetApplyFunction(subrlm
->_sources
, (__CFRunLoopCollectSources0
), &sources
);
1275 __CFRunLoopModeUnlock(subrlm
);
1278 __CFRunLoopUnlock(rl
);
1279 if (NULL
!= sources
) {
1280 // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef
1281 __CFRunLoopModeUnlock(rlm
);
1282 if (CFGetTypeID(sources
) == __kCFRunLoopSourceTypeID
) {
1283 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)sources
;
1284 __CFRunLoopSourceLock(rls
);
1285 __CFRunLoopSourceUnsetSignaled(rls
);
1286 if (__CFIsValid(rls
)) {
1287 __CFRunLoopSourceUnlock(rls
);
1288 if (NULL
!= rls
->_context
.version0
.perform
) {
1289 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1292 sourceHandled
= true;
1294 __CFRunLoopSourceUnlock(rls
);
1297 cnt
= CFArrayGetCount(sources
);
1298 CFArraySortValues((CFMutableArrayRef
)sources
, CFRangeMake(0, cnt
), (__CFRunLoopSourceComparator
), NULL
);
1299 for (idx
= 0; idx
< cnt
; idx
++) {
1300 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, idx
);
1301 __CFRunLoopSourceLock(rls
);
1302 __CFRunLoopSourceUnsetSignaled(rls
);
1303 if (__CFIsValid(rls
)) {
1304 __CFRunLoopSourceUnlock(rls
);
1305 if (NULL
!= rls
->_context
.version0
.perform
) {
1306 rls
->_context
.version0
.perform(rls
->_context
.version0
.info
); /* CALLOUT */
1309 sourceHandled
= true;
1311 __CFRunLoopSourceUnlock(rls
);
1313 if (stopAfterHandle
&& sourceHandled
) {
1319 __CFRunLoopModeLock(rlm
);
1321 return sourceHandled
;
1324 // msg, size and reply are unused on Windows
1325 static Boolean
__CFRunLoopDoSource1(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopSourceRef rls
1326 #if DEPLOYMENT_TARGET_MACOSX
1327 , mach_msg_header_t
*msg
, CFIndex size
, mach_msg_header_t
**reply
1329 ) { /* DOES CALLOUT */
1331 Boolean sourceHandled
= false;
1333 /* Fire a version 1 source */
1335 __CFRunLoopModeUnlock(rlm
);
1336 __CFRunLoopSourceLock(rls
);
1337 if (__CFIsValid(rls
)) {
1338 __CFRunLoopSourceUnsetSignaled(rls
);
1339 __CFRunLoopSourceUnlock(rls
);
1340 if (NULL
!= rls
->_context
.version1
.perform
) {
1341 #if DEPLOYMENT_TARGET_MACOSX
1342 *reply
= rls
->_context
.version1
.perform(msg
, size
, kCFAllocatorSystemDefault
, rls
->_context
.version1
.info
); /* CALLOUT */
1345 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1346 rls
->_context
.version1
.perform(rls
->_context
.version1
.info
); /* CALLOUT */
1350 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); }
1352 sourceHandled
= true;
1354 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls
); }
1355 __CFRunLoopSourceUnlock(rls
);
1358 __CFRunLoopModeLock(rlm
);
1359 return sourceHandled
;
1362 static Boolean
__CFRunLoopDoTimer(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
1363 Boolean timerHandled
= false;
1364 int64_t oldFireTSR
= 0;
1368 __CFRunLoopModeUnlock(rlm
);
1369 __CFRunLoopTimerLock(rlt
);
1370 if (__CFIsValid(rlt
) && !__CFRunLoopTimerIsFiring(rlt
)) {
1371 __CFRunLoopTimerUnsetDidFire(rlt
);
1372 __CFRunLoopTimerSetFiring(rlt
);
1373 __CFRunLoopTimerUnlock(rlt
);
1374 __CFRunLoopTimerFireTSRLock();
1375 oldFireTSR
= rlt
->_fireTSR
;
1376 __CFRunLoopTimerFireTSRUnlock();
1377 rlt
->_callout(rlt
, rlt
->_context
.info
); /* CALLOUT */
1379 __CFRunLoopTimerUnsetFiring(rlt
);
1380 timerHandled
= true;
1382 // If the timer fires while it is firing in a higher activiation,
1383 // it is not allowed to fire, but we have to remember that fact.
1384 // Later, if the timer's fire date is being handled manually, we
1385 // need to re-arm the kernel timer, since it has possibly already
1386 // fired (this firing which is being skipped, say) and the timer
1387 // will permanently stop if we completely drop this firing.
1388 if (__CFRunLoopTimerIsFiring(rlt
)) __CFRunLoopTimerSetDidFire(rlt
);
1389 __CFRunLoopTimerUnlock(rlt
);
1391 if (__CFIsValid(rlt
) && timerHandled
) {
1392 if (0 == rlt
->_intervalTSR
) {
1393 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
1395 /* This is just a little bit tricky: we want to support calling
1396 * CFRunLoopTimerSetNextFireDate() from within the callout and
1397 * honor that new time here if it is a later date, otherwise
1398 * it is completely ignored. */
1399 int64_t currentFireTSR
;
1400 __CFRunLoopTimerFireTSRLock();
1401 currentFireTSR
= rlt
->_fireTSR
;
1402 if (oldFireTSR
< currentFireTSR
) {
1403 /* Next fire TSR was set, and set to a date after the previous
1404 * fire date, so we honor it. */
1405 if (__CFRunLoopTimerDidFire(rlt
)) {
1406 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rl
);
1407 __CFRunLoopTimerUnsetDidFire(rlt
);
1410 if ((uint64_t)LLONG_MAX
<= (uint64_t)oldFireTSR
+ (uint64_t)rlt
->_intervalTSR
) {
1411 currentFireTSR
= LLONG_MAX
;
1413 int64_t currentTSR
= (int64_t)__CFReadTSR();
1414 currentFireTSR
= oldFireTSR
;
1415 while (currentFireTSR
<= currentTSR
) {
1416 currentFireTSR
+= rlt
->_intervalTSR
;
1419 rlt
->_fireTSR
= currentFireTSR
;
1420 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rl
);
1422 __CFRunLoopTimerFireTSRUnlock();
1426 __CFRunLoopModeLock(rlm
);
1427 return timerHandled
;
1430 CF_EXPORT Boolean
_CFRunLoopFinished(CFRunLoopRef rl
, CFStringRef modeName
) {
1432 CFRunLoopModeRef rlm
;
1433 Boolean result
= false;
1434 __CFRunLoopLock(rl
);
1435 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1436 if (NULL
== rlm
|| __CFRunLoopModeIsEmpty(rl
, rlm
)) {
1439 __CFRunLoopUnlock(rl
);
1440 if (rlm
) __CFRunLoopModeUnlock(rlm
);
1444 // rl is locked, rlm is locked on entry and exit
1445 static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, __CFPortSet portSet
) {
1447 const void **list
, *buffer
[256];
1449 // Timers and version 1 sources go into the portSet currently
1450 if (NULL
!= rlm
->_sources
) {
1451 cnt
= CFSetGetCount(rlm
->_sources
);
1452 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1453 CFSetGetValues(rlm
->_sources
, list
);
1454 for (idx
= 0; idx
< cnt
; idx
++) {
1455 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)list
[idx
];
1456 if (1 == rls
->_context
.version0
.version
) {
1457 __CFPort port
= rls
->_context
.version1
.getPort(rls
->_context
.version1
.info
); /* CALLOUT */
1458 if (CFPORT_NULL
!= port
) {
1459 __CFPortSetInsert(port
, portSet
);
1463 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1465 #if DEPLOYMENT_TARGET_MACOSX
1466 if (NULL
!= rlm
->_timers
) {
1467 cnt
= CFSetGetCount(rlm
->_timers
);
1468 list
= (cnt
<= 256) ? buffer
: CFAllocatorAllocate(kCFAllocatorSystemDefault
, cnt
* sizeof(void *), 0);
1469 CFSetGetValues(rlm
->_timers
, list
);
1470 for (idx
= 0; idx
< cnt
; idx
++) {
1471 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)list
[idx
];
1472 if (MACH_PORT_NULL
!= rlt
->_port
) {
1473 mach_port_insert_member(mach_task_self(), rlt
->_port
, portSet
);
1476 if (list
!= buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, list
);
1479 // iterate over submodes
1480 for (idx
= 0, cnt
= NULL
!= rlm
->_submodes
? CFArrayGetCount(rlm
->_submodes
) : 0; idx
< cnt
; idx
++) {
1481 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1482 CFRunLoopModeRef subrlm
;
1483 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1484 if (NULL
!= subrlm
) {
1485 __CFRunLoopModeAddPortsToPortSet(rl
, subrlm
, portSet
);
1486 __CFRunLoopModeUnlock(subrlm
);
1491 static __CFPortSet _LastMainWaitSet
= 0;
1493 // return NO if we're the main runloop and there are no messages waiting on the port set
1494 int _CFRunLoopInputsReady(void) {
1496 // XXX_PCB: the following 2 lines aren't safe to call during GC, because another
1497 // thread may have entered CFRunLoopGetMain(), which grabs a spink lock, and then
1498 // is suspended by the GC. We can check for the main thread more directly
1499 // by calling pthread_main_np().
1500 // CFRunLoopRef current = CFRunLoopGetMain()
1501 // if (current != CFRunLoopGetMain()) return true;
1502 #if DEPLOYMENT_TARGET_MACOSX
1503 if (!pthread_main_np()) return true;
1505 // XXX_PCB: can't be any messages waiting if the wait set is NULL.
1506 if (_LastMainWaitSet
== MACH_PORT_NULL
) return false;
1508 // prepare a message header with no space for any data, nor a trailer
1509 mach_msg_header_t msg
;
1510 msg
.msgh_size
= sizeof(msg
); // just the header, ma'am
1511 // need the waitset, actually XXX
1512 msg
.msgh_local_port
= _LastMainWaitSet
;
1513 msg
.msgh_remote_port
= MACH_PORT_NULL
;
1516 kern_return_t ret
= mach_msg(&msg
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
| MACH_RCV_LARGE
, 0, msg
.msgh_size
, _LastMainWaitSet
, 0, MACH_PORT_NULL
);
1518 return (MACH_RCV_TOO_LARGE
== ret
);
1524 static void print_msg_scan_header(void) {
1525 printf("======== ======== ======== ========\n");
1526 printf("description\tport\tport type\t\treferences\n");
1529 static void print_one_port_info(const char *desc
, mach_port_t port
, mach_msg_type_name_t type
) {
1530 mach_port_urefs_t refs
;
1531 kern_return_t ret
= mach_port_get_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, &refs
);
1532 if (ret
!= KERN_SUCCESS
) refs
= 0;
1533 const char *type_name
= "???";
1535 case MACH_MSG_TYPE_MOVE_SEND
: type_name
= "MACH_MSG_TYPE_MOVE_SEND"; break;
1536 case MACH_MSG_TYPE_MOVE_SEND_ONCE
: type_name
= "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break;
1537 case MACH_MSG_TYPE_MOVE_RECEIVE
: type_name
= "MACH_MSG_TYPE_MOVE_RECEIVE"; break;
1538 case MACH_MSG_TYPE_MAKE_SEND
: type_name
= "MACH_MSG_TYPE_MAKE_SEND"; break;
1539 case MACH_MSG_TYPE_MAKE_SEND_ONCE
: type_name
= "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break;
1541 printf("%s\t%p\t%-20s\t%u\n", desc
, port
, type_name
, refs
);
1544 static void mach_msg_scan(mach_msg_header_t
*msg
, int clean
) {
1545 Boolean printed_header
= false;
1547 * The msgh_local_port field doesn't hold a port right.
1548 * The receive operation consumes the destination port right.
1550 if (MACH_PORT_NULL
!= msg
->msgh_remote_port
) {
1551 if (! printed_header
) print_msg_scan_header();
1552 printed_header
= true;
1553 print_one_port_info("msg->msgh_remote_port", msg
->msgh_remote_port
, MACH_MSGH_BITS_REMOTE(msg
->msgh_bits
));
1555 if (msg
->msgh_bits
& MACH_MSGH_BITS_COMPLEX
) {
1556 mach_msg_body_t
*body
= (mach_msg_body_t
*) (msg
+ 1);
1557 mach_msg_descriptor_t
*saddr
= (mach_msg_descriptor_t
*) ((mach_msg_base_t
*) msg
+ 1);
1558 mach_msg_descriptor_t
*eaddr
= saddr
+ body
->msgh_descriptor_count
;
1559 for ( ; saddr
< eaddr
; saddr
++) {
1560 switch (saddr
->type
.type
) {
1561 case MACH_MSG_PORT_DESCRIPTOR
:;
1562 mach_msg_port_descriptor_t
*dsc
= &saddr
->port
;
1563 if (! printed_header
) print_msg_scan_header();
1564 printed_header
= true;
1565 print_one_port_info("port in body", dsc
->name
, dsc
->disposition
);
1566 // if (clean) mach_port_deallocate(mach_task_self(), dsc->name);
1568 case MACH_MSG_OOL_PORTS_DESCRIPTOR
:;
1569 mach_msg_ool_ports_descriptor_t
*dsc2
= &saddr
->ool_ports
;
1570 mach_port_t
*ports
= (mach_port_t
*) dsc2
->address
;
1571 for (mach_msg_type_number_t j
= 0; j
< dsc2
->count
; j
++, ports
++) {
1572 if (! printed_header
) print_msg_scan_header();
1573 printed_header
= true;
1574 print_one_port_info("port in OOL ports", *ports
, dsc2
->disposition
);
1583 /* rl is unlocked, rlm locked on entrance and exit */
1584 static int32_t __CFRunLoopRun(CFRunLoopRef rl
, CFRunLoopModeRef rlm
, CFTimeInterval seconds
, Boolean stopAfterHandle
, Boolean waitIfEmpty
) { /* DOES CALLOUT */
1586 #if DEPLOYMENT_TARGET_MACOSX
1587 mach_port_name_t timeoutPort
= MACH_PORT_NULL
;
1588 Boolean timeoutPortAdded
= false;
1590 Boolean poll
= false;
1591 Boolean firstPass
= true;
1593 if (__CFRunLoopIsStopped(rl
)) {
1594 return kCFRunLoopRunStopped
;
1595 } else if (rlm
->_stopped
) {
1596 rlm
->_stopped
= false;
1597 return kCFRunLoopRunStopped
;
1599 if (seconds
<= 0.0) {
1601 } else if (3.1556952e+9 < seconds
) {
1602 termTSR
= LLONG_MAX
;
1604 termTSR
= (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds
);
1605 #if DEPLOYMENT_TARGET_MACOSX
1606 timeoutPort
= mk_timer_create();
1607 mk_timer_arm(timeoutPort
, __CFUInt64ToAbsoluteTime(termTSR
));
1610 if (seconds
<= 0.0) {
1613 if (rl
== _CFRunLoop0(kNilPthreadT
)) _LastMainWaitSet
= CFPORT_NULL
;
1615 __CFPortSet waitSet
= CFPORT_NULL
;
1616 waitSet
= CFPORT_NULL
;
1617 Boolean destroyWaitSet
= false;
1618 CFRunLoopSourceRef rls
;
1619 #if DEPLOYMENT_TARGET_MACOSX
1620 mach_msg_header_t
*msg
;
1622 uint8_t buffer
[1024 + 80] = {0}; // large enough for 1k of inline payload; must be zeroed for GC
1624 CFArrayRef timersToCall
= NULL
;
1626 int32_t returnValue
= 0;
1627 Boolean sourceHandledThisLoop
= false;
1629 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeTimers
);
1630 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeSources
);
1632 sourceHandledThisLoop
= __CFRunLoopDoSources0(rl
, rlm
, stopAfterHandle
);
1634 if (sourceHandledThisLoop
) {
1639 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopBeforeWaiting
);
1640 __CFRunLoopSetSleeping(rl
);
1642 if (NULL
!= rlm
->_submodes
) {
1643 // !!! what do we do if this doesn't succeed?
1644 waitSet
= __CFPortSetAllocate();
1645 if (CFPORT_NULL
== waitSet
) HALT
;
1646 __CFRunLoopModeUnlock(rlm
);
1647 __CFRunLoopLock(rl
);
1648 __CFRunLoopModeLock(rlm
);
1649 __CFRunLoopModeAddPortsToPortSet(rl
, rlm
, waitSet
);
1650 __CFRunLoopUnlock(rl
);
1651 #if DEPLOYMENT_TARGET_MACOSX
1652 if (CFPORT_NULL
!= timeoutPort
) {
1653 __CFPortSetInsert(timeoutPort
, waitSet
);
1656 destroyWaitSet
= true;
1658 waitSet
= rlm
->_portSet
;
1659 #if DEPLOYMENT_TARGET_MACOSX
1660 if (!timeoutPortAdded
&& CFPORT_NULL
!= timeoutPort
) {
1661 __CFPortSetInsert(timeoutPort
, waitSet
);
1662 timeoutPortAdded
= true;
1666 if (rl
== _CFRunLoop0(kNilPthreadT
)) _LastMainWaitSet
= waitSet
;
1667 __CFRunLoopModeUnlock(rlm
);
1669 #if DEPLOYMENT_TARGET_MACOSX
1670 msg
= (mach_msg_header_t
*)buffer
;
1671 msg
->msgh_size
= sizeof(buffer
);
1673 /* In that sleep of death what nightmares may come ... */
1676 msg
->msgh_local_port
= waitSet
;
1677 msg
->msgh_remote_port
= MACH_PORT_NULL
;
1679 ret
= mach_msg(msg
, MACH_RCV_MSG
|MACH_RCV_LARGE
|(poll
? MACH_RCV_TIMEOUT
: 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT
), 0, msg
->msgh_size
, waitSet
, 0, MACH_PORT_NULL
);
1680 if (MACH_RCV_TOO_LARGE
== ret
) {
1681 uint32_t newSize
= round_msg(msg
->msgh_size
) + sizeof(mach_msg_audit_trailer_t
);
1682 if (msg
== (mach_msg_header_t
*)buffer
) msg
= NULL
;
1683 msg
= CFAllocatorReallocate(kCFAllocatorSystemDefault
, msg
, newSize
, 0);
1684 msg
->msgh_size
= newSize
;
1686 } else if (MACH_RCV_TIMED_OUT
== ret
) {
1687 // timeout, for poll
1688 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
1690 } else if (MACH_MSG_SUCCESS
!= ret
) {
1693 #elif defined(__WIN32__)
1694 DWORD waitResult
= WAIT_TIMEOUT
;
1695 HANDLE handleBuf
[MAXIMUM_WAIT_OBJECTS
];
1697 uint32_t handleCount
;
1698 Boolean freeHandles
;
1699 if (destroyWaitSet
) {
1700 // wait set is a local, no one else could modify it, no need to copy handles
1701 handles
= waitSet
->handles
;
1702 handleCount
= waitSet
->used
;
1703 freeHandles
= FALSE
;
1705 // copy out the handles to be safe from other threads at work
1706 handles
= __CFPortSetGetPorts(waitSet
, handleBuf
, MAXIMUM_WAIT_OBJECTS
, &handleCount
);
1707 freeHandles
= (handles
!= handleBuf
);
1709 // should msgQMask be an OR'ing of this and all submodes' masks?
1710 if (0 == GetQueueStatus(rlm
->_msgQMask
)) {
1715 __CFRunLoopModeLock(rlm
);
1716 int64_t nextStop
= __CFRunLoopGetNextTimerFireTSR(rl
, rlm
);
1719 else if (nextStop
> termTSR
)
1721 // else the next stop is dictated by the next timer
1722 int64_t timeoutTSR
= nextStop
- __CFReadTSR();
1726 CFTimeInterval timeoutCF
= __CFTSRToTimeInterval(timeoutTSR
) * 1000;
1727 if (timeoutCF
> MAXDWORD
)
1730 timeout
= timeoutCF
;
1733 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s)- about to wait for %d objects, wakeupport is %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), handleCount
, rl
->_wakeUpPort
); }
1734 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("All RLM sources = %@"), rlm
->_sources
); }
1735 waitResult
= MsgWaitForMultipleObjects(__CFMin(handleCount
, MAXIMUM_WAIT_OBJECTS
), handles
, false, timeout
, rlm
->_msgQMask
);
1736 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s)- waitResult was %d"), CFRunLoopGetCurrent(), *_CFGetProgname(), waitResult
); }
1738 ResetEvent(rl
->_wakeUpPort
);
1740 if (destroyWaitSet
) {
1741 __CFPortSetFree(waitSet
);
1742 if (rl
== _CFRunLoop0(kNilPthreadT
)) _LastMainWaitSet
= 0;
1744 __CFRunLoopLock(rl
);
1745 __CFRunLoopModeLock(rlm
);
1746 __CFRunLoopUnlock(rl
);
1748 __CFRunLoopUnsetSleeping(rl
);
1749 __CFRunLoopDoObservers(rl
, rlm
, kCFRunLoopAfterWaiting
);
1752 __CFRunLoopModeUnlock(rlm
);
1753 __CFRunLoopLock(rl
);
1754 __CFRunLoopModeLock(rlm
);
1756 __CFPort livePort
= CFPORT_NULL
;
1757 #if DEPLOYMENT_TARGET_MACOSX
1759 livePort
= msg
->msgh_local_port
;
1761 #elif defined(__WIN32__)
1762 CFAssert2(waitResult
!= WAIT_FAILED
, __kCFLogAssertion
, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__
, GetLastError());
1763 if (waitResult
== WAIT_TIMEOUT
) {
1764 // do nothing, just return to caller
1765 } else if (waitResult
>= WAIT_OBJECT_0
&& waitResult
< WAIT_OBJECT_0
+handleCount
) {
1766 // a handle was signalled
1767 livePort
= handles
[waitResult
-WAIT_OBJECT_0
];
1768 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("%p (%s)- Resetting event %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), livePort
); }
1769 } else if (waitResult
== WAIT_OBJECT_0
+handleCount
) {
1770 // windows message received - the CFWindowsMessageQueue will pick this up when
1771 // the v0 RunLoopSources get their chance
1772 } else if (waitResult
>= WAIT_ABANDONED_0
&& waitResult
< WAIT_ABANDONED_0
+handleCount
) {
1773 // an "abandoned mutex object"
1774 livePort
= handles
[waitResult
-WAIT_ABANDONED_0
];
1776 CFAssert2(waitResult
== WAIT_FAILED
, __kCFLogAssertion
, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__
, waitResult
);
1779 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, handles
);
1780 timersToCall
= __CFRunLoopTimersToFire(rl
, rlm
);
1783 if (CFPORT_NULL
== livePort
) {
1784 __CFRunLoopUnlock(rl
);
1785 } else if (livePort
== rl
->_wakeUpPort
) {
1787 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("wakeupPort was signalled")); }
1788 __CFRunLoopUnlock(rl
);
1790 #if DEPLOYMENT_TARGET_MACOSX
1791 else if (livePort
== timeoutPort
) {
1792 returnValue
= kCFRunLoopRunTimedOut
;
1793 __CFRunLoopUnlock(rl
);
1794 } else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
1795 mach_msg_header_t
*reply
= NULL
;
1796 __CFRunLoopUnlock(rl
);
1797 // mach_msg_scan(msg, 0);
1798 if (__CFRunLoopDoSource1(rl
, rlm
, rls
, msg
, msg
->msgh_size
, &reply
)) {
1799 sourceHandledThisLoop
= true;
1801 // mach_msg_scan(msg, 1);
1802 if (NULL
!= reply
) {
1803 ret
= mach_msg(reply
, MACH_SEND_MSG
, reply
->msgh_size
, 0, MACH_PORT_NULL
, 0, MACH_PORT_NULL
);
1804 //#warning CF: what should be done with the return value?
1805 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, reply
);
1808 CFRunLoopTimerRef rlt
;
1809 rlt
= __CFRunLoopModeFindTimerForMachPort(rlm
, livePort
);
1810 __CFRunLoopUnlock(rl
);
1812 __CFRunLoopDoTimer(rl
, rlm
, rlt
);
1815 if (msg
!= (mach_msg_header_t
*)buffer
) CFAllocatorDeallocate(kCFAllocatorSystemDefault
, msg
);
1817 else if (NULL
!= (rls
= __CFRunLoopModeFindSourceForMachPort(rl
, rlm
, livePort
))) {
1818 __CFRunLoopUnlock(rl
);
1819 if (_LogCFRunLoop
) { CFLog(kCFLogLevelDebug
, CFSTR("Source %@ was signalled"), rls
); }
1820 if (__CFRunLoopDoSource1(rl
, rlm
, rls
)) {
1821 sourceHandledThisLoop
= true;
1826 __CFRunLoopModeUnlock(rlm
); // locks must be taken in order
1827 __CFRunLoopLock(rl
);
1828 __CFRunLoopModeLock(rlm
);
1829 if (sourceHandledThisLoop
&& stopAfterHandle
) {
1830 returnValue
= kCFRunLoopRunHandledSource
;
1831 // If we're about to timeout, but we just did a zero-timeout poll that only found our own
1832 // internal wakeup signal on the first look at the portset, we'll go around the loop one
1833 // more time, so as not to starve a v1 source that was just added along with a runloop wakeup.
1834 } else if (0 != returnValue
|| (uint64_t)termTSR
<= __CFReadTSR()) {
1835 returnValue
= kCFRunLoopRunTimedOut
;
1836 } else if (__CFRunLoopIsStopped(rl
)) {
1837 returnValue
= kCFRunLoopRunStopped
;
1838 } else if (rlm
->_stopped
) {
1839 rlm
->_stopped
= false;
1840 returnValue
= kCFRunLoopRunStopped
;
1841 } else if (!waitIfEmpty
&& __CFRunLoopModeIsEmpty(rl
, rlm
)) {
1842 returnValue
= kCFRunLoopRunFinished
;
1844 __CFRunLoopUnlock(rl
);
1845 if (0 != returnValue
) {
1846 #if DEPLOYMENT_TARGET_MACOSX
1847 if (MACH_PORT_NULL
!= timeoutPort
) {
1848 if (!destroyWaitSet
) __CFPortSetRemove(timeoutPort
, waitSet
);
1849 mk_timer_destroy(timeoutPort
);
1858 SInt32
CFRunLoopRunSpecific(CFRunLoopRef rl
, CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
1860 if (__CFRunLoopIsDeallocating(rl
)) return kCFRunLoopRunFinished
;
1861 __CFRunLoopLock(rl
);
1862 CFRunLoopModeRef currentMode
= __CFRunLoopFindMode(rl
, modeName
, false);
1863 if (NULL
== currentMode
|| __CFRunLoopModeIsEmpty(rl
, currentMode
)) {
1864 if (currentMode
) __CFRunLoopModeUnlock(currentMode
);
1865 __CFRunLoopUnlock(rl
);
1866 return kCFRunLoopRunFinished
;
1868 uint32_t *previousStopped
= (uint32_t *)rl
->_stopped
;
1869 rl
->_stopped
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, 4 * sizeof(uint32_t), 0);
1870 rl
->_stopped
[0] = 0x4346524C;
1871 rl
->_stopped
[1] = 0x4346524C; // 'CFRL'
1872 rl
->_stopped
[2] = 0x00000000; // here the value is stored
1873 rl
->_stopped
[3] = 0x4346524C;
1874 CFRunLoopModeRef previousMode
= rl
->_currentMode
;
1875 rl
->_currentMode
= currentMode
;
1876 __CFRunLoopUnlock(rl
);
1878 __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopEntry
);
1879 result
= __CFRunLoopRun(rl
, currentMode
, seconds
, returnAfterSourceHandled
, false);
1880 __CFRunLoopDoObservers(rl
, currentMode
, kCFRunLoopExit
);
1881 __CFRunLoopModeUnlock(currentMode
);
1882 __CFRunLoopLock(rl
);
1883 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, (uint32_t *)rl
->_stopped
);
1884 rl
->_stopped
= previousStopped
;
1885 rl
->_currentMode
= previousMode
;
1886 __CFRunLoopUnlock(rl
);
1890 void CFRunLoopRun(void) { /* DOES CALLOUT */
1893 result
= CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode
, 1.0e10
, false);
1895 } while (kCFRunLoopRunStopped
!= result
&& kCFRunLoopRunFinished
!= result
);
1898 SInt32
CFRunLoopRunInMode(CFStringRef modeName
, CFTimeInterval seconds
, Boolean returnAfterSourceHandled
) { /* DOES CALLOUT */
1900 return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName
, seconds
, returnAfterSourceHandled
);
1903 static void __CFRunLoopFindMinTimer(const void *value
, void *ctx
) {
1904 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)value
;
1905 if (__CFIsValid(rlt
)) {
1906 CFRunLoopTimerRef
*result
= ctx
;
1907 if (NULL
== *result
|| rlt
->_fireTSR
< (*result
)->_fireTSR
) {
1913 static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl
, CFRunLoopModeRef rlm
) {
1914 CFRunLoopTimerRef result
= NULL
;
1915 int64_t fireTime
= 0;
1917 if (NULL
!= rlm
->_timers
&& 0 < CFSetGetCount(rlm
->_timers
)) {
1918 __CFRunLoopTimerFireTSRLock();
1919 CFSetApplyFunction(rlm
->_timers
, (__CFRunLoopFindMinTimer
), &result
);
1921 fireTime
= result
->_fireTSR
;
1922 __CFRunLoopTimerFireTSRUnlock();
1924 if (NULL
!= rlm
->_submodes
) {
1926 for (idx
= 0, cnt
= CFArrayGetCount(rlm
->_submodes
); idx
< cnt
; idx
++) {
1927 CFStringRef modeName
= (CFStringRef
)CFArrayGetValueAtIndex(rlm
->_submodes
, idx
);
1928 CFRunLoopModeRef subrlm
;
1929 subrlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1930 if (NULL
!= subrlm
) {
1931 int64_t newFireTime
= __CFRunLoopGetNextTimerFireTSR(rl
, subrlm
);
1932 __CFRunLoopModeUnlock(subrlm
);
1933 if (fireTime
== 0 || (newFireTime
!= 0 && newFireTime
< fireTime
))
1934 fireTime
= newFireTime
;
1938 __CFRunLoopModeUnlock(rlm
);
1943 CFAbsoluteTime
CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl
, CFStringRef modeName
) {
1945 CFRunLoopModeRef rlm
;
1947 __CFRunLoopLock(rl
);
1948 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
1949 __CFRunLoopUnlock(rl
);
1950 fireTSR
= __CFRunLoopGetNextTimerFireTSR(rl
, rlm
);
1951 int64_t now2
= (int64_t)mach_absolute_time();
1952 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
1953 return (0 == fireTSR
) ? 0.0 : (now1
+ __CFTSRToTimeInterval(fireTSR
- now2
));
1956 Boolean
CFRunLoopIsWaiting(CFRunLoopRef rl
) {
1958 return __CFRunLoopIsSleeping(rl
);
1961 void CFRunLoopWakeUp(CFRunLoopRef rl
) {
1963 #if DEPLOYMENT_TARGET_MACOSX
1965 /* We unconditionally try to send the message, since we don't want
1966 * to lose a wakeup, but the send may fail if there is already a
1967 * wakeup pending, since the queue length is 1. */
1968 ret
= __CFSendTrivialMachMessage(rl
->_wakeUpPort
, 0, MACH_SEND_TIMEOUT
, 0);
1969 if (ret
!= MACH_MSG_SUCCESS
&& ret
!= MACH_SEND_TIMED_OUT
) {
1973 SetEvent(rl
->_wakeUpPort
);
1977 void CFRunLoopStop(CFRunLoopRef rl
) {
1979 __CFRunLoopLock(rl
);
1980 __CFRunLoopSetStopped(rl
);
1981 __CFRunLoopUnlock(rl
);
1982 CFRunLoopWakeUp(rl
);
1985 CF_EXPORT
void _CFRunLoopStopMode(CFRunLoopRef rl
, CFStringRef modeName
) {
1987 CFRunLoopModeRef rlm
;
1988 __CFRunLoopLock(rl
);
1989 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
1990 __CFRunLoopUnlock(rl
);
1992 rlm
->_stopped
= true;
1993 __CFRunLoopModeUnlock(rlm
);
1995 CFRunLoopWakeUp(rl
);
1998 CF_EXPORT Boolean
_CFRunLoopModeContainsMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef candidateContainedName
) {
2000 CFRunLoopModeRef rlm
;
2001 if (modeName
== kCFRunLoopCommonModes
|| candidateContainedName
== kCFRunLoopCommonModes
) {
2003 } else if (CFEqual(modeName
, candidateContainedName
)) {
2006 __CFRunLoopLock(rl
);
2007 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2008 __CFRunLoopUnlock(rl
);
2010 CFArrayRef submodes
;
2011 if (NULL
== rlm
->_submodes
) {
2012 __CFRunLoopModeUnlock(rlm
);
2015 if (CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), candidateContainedName
)) {
2016 __CFRunLoopModeUnlock(rlm
);
2019 submodes
= (NULL
!= rlm
->_submodes
&& 0 < CFArrayGetCount(rlm
->_submodes
)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault
, rlm
->_submodes
) : NULL
;
2020 __CFRunLoopModeUnlock(rlm
);
2021 if (NULL
!= submodes
) {
2023 for (idx
= 0, cnt
= CFArrayGetCount(submodes
); idx
< cnt
; idx
++) {
2024 CFStringRef subname
= (CFStringRef
)CFArrayGetValueAtIndex(submodes
, idx
);
2025 if (_CFRunLoopModeContainsMode(rl
, subname
, candidateContainedName
)) {
2026 CFRelease(submodes
);
2030 CFRelease(submodes
);
2036 CF_EXPORT
void _CFRunLoopAddModeToMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef toModeName
) {
2038 CFRunLoopModeRef rlm
;
2039 if (__CFRunLoopIsDeallocating(rl
)) return;
2040 // should really do a recursive check here, to make sure that a cycle isn't
2041 // introduced; of course, if that happens, you aren't going to get very far.
2042 if (modeName
== kCFRunLoopCommonModes
|| toModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, toModeName
)) {
2045 __CFRunLoopLock(rl
);
2046 rlm
= __CFRunLoopFindMode(rl
, toModeName
, true);
2047 __CFRunLoopUnlock(rl
);
2049 if (NULL
== rlm
->_submodes
) {
2050 rlm
->_submodes
= CFArrayCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeArrayCallBacks
);
2052 if (!CFArrayContainsValue(rlm
->_submodes
, CFRangeMake(0, CFArrayGetCount(rlm
->_submodes
)), modeName
)) {
2053 CFArrayAppendValue(rlm
->_submodes
, modeName
);
2055 __CFRunLoopModeUnlock(rlm
);
2060 CF_EXPORT
void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl
, CFStringRef modeName
, CFStringRef fromModeName
) {
2062 CFRunLoopModeRef rlm
;
2063 // should really do a recursive check here, to make sure that a cycle isn't
2064 // introduced; of course, if that happens, you aren't going to get very far.
2065 if (modeName
== kCFRunLoopCommonModes
|| fromModeName
== kCFRunLoopCommonModes
|| CFEqual(modeName
, fromModeName
)) {
2068 __CFRunLoopLock(rl
);
2069 rlm
= __CFRunLoopFindMode(rl
, fromModeName
, true);
2070 __CFRunLoopUnlock(rl
);
2072 if (NULL
!= rlm
->_submodes
) {
2073 CFIndex idx
, cnt
= CFArrayGetCount(rlm
->_submodes
);
2074 idx
= CFArrayGetFirstIndexOfValue(rlm
->_submodes
, CFRangeMake(0, cnt
), modeName
);
2075 if (0 <= idx
) CFArrayRemoveValueAtIndex(rlm
->_submodes
, idx
);
2077 __CFRunLoopModeUnlock(rlm
);
2082 Boolean
CFRunLoopContainsSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) {
2084 CFRunLoopModeRef rlm
;
2085 Boolean hasValue
= false;
2086 __CFRunLoopLock(rl
);
2087 if (modeName
== kCFRunLoopCommonModes
) {
2088 if (NULL
!= rl
->_commonModeItems
) {
2089 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rls
);
2091 __CFRunLoopUnlock(rl
);
2093 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2094 __CFRunLoopUnlock(rl
);
2095 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
) {
2096 hasValue
= CFSetContainsValue(rlm
->_sources
, rls
);
2097 __CFRunLoopModeUnlock(rlm
);
2098 } else if (NULL
!= rlm
) {
2099 __CFRunLoopModeUnlock(rlm
);
2105 void CFRunLoopAddSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2107 CFRunLoopModeRef rlm
;
2108 if (__CFRunLoopIsDeallocating(rl
)) return;
2109 if (!__CFIsValid(rls
)) return;
2110 __CFRunLoopLock(rl
);
2111 if (modeName
== kCFRunLoopCommonModes
) {
2112 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2113 if (NULL
== rl
->_commonModeItems
) {
2114 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
2115 _CFSetSetCapacity(rl
->_commonModeItems
, 20);
2117 CFSetAddValue(rl
->_commonModeItems
, rls
);
2118 __CFRunLoopUnlock(rl
);
2120 CFTypeRef context
[2] = {rl
, rls
};
2121 /* add new item to all common-modes */
2122 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2126 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2127 __CFRunLoopUnlock(rl
);
2128 if (NULL
!= rlm
&& NULL
== rlm
->_sources
) {
2129 rlm
->_sources
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
2130 _CFSetSetCapacity(rlm
->_sources
, 10);
2132 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_sources
, rls
)) {
2133 CFSetAddValue(rlm
->_sources
, rls
);
2134 __CFRunLoopModeUnlock(rlm
);
2135 __CFRunLoopSourceSchedule(rls
, rl
, rlm
); /* DOES CALLOUT */
2136 } else if (NULL
!= rlm
) {
2137 __CFRunLoopModeUnlock(rlm
);
2142 void CFRunLoopRemoveSource(CFRunLoopRef rl
, CFRunLoopSourceRef rls
, CFStringRef modeName
) { /* DOES CALLOUT */
2144 CFRunLoopModeRef rlm
;
2145 __CFRunLoopLock(rl
);
2146 if (modeName
== kCFRunLoopCommonModes
) {
2147 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rls
)) {
2148 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2149 CFSetRemoveValue(rl
->_commonModeItems
, rls
);
2150 __CFRunLoopUnlock(rl
);
2152 CFTypeRef context
[2] = {rl
, rls
};
2153 /* remove new item from all common-modes */
2154 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2158 __CFRunLoopUnlock(rl
);
2161 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2162 __CFRunLoopUnlock(rl
);
2163 if (NULL
!= rlm
&& NULL
!= rlm
->_sources
&& CFSetContainsValue(rlm
->_sources
, rls
)) {
2165 CFSetRemoveValue(rlm
->_sources
, rls
);
2166 __CFRunLoopModeUnlock(rlm
);
2167 __CFRunLoopSourceCancel(rls
, rl
, rlm
); /* DOES CALLOUT */
2169 } else if (NULL
!= rlm
) {
2170 __CFRunLoopModeUnlock(rlm
);
2175 Boolean
CFRunLoopContainsObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2177 CFRunLoopModeRef rlm
;
2178 Boolean hasValue
= false;
2179 __CFRunLoopLock(rl
);
2180 if (modeName
== kCFRunLoopCommonModes
) {
2181 if (NULL
!= rl
->_commonModeItems
) {
2182 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlo
);
2184 __CFRunLoopUnlock(rl
);
2186 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2187 __CFRunLoopUnlock(rl
);
2188 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
) {
2189 hasValue
= CFSetContainsValue(rlm
->_observers
, rlo
);
2190 __CFRunLoopModeUnlock(rlm
);
2191 } else if (NULL
!= rlm
) {
2192 __CFRunLoopModeUnlock(rlm
);
2198 void CFRunLoopAddObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2200 CFRunLoopModeRef rlm
;
2201 if (__CFRunLoopIsDeallocating(rl
)) return;
2202 if (!__CFIsValid(rlo
) || (NULL
!= rlo
->_runLoop
&& rlo
->_runLoop
!= rl
)) return;
2203 __CFRunLoopLock(rl
);
2204 if (modeName
== kCFRunLoopCommonModes
) {
2205 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2206 if (NULL
== rl
->_commonModeItems
) {
2207 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
2209 CFSetAddValue(rl
->_commonModeItems
, rlo
);
2210 __CFRunLoopUnlock(rl
);
2212 CFTypeRef context
[2] = {rl
, rlo
};
2213 /* add new item to all common-modes */
2214 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2218 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2219 __CFRunLoopUnlock(rl
);
2220 if (NULL
!= rlm
&& NULL
== rlm
->_observers
) {
2221 rlm
->_observers
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
2223 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_observers
, rlo
)) {
2224 CFSetAddValue(rlm
->_observers
, rlo
);
2225 __CFRunLoopModeUnlock(rlm
);
2226 __CFRunLoopObserverSchedule(rlo
, rl
, rlm
);
2227 } else if (NULL
!= rlm
) {
2228 __CFRunLoopModeUnlock(rlm
);
2233 void CFRunLoopRemoveObserver(CFRunLoopRef rl
, CFRunLoopObserverRef rlo
, CFStringRef modeName
) {
2235 CFRunLoopModeRef rlm
;
2236 __CFRunLoopLock(rl
);
2237 if (modeName
== kCFRunLoopCommonModes
) {
2238 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlo
)) {
2239 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2240 CFSetRemoveValue(rl
->_commonModeItems
, rlo
);
2241 __CFRunLoopUnlock(rl
);
2243 CFTypeRef context
[2] = {rl
, rlo
};
2244 /* remove new item from all common-modes */
2245 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2249 __CFRunLoopUnlock(rl
);
2252 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2253 __CFRunLoopUnlock(rl
);
2254 if (NULL
!= rlm
&& NULL
!= rlm
->_observers
&& CFSetContainsValue(rlm
->_observers
, rlo
)) {
2256 CFSetRemoveValue(rlm
->_observers
, rlo
);
2257 __CFRunLoopModeUnlock(rlm
);
2258 __CFRunLoopObserverCancel(rlo
, rl
, rlm
);
2260 } else if (NULL
!= rlm
) {
2261 __CFRunLoopModeUnlock(rlm
);
2266 Boolean
CFRunLoopContainsTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2268 CFRunLoopModeRef rlm
;
2269 Boolean hasValue
= false;
2270 __CFRunLoopLock(rl
);
2271 if (modeName
== kCFRunLoopCommonModes
) {
2272 if (NULL
!= rl
->_commonModeItems
) {
2273 hasValue
= CFSetContainsValue(rl
->_commonModeItems
, rlt
);
2275 __CFRunLoopUnlock(rl
);
2277 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2278 __CFRunLoopUnlock(rl
);
2279 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
) {
2280 hasValue
= CFSetContainsValue(rlm
->_timers
, rlt
);
2281 __CFRunLoopModeUnlock(rlm
);
2282 } else if (NULL
!= rlm
) {
2283 __CFRunLoopModeUnlock(rlm
);
2289 void CFRunLoopAddTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2291 CFRunLoopModeRef rlm
;
2292 if (__CFRunLoopIsDeallocating(rl
)) return;
2293 if (!__CFIsValid(rlt
) || (NULL
!= rlt
->_runLoop
&& rlt
->_runLoop
!= rl
)) return;
2294 __CFRunLoopLock(rl
);
2295 if (modeName
== kCFRunLoopCommonModes
) {
2296 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2297 if (NULL
== rl
->_commonModeItems
) {
2298 rl
->_commonModeItems
= CFSetCreateMutable(CFGetAllocator(rl
), 0, &kCFTypeSetCallBacks
);
2300 CFSetAddValue(rl
->_commonModeItems
, rlt
);
2301 __CFRunLoopUnlock(rl
);
2303 CFTypeRef context
[2] = {rl
, rlt
};
2304 /* add new item to all common-modes */
2305 CFSetApplyFunction(set
, (__CFRunLoopAddItemToCommonModes
), (void *)context
);
2309 rlm
= __CFRunLoopFindMode(rl
, modeName
, true);
2310 __CFRunLoopUnlock(rl
);
2311 if (NULL
!= rlm
&& NULL
== rlm
->_timers
) {
2312 rlm
->_timers
= CFSetCreateMutable(CFGetAllocator(rlm
), 0, &kCFTypeSetCallBacks
);
2314 if (NULL
!= rlm
&& !CFSetContainsValue(rlm
->_timers
, rlt
)) {
2315 CFSetAddValue(rlm
->_timers
, rlt
);
2316 __CFRunLoopModeUnlock(rlm
);
2317 __CFRunLoopTimerSchedule(rlt
, rl
, rlm
);
2318 } else if (NULL
!= rlm
) {
2319 __CFRunLoopModeUnlock(rlm
);
2324 void CFRunLoopRemoveTimer(CFRunLoopRef rl
, CFRunLoopTimerRef rlt
, CFStringRef modeName
) {
2326 CFRunLoopModeRef rlm
;
2327 __CFRunLoopLock(rl
);
2328 if (modeName
== kCFRunLoopCommonModes
) {
2329 if (NULL
!= rl
->_commonModeItems
&& CFSetContainsValue(rl
->_commonModeItems
, rlt
)) {
2330 CFSetRef set
= rl
->_commonModes
? CFSetCreateCopy(kCFAllocatorSystemDefault
, rl
->_commonModes
) : NULL
;
2331 CFSetRemoveValue(rl
->_commonModeItems
, rlt
);
2332 __CFRunLoopUnlock(rl
);
2334 CFTypeRef context
[2] = {rl
, rlt
};
2335 /* remove new item from all common-modes */
2336 CFSetApplyFunction(set
, (__CFRunLoopRemoveItemFromCommonModes
), (void *)context
);
2340 __CFRunLoopUnlock(rl
);
2343 rlm
= __CFRunLoopFindMode(rl
, modeName
, false);
2344 __CFRunLoopUnlock(rl
);
2345 if (NULL
!= rlm
&& NULL
!= rlm
->_timers
&& CFSetContainsValue(rlm
->_timers
, rlt
)) {
2347 CFSetRemoveValue(rlm
->_timers
, rlt
);
2348 __CFRunLoopModeUnlock(rlm
);
2349 __CFRunLoopTimerCancel(rlt
, rl
, rlm
);
2351 } else if (NULL
!= rlm
) {
2352 __CFRunLoopModeUnlock(rlm
);
2358 /* CFRunLoopSource */
2360 static Boolean
__CFRunLoopSourceEqual(CFTypeRef cf1
, CFTypeRef cf2
) { /* DOES CALLOUT */
2361 CFRunLoopSourceRef rls1
= (CFRunLoopSourceRef
)cf1
;
2362 CFRunLoopSourceRef rls2
= (CFRunLoopSourceRef
)cf2
;
2363 if (rls1
== rls2
) return true;
2364 if (rls1
->_order
!= rls2
->_order
) return false;
2365 if (rls1
->_context
.version0
.version
!= rls2
->_context
.version0
.version
) return false;
2366 if (rls1
->_context
.version0
.hash
!= rls2
->_context
.version0
.hash
) return false;
2367 if (rls1
->_context
.version0
.equal
!= rls2
->_context
.version0
.equal
) return false;
2368 if (0 == rls1
->_context
.version0
.version
&& rls1
->_context
.version0
.perform
!= rls2
->_context
.version0
.perform
) return false;
2369 if (1 == rls1
->_context
.version0
.version
&& rls1
->_context
.version1
.perform
!= rls2
->_context
.version1
.perform
) return false;
2370 if (rls1
->_context
.version0
.equal
)
2371 return rls1
->_context
.version0
.equal(rls1
->_context
.version0
.info
, rls2
->_context
.version0
.info
);
2372 return (rls1
->_context
.version0
.info
== rls2
->_context
.version0
.info
);
2375 static CFHashCode
__CFRunLoopSourceHash(CFTypeRef cf
) { /* DOES CALLOUT */
2376 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2377 if (rls
->_context
.version0
.hash
)
2378 return rls
->_context
.version0
.hash(rls
->_context
.version0
.info
);
2379 return (CFHashCode
)rls
->_context
.version0
.info
;
2382 static CFStringRef
__CFRunLoopSourceCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2383 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2385 CFStringRef contextDesc
= NULL
;
2386 if (NULL
!= rls
->_context
.version0
.copyDescription
) {
2387 contextDesc
= rls
->_context
.version0
.copyDescription(rls
->_context
.version0
.info
);
2389 if (NULL
== contextDesc
) {
2390 void *addr
= rls
->_context
.version0
.version
== 0 ? (void *)rls
->_context
.version0
.perform
: (rls
->_context
.version0
.version
== 1 ? (void *)rls
->_context
.version1
.perform
: NULL
);
2391 #if DEPLOYMENT_TARGET_MACOSX
2393 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2394 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rls
), NULL
, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls
->_context
.version0
.version
, rls
->_context
.version0
.info
, name
, addr
);
2396 #error Unknown or unspecified DEPLOYMENT_TARGET
2399 result
= CFStringCreateWithFormat(CFGetAllocator(rls
), NULL
, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf
, CFGetAllocator(rls
), lockCount(rls
->_lock
) ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls
) ? "Yes" : "No", __CFIsValid(rls
) ? "Yes" : "No", rls
->_order
, contextDesc
);
2400 CFRelease(contextDesc
);
2404 static void __CFRunLoopSourceDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2405 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)cf
;
2406 CFRunLoopSourceInvalidate(rls
);
2407 if (rls
->_context
.version0
.release
) {
2408 rls
->_context
.version0
.release(rls
->_context
.version0
.info
);
2412 static const CFRuntimeClass __CFRunLoopSourceClass
= {
2413 _kCFRuntimeScannedObject
,
2417 __CFRunLoopSourceDeallocate
,
2418 __CFRunLoopSourceEqual
,
2419 __CFRunLoopSourceHash
,
2421 __CFRunLoopSourceCopyDescription
2424 __private_extern__
void __CFRunLoopSourceInitialize(void) {
2425 __kCFRunLoopSourceTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopSourceClass
);
2428 CFTypeID
CFRunLoopSourceGetTypeID(void) {
2429 return __kCFRunLoopSourceTypeID
;
2432 CFRunLoopSourceRef
CFRunLoopSourceCreate(CFAllocatorRef allocator
, CFIndex order
, CFRunLoopSourceContext
*context
) {
2434 CFRunLoopSourceRef memory
;
2436 if (NULL
== context
) HALT
;
2437 size
= sizeof(struct __CFRunLoopSource
) - sizeof(CFRuntimeBase
);
2438 memory
= (CFRunLoopSourceRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopSourceTypeID
, size
, NULL
);
2439 if (NULL
== memory
) {
2442 __CFSetValid(memory
);
2443 __CFRunLoopSourceUnsetSignaled(memory
);
2444 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
2446 memory
->_order
= order
;
2447 memory
->_runLoops
= NULL
;
2449 switch (context
->version
) {
2451 size
= sizeof(CFRunLoopSourceContext
);
2454 size
= sizeof(CFRunLoopSourceContext1
);
2456 #if DEPLOYMENT_TARGET_MACOSX
2458 size
= sizeof(CFRunLoopSourceContext2
);
2462 CF_WRITE_BARRIER_MEMMOVE(&memory
->_context
, context
, size
);
2463 if (context
->retain
) {
2464 memory
->_context
.version0
.info
= (void *)context
->retain(context
->info
);
2469 CFIndex
CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls
) {
2471 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2475 static void __CFRunLoopSourceRemoveFromRunLoop(const void *value
, void *context
) {
2476 CFRunLoopRef rl
= (CFRunLoopRef
)value
;
2477 CFTypeRef
*params
= context
;
2478 CFRunLoopSourceRef rls
= (CFRunLoopSourceRef
)params
[0];
2481 if (rl
== params
[1]) return;
2482 array
= CFRunLoopCopyAllModes(rl
);
2483 for (idx
= CFArrayGetCount(array
); idx
--;) {
2484 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2485 CFRunLoopRemoveSource(rl
, rls
, modeName
);
2487 CFRunLoopRemoveSource(rl
, rls
, kCFRunLoopCommonModes
);
2492 void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls
) {
2494 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2496 __CFRunLoopSourceLock(rls
);
2497 if (__CFIsValid(rls
)) {
2498 __CFUnsetValid(rls
);
2499 __CFRunLoopSourceUnsetSignaled(rls
);
2500 if (NULL
!= rls
->_runLoops
) {
2501 CFTypeRef params
[2] = {rls
, NULL
};
2502 CFBagRef bag
= CFBagCreateCopy(kCFAllocatorSystemDefault
, rls
->_runLoops
);
2503 CFRelease(rls
->_runLoops
);
2504 rls
->_runLoops
= NULL
;
2505 __CFRunLoopSourceUnlock(rls
);
2506 CFBagApplyFunction(bag
, (__CFRunLoopSourceRemoveFromRunLoop
), params
);
2509 __CFRunLoopSourceUnlock(rls
);
2511 /* for hashing- and equality-use purposes, can't actually release the context here */
2513 __CFRunLoopSourceUnlock(rls
);
2518 Boolean
CFRunLoopSourceIsValid(CFRunLoopSourceRef rls
) {
2520 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2521 return __CFIsValid(rls
);
2524 void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls
, CFRunLoopSourceContext
*context
) {
2526 __CFGenericValidateType(rls
, __kCFRunLoopSourceTypeID
);
2527 CFAssert1(0 == context
->version
|| 1 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__
);
2529 switch (context
->version
) {
2531 size
= sizeof(CFRunLoopSourceContext
);
2534 size
= sizeof(CFRunLoopSourceContext1
);
2536 #if DEPLOYMENT_TARGET_MACOSX
2538 size
= sizeof(CFRunLoopSourceContext2
);
2542 memmove(context
, &rls
->_context
, size
);
2545 void CFRunLoopSourceSignal(CFRunLoopSourceRef rls
) {
2547 __CFRunLoopSourceLock(rls
);
2548 if (__CFIsValid(rls
)) {
2549 __CFRunLoopSourceSetSignaled(rls
);
2551 __CFRunLoopSourceUnlock(rls
);
2554 Boolean
CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls
) {
2556 __CFRunLoopSourceLock(rls
);
2557 Boolean ret
= __CFRunLoopSourceIsSignaled(rls
) ? true : false;
2558 __CFRunLoopSourceUnlock(rls
);
2562 /* CFRunLoopObserver */
2564 static CFStringRef
__CFRunLoopObserverCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2565 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
2567 CFStringRef contextDesc
= NULL
;
2568 if (NULL
!= rlo
->_context
.copyDescription
) {
2569 contextDesc
= rlo
->_context
.copyDescription(rlo
->_context
.info
);
2572 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rlo
), NULL
, CFSTR("<CFRunLoopObserver context %p>"), rlo
->_context
.info
);
2574 #if DEPLOYMENT_TARGET_MACOSX
2575 void *addr
= rlo
->_callout
;
2577 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2578 result
= CFStringCreateWithFormat(CFGetAllocator(rlo
), NULL
, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlo
), lockCount(rlo
->_lock
) ? "Yes" : "No", __CFIsValid(rlo
) ? "Yes" : "No", rlo
->_activities
, __CFRunLoopObserverRepeats(rlo
) ? "Yes" : "No", rlo
->_order
, name
, addr
, contextDesc
);
2580 #error Unknown or unspecified DEPLOYMENT_TARGET
2582 CFRelease(contextDesc
);
2586 static void __CFRunLoopObserverDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2587 CFRunLoopObserverRef rlo
= (CFRunLoopObserverRef
)cf
;
2588 CFRunLoopObserverInvalidate(rlo
);
2591 static const CFRuntimeClass __CFRunLoopObserverClass
= {
2593 "CFRunLoopObserver",
2596 __CFRunLoopObserverDeallocate
,
2600 __CFRunLoopObserverCopyDescription
2603 __private_extern__
void __CFRunLoopObserverInitialize(void) {
2604 __kCFRunLoopObserverTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopObserverClass
);
2607 CFTypeID
CFRunLoopObserverGetTypeID(void) {
2608 return __kCFRunLoopObserverTypeID
;
2611 CFRunLoopObserverRef
CFRunLoopObserverCreate(CFAllocatorRef allocator
, CFOptionFlags activities
, Boolean repeats
, CFIndex order
, CFRunLoopObserverCallBack callout
, CFRunLoopObserverContext
*context
) {
2613 CFRunLoopObserverRef memory
;
2615 size
= sizeof(struct __CFRunLoopObserver
) - sizeof(CFRuntimeBase
);
2616 memory
= (CFRunLoopObserverRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopObserverTypeID
, size
, NULL
);
2617 if (NULL
== memory
) {
2620 __CFSetValid(memory
);
2621 __CFRunLoopObserverUnsetFiring(memory
);
2623 __CFRunLoopObserverSetRepeats(memory
);
2625 __CFRunLoopObserverUnsetRepeats(memory
);
2627 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
2628 memory
->_runLoop
= NULL
;
2629 memory
->_rlCount
= 0;
2630 memory
->_activities
= activities
;
2631 memory
->_order
= order
;
2632 memory
->_callout
= callout
;
2634 if (context
->retain
) {
2635 memory
->_context
.info
= (void *)context
->retain(context
->info
);
2637 memory
->_context
.info
= context
->info
;
2639 memory
->_context
.retain
= context
->retain
;
2640 memory
->_context
.release
= context
->release
;
2641 memory
->_context
.copyDescription
= context
->copyDescription
;
2643 memory
->_context
.info
= 0;
2644 memory
->_context
.retain
= 0;
2645 memory
->_context
.release
= 0;
2646 memory
->_context
.copyDescription
= 0;
2651 CFOptionFlags
CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo
) {
2653 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2654 return rlo
->_activities
;
2657 CFIndex
CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo
) {
2659 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2663 Boolean
CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo
) {
2665 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2666 return __CFRunLoopObserverRepeats(rlo
);
2669 void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo
) { /* DOES CALLOUT */
2671 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2673 __CFRunLoopObserverLock(rlo
);
2674 if (__CFIsValid(rlo
)) {
2675 CFRunLoopRef rl
= rlo
->_runLoop
;
2676 __CFUnsetValid(rlo
);
2677 __CFRunLoopObserverUnlock(rlo
);
2681 array
= CFRunLoopCopyAllModes(rl
);
2682 for (idx
= CFArrayGetCount(array
); idx
--;) {
2683 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2684 CFRunLoopRemoveObserver(rl
, rlo
, modeName
);
2686 CFRunLoopRemoveObserver(rl
, rlo
, kCFRunLoopCommonModes
);
2689 if (rlo
->_context
.release
)
2690 rlo
->_context
.release(rlo
->_context
.info
); /* CALLOUT */
2691 rlo
->_context
.info
= NULL
;
2693 __CFRunLoopObserverUnlock(rlo
);
2698 Boolean
CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo
) {
2700 return __CFIsValid(rlo
);
2703 void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo
, CFRunLoopObserverContext
*context
) {
2705 __CFGenericValidateType(rlo
, __kCFRunLoopObserverTypeID
);
2706 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2707 *context
= rlo
->_context
;
2710 /* CFRunLoopTimer */
2712 static CFStringRef
__CFRunLoopTimerCopyDescription(CFTypeRef cf
) { /* DOES CALLOUT */
2713 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
2715 CFStringRef contextDesc
= NULL
;
2717 __CFRunLoopTimerFireTSRLock();
2718 fireTime
= rlt
->_fireTSR
;
2719 __CFRunLoopTimerFireTSRUnlock();
2720 if (NULL
!= rlt
->_context
.copyDescription
) {
2721 contextDesc
= rlt
->_context
.copyDescription(rlt
->_context
.info
);
2723 if (NULL
== contextDesc
) {
2724 contextDesc
= CFStringCreateWithFormat(CFGetAllocator(rlt
), NULL
, CFSTR("<CFRunLoopTimer context %p>"), rlt
->_context
.info
);
2726 int64_t now2
= (int64_t)mach_absolute_time();
2727 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2728 #if DEPLOYMENT_TARGET_MACOSX
2729 void *addr
= rlt
->_callout
;
2731 const char *name
= (dladdr(addr
, &info
) && info
.dli_saddr
== addr
&& info
.dli_sname
) ? info
.dli_sname
: "???";
2732 result
= CFStringCreateWithFormat(CFGetAllocator(rlt
), NULL
, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %s (%p), context = %@}"), cf
, CFGetAllocator(rlt
), lockCount(rlt
->_lock
) ? "Yes" : "No", __CFIsValid(rlt
) ? "Yes" : "No", __CFTSRToTimeInterval(rlt
->_intervalTSR
), now1
+ __CFTSRToTimeInterval(fireTime
- now2
), rlt
->_order
, name
, addr
, contextDesc
);
2734 #error Unknown or unspecified DEPLOYMENT_TARGET
2736 CFRelease(contextDesc
);
2740 static void __CFRunLoopTimerDeallocate(CFTypeRef cf
) { /* DOES CALLOUT */
2741 CFRunLoopTimerRef rlt
= (CFRunLoopTimerRef
)cf
;
2742 CFRunLoopTimerInvalidate(rlt
); /* DOES CALLOUT */
2745 static const CFRuntimeClass __CFRunLoopTimerClass
= {
2750 __CFRunLoopTimerDeallocate
,
2754 __CFRunLoopTimerCopyDescription
2757 __private_extern__
void __CFRunLoopTimerInitialize(void) {
2758 __kCFRunLoopTimerTypeID
= _CFRuntimeRegisterClass(&__CFRunLoopTimerClass
);
2761 CFTypeID
CFRunLoopTimerGetTypeID(void) {
2762 return __kCFRunLoopTimerTypeID
;
2765 CFRunLoopTimerRef
CFRunLoopTimerCreate(CFAllocatorRef allocator
, CFAbsoluteTime fireDate
, CFTimeInterval interval
, CFOptionFlags flags
, CFIndex order
, CFRunLoopTimerCallBack callout
, CFRunLoopTimerContext
*context
) {
2767 CFRunLoopTimerRef memory
;
2769 size
= sizeof(struct __CFRunLoopTimer
) - sizeof(CFRuntimeBase
);
2770 memory
= (CFRunLoopTimerRef
)_CFRuntimeCreateInstance(allocator
, __kCFRunLoopTimerTypeID
, size
, NULL
);
2771 if (NULL
== memory
) {
2774 __CFSetValid(memory
);
2775 __CFRunLoopTimerUnsetFiring(memory
);
2776 __CFRunLoopTimerUnsetDidFire(memory
);
2777 CF_SPINLOCK_INIT_FOR_STRUCTS(memory
->_lock
);
2778 memory
->_runLoop
= NULL
;
2779 memory
->_rlCount
= 0;
2780 #if DEPLOYMENT_TARGET_MACOSX
2781 memory
->_port
= MACH_PORT_NULL
;
2783 memory
->_order
= order
;
2784 int64_t now2
= (int64_t)mach_absolute_time();
2785 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2786 if (3.1556952e+9 < fireDate
) fireDate
= 3.1556952e+9;
2787 if (fireDate
< now1
) {
2788 memory
->_fireTSR
= now2
;
2789 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
2790 memory
->_fireTSR
= LLONG_MAX
;
2792 memory
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
2794 if (3.1556952e+9 < interval
) interval
= 3.1556952e+9;
2795 if (interval
<= 0.0) {
2796 memory
->_intervalTSR
= 0;
2797 } else if (__CFTSRToTimeInterval(LLONG_MAX
) < interval
) {
2798 memory
->_intervalTSR
= LLONG_MAX
;
2800 memory
->_intervalTSR
= __CFTimeIntervalToTSR(interval
);
2802 memory
->_callout
= callout
;
2803 if (NULL
!= context
) {
2804 if (context
->retain
) {
2805 memory
->_context
.info
= (void *)context
->retain(context
->info
);
2807 memory
->_context
.info
= context
->info
;
2809 memory
->_context
.retain
= context
->retain
;
2810 memory
->_context
.release
= context
->release
;
2811 memory
->_context
.copyDescription
= context
->copyDescription
;
2813 memory
->_context
.info
= 0;
2814 memory
->_context
.retain
= 0;
2815 memory
->_context
.release
= 0;
2816 memory
->_context
.copyDescription
= 0;
2821 CFAbsoluteTime
CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt
) {
2823 int64_t fireTime
, result
= 0;
2824 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFAbsoluteTime
, rlt
, "_cffireTime");
2825 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2826 __CFRunLoopTimerFireTSRLock();
2827 fireTime
= rlt
->_fireTSR
;
2828 __CFRunLoopTimerFireTSRUnlock();
2829 __CFRunLoopTimerLock(rlt
);
2830 if (__CFIsValid(rlt
)) {
2833 __CFRunLoopTimerUnlock(rlt
);
2834 int64_t now2
= (int64_t)mach_absolute_time();
2835 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2836 return (0 == result
) ? 0.0 : now1
+ __CFTSRToTimeInterval(result
- now2
);
2839 void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt
, CFAbsoluteTime fireDate
) {
2841 __CFRunLoopTimerFireTSRLock();
2842 int64_t now2
= (int64_t)mach_absolute_time();
2843 CFAbsoluteTime now1
= CFAbsoluteTimeGetCurrent();
2844 if (3.1556952e+9 < fireDate
) fireDate
= 3.1556952e+9;
2845 if (fireDate
< now1
) {
2846 rlt
->_fireTSR
= now2
;
2847 } else if (now1
+ __CFTSRToTimeInterval(LLONG_MAX
) < fireDate
) {
2848 rlt
->_fireTSR
= LLONG_MAX
;
2850 rlt
->_fireTSR
= now2
+ __CFTimeIntervalToTSR(fireDate
- now1
);
2852 if (rlt
->_runLoop
!= NULL
) {
2853 __CFRunLoopTimerRescheduleWithAllModes(rlt
, rlt
->_runLoop
);
2855 __CFRunLoopTimerFireTSRUnlock();
2858 CFTimeInterval
CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt
) {
2860 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFTimeInterval
, rlt
, "timeInterval");
2861 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2862 return __CFTSRToTimeInterval(rlt
->_intervalTSR
);
2865 Boolean
CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt
) {
2867 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2868 return (0 != rlt
->_intervalTSR
);
2871 CFIndex
CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt
) {
2873 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, CFIndex
, rlt
, "order");
2874 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2878 void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt
) { /* DOES CALLOUT */
2880 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, void, rlt
, "invalidate");
2881 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2883 __CFRunLoopTimerLock(rlt
);
2884 if (__CFIsValid(rlt
)) {
2885 CFRunLoopRef rl
= rlt
->_runLoop
;
2886 void *info
= rlt
->_context
.info
;
2887 __CFUnsetValid(rlt
);
2888 #if DEPLOYMENT_TARGET_MACOSX
2889 __CFRunLoopTimerPortMapLock();
2890 if (NULL
!= __CFRLTPortMap
) {
2891 CFDictionaryRemoveValue(__CFRLTPortMap
, (void *)(uintptr_t)rlt
->_port
);
2893 __CFRunLoopTimerPortMapUnlock();
2894 mk_timer_destroy(rlt
->_port
);
2895 rlt
->_port
= MACH_PORT_NULL
;
2897 rlt
->_context
.info
= NULL
;
2898 __CFRunLoopTimerUnlock(rlt
);
2902 array
= CFRunLoopCopyAllModes(rl
);
2903 for (idx
= CFArrayGetCount(array
); idx
--;) {
2904 CFStringRef modeName
= CFArrayGetValueAtIndex(array
, idx
);
2905 CFRunLoopRemoveTimer(rl
, rlt
, modeName
);
2907 CFRunLoopRemoveTimer(rl
, rlt
, kCFRunLoopCommonModes
);
2910 if (NULL
!= rlt
->_context
.release
) {
2911 rlt
->_context
.release(info
); /* CALLOUT */
2914 __CFRunLoopTimerUnlock(rlt
);
2919 Boolean
CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt
) {
2921 CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID
, Boolean
, rlt
, "isValid");
2922 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2923 return __CFIsValid(rlt
);
2926 void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt
, CFRunLoopTimerContext
*context
) {
2928 __CFGenericValidateType(rlt
, __kCFRunLoopTimerTypeID
);
2929 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
2930 *context
= rlt
->_context
;