]>
Commit | Line | Data |
---|---|---|
9ce05555 | 1 | /* |
e588f561 | 2 | * Copyright (c) 2010 Apple Inc. All rights reserved. |
9ce05555 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
9ce05555 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
f64f9b69 | 23 | |
9ce05555 | 24 | /* CFRunLoop.c |
cf7d2af9 | 25 | Copyright (c) 1998-2009, Apple Inc. All rights reserved. |
9ce05555 A |
26 | Responsibility: Christopher Kane |
27 | */ | |
28 | ||
29 | #include <CoreFoundation/CFRunLoop.h> | |
30 | #include <CoreFoundation/CFSet.h> | |
31 | #include <CoreFoundation/CFBag.h> | |
32 | #include "CFInternal.h" | |
33 | #include <math.h> | |
d8925383 | 34 | #include <stdio.h> |
9ce05555 | 35 | #include <limits.h> |
cf7d2af9 A |
36 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
37 | #include <dispatch/dispatch.h> | |
9ce05555 A |
38 | #include <mach/mach.h> |
39 | #include <mach/clock_types.h> | |
40 | #include <mach/clock.h> | |
bd5b749c A |
41 | #include <unistd.h> |
42 | #include <dlfcn.h> | |
cf7d2af9 A |
43 | extern mach_port_t _dispatch_get_main_queue_port_4CF(void); |
44 | extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg); | |
9ce05555 | 45 | #else |
d8925383 | 46 | #include <process.h> |
cf7d2af9 | 47 | #define __CFReadTSR() mach_absolute_time() |
9ce05555 | 48 | #endif |
cf7d2af9 | 49 | #include <Block.h> |
9ce05555 | 50 | |
bd5b749c A |
51 | static int _LogCFRunLoop = 0; |
52 | ||
cf7d2af9 A |
53 | // for conservative arithmetic safety, such that (TIMER_DATE_LIMIT + TIMER_INTERVAL_LIMIT + kCFAbsoluteTimeIntervalSince1970) * 10^9 < 2^63 |
54 | #define TIMER_DATE_LIMIT 4039289856.0 | |
55 | #define TIMER_INTERVAL_LIMIT 504911232.0 | |
56 | ||
57 | #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0 | |
58 | ||
59 | #if DEPLOYMENT_TARGET_WINDOWS | |
bd5b749c A |
60 | static pthread_t kNilPthreadT = { nil, nil }; |
61 | #define pthreadPointer(a) a.p | |
cf7d2af9 A |
62 | |
63 | static DWORD __CFTSDKeyRunLoopKey = ~0; | |
64 | ||
65 | // See function below. | |
66 | bool gMARRY_MESSAGE_QUEUE = FALSE; | |
67 | // | |
68 | // vod __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled) | |
69 | // | |
70 | // This function will exist for a while until code is written | |
71 | // by the WebKit folks to handle the new RunLoop message-queue | |
72 | // model. | |
73 | CF_EXPORT void __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled) { | |
74 | gMARRY_MESSAGE_QUEUE = bEnabled; | |
75 | } | |
76 | bool __CFIsNonMachRunLoopMarryMsgQueueEnabled(void) { | |
77 | return gMARRY_MESSAGE_QUEUE; | |
78 | } | |
79 | ||
bd5b749c | 80 | #else |
cf7d2af9 | 81 | |
bd5b749c A |
82 | static pthread_t kNilPthreadT = (pthread_t)0; |
83 | #define pthreadPointer(a) a | |
84 | #define lockCount(a) a | |
85 | #endif | |
86 | ||
cf7d2af9 | 87 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
bd5b749c A |
88 | #include <sys/types.h> |
89 | #include <sys/event.h> | |
90 | ||
91 | typedef struct { | |
92 | CFIndex version; | |
93 | void * info; | |
94 | const void *(*retain)(const void *info); | |
95 | void (*release)(const void *info); | |
96 | CFStringRef (*copyDescription)(const void *info); | |
97 | Boolean (*equal)(const void *info1, const void *info2); | |
98 | CFHashCode (*hash)(const void *info); | |
99 | void (*perform)(const struct kevent *kev, void *info); | |
100 | struct kevent event; | |
101 | } CFRunLoopSourceContext2; | |
102 | ||
103 | // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR. | |
104 | // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop. | |
105 | // There is no way to EV_ENABLE or EV_DISABLE a kevent. | |
106 | // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet. | |
107 | // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet. | |
108 | // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos). | |
109 | #endif | |
d8925383 | 110 | |
cf7d2af9 | 111 | CF_EXPORT bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey); |
9ce05555 | 112 | |
d8925383 A |
113 | // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a |
114 | // simple abstraction layer spanning Mach ports and Windows HANDLES | |
cf7d2af9 | 115 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 A |
116 | |
117 | typedef mach_port_t __CFPort; | |
118 | #define CFPORT_NULL MACH_PORT_NULL | |
119 | typedef mach_port_t __CFPortSet; | |
120 | ||
cf7d2af9 A |
121 | static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) __attribute__((noinline)); |
122 | static void __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(kern_return_t ret) { HALT; }; | |
123 | ||
d8925383 | 124 | static __CFPort __CFPortAllocate(void) { |
cf7d2af9 | 125 | __CFPort result = CFPORT_NULL; |
d8925383 A |
126 | kern_return_t ret; |
127 | ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result); | |
128 | if (KERN_SUCCESS == ret) { | |
129 | ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND); | |
cf7d2af9 A |
130 | } else { |
131 | __THE_SYSTEM_HAS_NO_PORTS_AVAILABLE__(ret); | |
d8925383 A |
132 | } |
133 | if (KERN_SUCCESS == ret) { | |
134 | mach_port_limits_t limits; | |
135 | limits.mpl_qlimit = 1; | |
136 | ret = mach_port_set_attributes(mach_task_self(), result, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT); | |
137 | } | |
cf7d2af9 | 138 | if (KERN_SUCCESS != ret) mach_port_destroy(mach_task_self(), result); |
d8925383 A |
139 | return (KERN_SUCCESS == ret) ? result : CFPORT_NULL; |
140 | } | |
141 | ||
142 | CF_INLINE void __CFPortFree(__CFPort port) { | |
143 | mach_port_destroy(mach_task_self(), port); | |
144 | } | |
145 | ||
cf7d2af9 A |
146 | static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) __attribute__((noinline)); |
147 | static void __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(kern_return_t ret) { HALT; }; | |
148 | ||
d8925383 A |
149 | CF_INLINE __CFPortSet __CFPortSetAllocate(void) { |
150 | __CFPortSet result; | |
151 | kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &result); | |
cf7d2af9 | 152 | if (KERN_SUCCESS != ret) { __THE_SYSTEM_HAS_NO_PORT_SETS_AVAILABLE__(ret); } |
d8925383 A |
153 | return (KERN_SUCCESS == ret) ? result : CFPORT_NULL; |
154 | } | |
155 | ||
156 | CF_INLINE Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { | |
157 | kern_return_t ret = mach_port_insert_member(mach_task_self(), port, portSet); | |
158 | return (KERN_SUCCESS == ret); | |
159 | } | |
160 | ||
161 | CF_INLINE Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { | |
162 | kern_return_t ret = mach_port_extract_member(mach_task_self(), port, portSet); | |
163 | return (KERN_SUCCESS == ret); | |
164 | } | |
165 | ||
166 | CF_INLINE void __CFPortSetFree(__CFPortSet portSet) { | |
167 | kern_return_t ret; | |
168 | mach_port_name_array_t array; | |
169 | mach_msg_type_number_t idx, number; | |
170 | ||
171 | ret = mach_port_get_set_status(mach_task_self(), portSet, &array, &number); | |
172 | if (KERN_SUCCESS == ret) { | |
173 | for (idx = 0; idx < number; idx++) { | |
174 | mach_port_extract_member(mach_task_self(), array[idx], portSet); | |
175 | } | |
176 | vm_deallocate(mach_task_self(), (vm_address_t)array, number * sizeof(mach_port_name_t)); | |
177 | } | |
178 | mach_port_destroy(mach_task_self(), portSet); | |
179 | } | |
180 | ||
cf7d2af9 | 181 | #elif DEPLOYMENT_TARGET_WINDOWS |
d8925383 A |
182 | |
183 | typedef HANDLE __CFPort; | |
184 | #define CFPORT_NULL NULL | |
185 | ||
186 | // A simple dynamic array of HANDLEs, which grows to a high-water mark | |
187 | typedef struct ___CFPortSet { | |
188 | uint16_t used; | |
189 | uint16_t size; | |
190 | HANDLE *handles; | |
191 | CFSpinLock_t lock; // insert and remove must be thread safe, like the Mach calls | |
192 | } *__CFPortSet; | |
193 | ||
194 | CF_INLINE __CFPort __CFPortAllocate(void) { | |
cf7d2af9 | 195 | return CreateEventA(NULL, true, false, NULL); |
d8925383 A |
196 | } |
197 | ||
198 | CF_INLINE void __CFPortFree(__CFPort port) { | |
199 | CloseHandle(port); | |
200 | } | |
201 | ||
202 | static __CFPortSet __CFPortSetAllocate(void) { | |
cf7d2af9 | 203 | __CFPortSet result = (__CFPortSet)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0); |
d8925383 A |
204 | result->used = 0; |
205 | result->size = 4; | |
cf7d2af9 | 206 | result->handles = (HANDLE *)CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0); |
bd5b749c | 207 | CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock); |
d8925383 A |
208 | return result; |
209 | } | |
210 | ||
211 | static void __CFPortSetFree(__CFPortSet portSet) { | |
212 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet->handles); | |
213 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet); | |
214 | } | |
215 | ||
216 | // Returns portBuf if ports fit in that space, else returns another ptr that must be freed | |
217 | static __CFPort *__CFPortSetGetPorts(__CFPortSet portSet, __CFPort *portBuf, uint32_t bufSize, uint32_t *portsUsed) { | |
218 | __CFSpinLock(&(portSet->lock)); | |
219 | __CFPort *result = portBuf; | |
cf7d2af9 A |
220 | if (bufSize < portSet->used) |
221 | result = (__CFPort *)CFAllocatorAllocate(kCFAllocatorSystemDefault, portSet->used * sizeof(HANDLE), 0); | |
222 | if (portSet->used > 1) { | |
223 | // rotate the ports to vaguely simulate round-robin behaviour | |
224 | uint16_t lastPort = portSet->used - 1; | |
225 | HANDLE swapHandle = portSet->handles[0]; | |
226 | memmove(portSet->handles, &portSet->handles[1], lastPort * sizeof(HANDLE)); | |
227 | portSet->handles[lastPort] = swapHandle; | |
228 | } | |
d8925383 A |
229 | memmove(result, portSet->handles, portSet->used * sizeof(HANDLE)); |
230 | *portsUsed = portSet->used; | |
231 | __CFSpinUnlock(&(portSet->lock)); | |
232 | return result; | |
233 | } | |
234 | ||
235 | static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { | |
236 | __CFSpinLock(&(portSet->lock)); | |
237 | if (portSet->used >= portSet->size) { | |
238 | portSet->size += 4; | |
cf7d2af9 | 239 | portSet->handles = (HANDLE *)CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0); |
d8925383 A |
240 | } |
241 | if (portSet->used >= MAXIMUM_WAIT_OBJECTS) | |
bd5b749c | 242 | CFLog(kCFLogLevelWarning, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS); |
d8925383 A |
243 | portSet->handles[portSet->used++] = port; |
244 | __CFSpinUnlock(&(portSet->lock)); | |
245 | return true; | |
246 | } | |
247 | ||
248 | static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { | |
249 | int i, j; | |
250 | __CFSpinLock(&(portSet->lock)); | |
251 | for (i = 0; i < portSet->used; i++) { | |
252 | if (portSet->handles[i] == port) { | |
253 | for (j = i+1; j < portSet->used; j++) { | |
254 | portSet->handles[j-1] = portSet->handles[j]; | |
255 | } | |
256 | portSet->used--; | |
257 | __CFSpinUnlock(&(portSet->lock)); | |
258 | return true; | |
259 | } | |
260 | } | |
261 | __CFSpinUnlock(&(portSet->lock)); | |
262 | return false; | |
263 | } | |
264 | ||
265 | #endif | |
266 | ||
cf7d2af9 | 267 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 A |
268 | extern mach_port_name_t mk_timer_create(void); |
269 | extern kern_return_t mk_timer_destroy(mach_port_name_t name); | |
270 | extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time); | |
271 | extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time); | |
272 | ||
273 | CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(int64_t x) { | |
274 | AbsoluteTime a; | |
275 | a.hi = x >> 32; | |
276 | a.lo = x & (int64_t)0xFFFFFFFF; | |
277 | return a; | |
278 | } | |
9ce05555 | 279 | |
9ce05555 A |
280 | static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) { |
281 | kern_return_t result; | |
282 | mach_msg_header_t header; | |
283 | header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); | |
284 | header.msgh_size = sizeof(mach_msg_header_t); | |
285 | header.msgh_remote_port = port; | |
286 | header.msgh_local_port = MACH_PORT_NULL; | |
287 | header.msgh_id = msg_id; | |
288 | result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL); | |
d8925383 | 289 | if (result == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header); |
9ce05555 A |
290 | return result; |
291 | } | |
9ce05555 A |
292 | #endif |
293 | ||
294 | /* unlock a run loop and modes before doing callouts/sleeping */ | |
295 | /* never try to take the run loop lock with a mode locked */ | |
296 | /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */ | |
297 | /* run loop mode structures should never be deallocated, even if they become empty */ | |
298 | ||
299 | static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID; | |
300 | static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID; | |
301 | static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID; | |
302 | static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID; | |
303 | static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID; | |
304 | ||
cf7d2af9 A |
305 | #if DEPLOYMENT_TARGET_WINDOWS |
306 | // The MSG identifier for the Windows message injected in the message queue to wake the run loop | |
307 | static unsigned int __kCFRunLoopWakeUpMessage = 0; | |
308 | static unsigned int __kCFRunLoopV1SourceReadyMessage = 0; | |
309 | #endif | |
310 | ||
9ce05555 A |
311 | typedef struct __CFRunLoopMode *CFRunLoopModeRef; |
312 | ||
313 | struct __CFRunLoopMode { | |
314 | CFRuntimeBase _base; | |
315 | CFSpinLock_t _lock; /* must have the run loop locked before locking this */ | |
316 | CFStringRef _name; | |
317 | Boolean _stopped; | |
318 | char _padding[3]; | |
319 | CFMutableSetRef _sources; | |
320 | CFMutableSetRef _observers; | |
321 | CFMutableSetRef _timers; | |
cf7d2af9 | 322 | CFMutableDictionaryRef _portToV1SourceMap; |
9ce05555 | 323 | CFMutableArrayRef _submodes; // names of the submodes |
d8925383 | 324 | __CFPortSet _portSet; |
cf7d2af9 A |
325 | CFIndex _observerMask; |
326 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
d8925383 | 327 | int _kq; |
9ce05555 | 328 | #endif |
cf7d2af9 A |
329 | #if DEPLOYMENT_TARGET_WINDOWS |
330 | DWORD _msgQMask; | |
331 | #endif | |
9ce05555 A |
332 | }; |
333 | ||
334 | CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) { | |
335 | __CFSpinLock(&(rlm->_lock)); | |
336 | } | |
337 | ||
338 | CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) { | |
339 | __CFSpinUnlock(&(rlm->_lock)); | |
340 | } | |
341 | ||
342 | static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) { | |
343 | CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1; | |
344 | CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2; | |
345 | return CFEqual(rlm1->_name, rlm2->_name); | |
346 | } | |
347 | ||
348 | static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) { | |
349 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; | |
350 | return CFHash(rlm->_name); | |
351 | } | |
352 | ||
353 | static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) { | |
354 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; | |
355 | CFMutableStringRef result; | |
356 | result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); | |
cf7d2af9 A |
357 | #if DEPLOYMENT_TARGET_WINDOWS |
358 | CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, "unknown"); | |
359 | #else | |
bd5b749c | 360 | CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, lockCount(rlm->_lock) ? "true" : "false"); |
cf7d2af9 | 361 | #endif |
9ce05555 | 362 | CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet); |
cf7d2af9 A |
363 | #if DEPLOYMENT_TARGET_WINDOWS |
364 | CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p,"), rlm->_msgQMask); | |
365 | #endif | |
366 | CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers); | |
9ce05555 A |
367 | return result; |
368 | } | |
369 | ||
370 | static void __CFRunLoopModeDeallocate(CFTypeRef cf) { | |
371 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; | |
372 | if (NULL != rlm->_sources) CFRelease(rlm->_sources); | |
373 | if (NULL != rlm->_observers) CFRelease(rlm->_observers); | |
374 | if (NULL != rlm->_timers) CFRelease(rlm->_timers); | |
375 | if (NULL != rlm->_submodes) CFRelease(rlm->_submodes); | |
cf7d2af9 | 376 | if (NULL != rlm->_portToV1SourceMap) CFRelease(rlm->_portToV1SourceMap); |
9ce05555 | 377 | CFRelease(rlm->_name); |
d8925383 | 378 | __CFPortSetFree(rlm->_portSet); |
cf7d2af9 | 379 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 | 380 | if (-1 != rlm->_kq) close(rlm->_kq); |
9ce05555 | 381 | #endif |
cf7d2af9 | 382 | memset((char *)cf + sizeof(CFRuntimeBase), 0x7C, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase)); |
9ce05555 A |
383 | } |
384 | ||
cf7d2af9 A |
385 | struct _block_item { |
386 | struct _block_item *_next; | |
387 | CFTypeRef _mode; // CFString or CFSet or CFRunLoopTimer | |
388 | void (^_block)(void); | |
389 | }; | |
390 | ||
9ce05555 A |
391 | struct __CFRunLoop { |
392 | CFRuntimeBase _base; | |
393 | CFSpinLock_t _lock; /* locked for accessing mode list */ | |
d8925383 | 394 | __CFPort _wakeUpPort; // used for CFRunLoopWakeUp |
bd5b749c | 395 | volatile uint32_t *_stopped; |
cf7d2af9 | 396 | pthread_t _pthread; |
9ce05555 A |
397 | CFMutableSetRef _commonModes; |
398 | CFMutableSetRef _commonModeItems; | |
399 | CFRunLoopModeRef _currentMode; | |
400 | CFMutableSetRef _modes; | |
cf7d2af9 A |
401 | struct _block_item *_blocks_head; |
402 | struct _block_item *_blocks_tail; | |
403 | #if DEPLOYMENT_TARGET_WINDOWS | |
404 | DWORD _threadID; | |
405 | __CFPort _msgUpdatePort; | |
406 | #endif | |
407 | CFTypeRef _counterpart; | |
9ce05555 A |
408 | }; |
409 | ||
cf7d2af9 A |
410 | #if DEPLOYMENT_TARGET_WINDOWS |
411 | void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl); | |
412 | void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl); | |
413 | static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls); | |
414 | CF_EXPORT LRESULT CALLBACK pumpRunLoopFromMessageQueue(int nCode, WPARAM wParam, LPARAM lParam); | |
415 | #endif | |
416 | ||
9ce05555 A |
417 | /* Bit 0 of the base reserved bits is used for stopped state */ |
418 | /* Bit 1 of the base reserved bits is used for sleeping state */ | |
419 | /* Bit 2 of the base reserved bits is used for deallocating state */ | |
420 | ||
421 | CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) { | |
422 | return (rl->_stopped && rl->_stopped[2]) ? true : false; | |
423 | } | |
424 | ||
425 | CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) { | |
cf7d2af9 A |
426 | if (!rl->_stopped) { |
427 | rl->_stopped = (uint32_t volatile *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 4 * sizeof(uint32_t), 0); | |
428 | rl->_stopped[0] = 0x4346524C; | |
429 | rl->_stopped[1] = 0x4346524C; // 'CFRL' | |
430 | rl->_stopped[2] = 0x00000000; // here the value is stored | |
431 | rl->_stopped[3] = 0x4346524C; | |
432 | } | |
9ce05555 A |
433 | if (rl->_stopped) rl->_stopped[2] = 0x53544F50; // 'STOP' |
434 | } | |
435 | ||
436 | CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) { | |
437 | if (rl->_stopped) rl->_stopped[2] = 0x0; | |
438 | } | |
439 | ||
440 | CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) { | |
bd5b749c | 441 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1); |
9ce05555 A |
442 | } |
443 | ||
444 | CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) { | |
bd5b749c | 445 | __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1); |
9ce05555 A |
446 | } |
447 | ||
448 | CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) { | |
bd5b749c | 449 | __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0); |
9ce05555 A |
450 | } |
451 | ||
452 | CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) { | |
bd5b749c | 453 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2); |
9ce05555 A |
454 | } |
455 | ||
456 | CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) { | |
bd5b749c | 457 | __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1); |
9ce05555 A |
458 | } |
459 | ||
460 | CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) { | |
461 | __CFSpinLock(&(((CFRunLoopRef)rl)->_lock)); | |
462 | } | |
463 | ||
464 | CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) { | |
465 | __CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock)); | |
466 | } | |
467 | ||
468 | static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) { | |
469 | CFRunLoopRef rl = (CFRunLoopRef)cf; | |
470 | CFMutableStringRef result; | |
471 | result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); | |
cf7d2af9 A |
472 | #if DEPLOYMENT_TARGET_WINDOWS |
473 | CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), "unknown", rl->_wakeUpPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); | |
474 | #else | |
475 | CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wakeup 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)")); | |
476 | #endif | |
9ce05555 A |
477 | CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes); |
478 | return result; | |
479 | } | |
480 | ||
cf7d2af9 A |
481 | __private_extern__ void __CFRunLoopDump() { // __private_extern__ to keep the compiler from discarding it |
482 | CFShow(CFCopyDescription(CFRunLoopGetCurrent())); | |
483 | } | |
484 | ||
9ce05555 A |
485 | /* call with rl locked */ |
486 | static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) { | |
bd5b749c | 487 | CHECK_FOR_FORK(); |
9ce05555 A |
488 | CFRunLoopModeRef rlm; |
489 | struct __CFRunLoopMode srlm; | |
cf7d2af9 | 490 | memset(&srlm, 0, sizeof(srlm)); |
bd5b749c | 491 | srlm._base._cfisa = __CFISAForTypeID(__kCFRunLoopModeTypeID); |
9ce05555 A |
492 | _CFRuntimeSetInstanceTypeID(&srlm, __kCFRunLoopModeTypeID); |
493 | srlm._name = modeName; | |
494 | rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm); | |
495 | if (NULL != rlm) { | |
496 | __CFRunLoopModeLock(rlm); | |
497 | return rlm; | |
498 | } | |
499 | if (!create) { | |
500 | return NULL; | |
501 | } | |
cf7d2af9 | 502 | rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL); |
9ce05555 A |
503 | if (NULL == rlm) { |
504 | return NULL; | |
505 | } | |
bd5b749c | 506 | CF_SPINLOCK_INIT_FOR_STRUCTS(rlm->_lock); |
cf7d2af9 | 507 | rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName); |
9ce05555 | 508 | rlm->_stopped = false; |
cf7d2af9 | 509 | rlm->_portToV1SourceMap = NULL; |
9ce05555 A |
510 | rlm->_sources = NULL; |
511 | rlm->_observers = NULL; | |
512 | rlm->_timers = NULL; | |
513 | rlm->_submodes = NULL; | |
cf7d2af9 | 514 | rlm->_observerMask = 0; |
d8925383 | 515 | rlm->_portSet = __CFPortSetAllocate(); |
d8925383 | 516 | if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT; |
cf7d2af9 | 517 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 | 518 | rlm->_kq = -1; |
cf7d2af9 A |
519 | #endif |
520 | #if DEPLOYMENT_TARGET_WINDOWS | |
521 | rlm->_msgQMask = 0; | |
9ce05555 A |
522 | #endif |
523 | CFSetAddValue(rl->_modes, rlm); | |
524 | CFRelease(rlm); | |
525 | __CFRunLoopModeLock(rlm); /* return mode locked */ | |
526 | return rlm; | |
527 | } | |
528 | ||
9ce05555 A |
529 | |
530 | // expects rl and rlm locked | |
cf7d2af9 | 531 | static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) { |
bd5b749c | 532 | CHECK_FOR_FORK(); |
9ce05555 | 533 | if (NULL == rlm) return true; |
cf7d2af9 A |
534 | #if DEPLOYMENT_TARGET_WINDOWS |
535 | if (0 != rlm->_msgQMask) return false; | |
536 | #endif | |
537 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
538 | Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ))); | |
539 | if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; // represents the libdispatch main queue | |
540 | #endif | |
9ce05555 A |
541 | if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false; |
542 | if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false; | |
cf7d2af9 A |
543 | #if 1 |
544 | struct _block_item *item = rl->_blocks_head; | |
545 | while (item) { | |
546 | struct _block_item *curr = item; | |
547 | item = item->_next; | |
548 | Boolean doit = false; | |
549 | if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) { | |
550 | doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name)); | |
551 | } else { | |
552 | doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name)); | |
553 | } | |
554 | if (doit) return false; | |
555 | } | |
556 | #endif | |
9ce05555 A |
557 | if (NULL != rlm->_submodes) { |
558 | CFIndex idx, cnt; | |
559 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
560 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
561 | CFRunLoopModeRef subrlm; | |
562 | Boolean subIsEmpty; | |
563 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
cf7d2af9 | 564 | subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm, previousMode) : true; |
9ce05555 A |
565 | if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm); |
566 | if (!subIsEmpty) return false; | |
567 | } | |
568 | } | |
569 | return true; | |
570 | } | |
571 | ||
cf7d2af9 A |
572 | #if DEPLOYMENT_TARGET_WINDOWS |
573 | DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) { | |
574 | CFRunLoopModeRef rlm; | |
575 | DWORD result = 0; | |
576 | __CFRunLoopLock(rl); | |
577 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
578 | if (rlm) { | |
579 | result = rlm->_msgQMask; | |
580 | __CFRunLoopModeUnlock(rlm); | |
581 | } | |
582 | __CFRunLoopUnlock(rl); | |
583 | return result; | |
584 | } | |
585 | ||
586 | void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef modeName) { | |
587 | CFRunLoopModeRef rlm; | |
588 | __CFRunLoopLock(rl); | |
589 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
590 | rlm->_msgQMask = mask; | |
591 | __CFRunLoopModeUnlock(rlm); | |
592 | __CFRunLoopUnlock(rl); | |
593 | } | |
594 | #endif | |
595 | ||
9ce05555 A |
596 | /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */ |
597 | ||
598 | CF_INLINE Boolean __CFIsValid(const void *cf) { | |
bd5b749c | 599 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3); |
9ce05555 A |
600 | } |
601 | ||
602 | CF_INLINE void __CFSetValid(void *cf) { | |
bd5b749c | 603 | __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1); |
9ce05555 A |
604 | } |
605 | ||
606 | CF_INLINE void __CFUnsetValid(void *cf) { | |
bd5b749c | 607 | __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0); |
9ce05555 A |
608 | } |
609 | ||
610 | struct __CFRunLoopSource { | |
611 | CFRuntimeBase _base; | |
612 | uint32_t _bits; | |
613 | CFSpinLock_t _lock; | |
614 | CFIndex _order; /* immutable */ | |
615 | CFMutableBagRef _runLoops; | |
616 | union { | |
617 | CFRunLoopSourceContext version0; /* immutable, except invalidation */ | |
d8925383 | 618 | CFRunLoopSourceContext1 version1; /* immutable, except invalidation */ |
9ce05555 A |
619 | } _context; |
620 | }; | |
621 | ||
bd5b749c | 622 | /* Bit 1 of the base reserved bits is used for signalled state */ |
9ce05555 A |
623 | |
624 | CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) { | |
625 | return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1); | |
626 | } | |
627 | ||
628 | CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) { | |
629 | __CFBitfieldSetValue(rls->_bits, 1, 1, 1); | |
630 | } | |
631 | ||
632 | CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) { | |
633 | __CFBitfieldSetValue(rls->_bits, 1, 1, 0); | |
634 | } | |
635 | ||
636 | CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) { | |
637 | __CFSpinLock(&(rls->_lock)); | |
638 | } | |
639 | ||
640 | CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) { | |
641 | __CFSpinUnlock(&(rls->_lock)); | |
642 | } | |
643 | ||
644 | /* rlm is not locked */ | |
645 | static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ | |
cf7d2af9 | 646 | //printf("Scheduling source %p with mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl); |
9ce05555 A |
647 | __CFRunLoopSourceLock(rls); |
648 | if (NULL == rls->_runLoops) { | |
cf7d2af9 | 649 | rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); // sources retain run loops! |
9ce05555 A |
650 | } |
651 | CFBagAddValue(rls->_runLoops, rl); | |
652 | __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety | |
653 | if (0 == rls->_context.version0.version) { | |
654 | if (NULL != rls->_context.version0.schedule) { | |
655 | rls->_context.version0.schedule(rls->_context.version0.info, rl, rlm->_name); | |
656 | } | |
9ce05555 | 657 | } else if (1 == rls->_context.version0.version) { |
d8925383 A |
658 | __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ |
659 | if (CFPORT_NULL != port) { | |
660 | __CFPortSetInsert(port, rlm->_portSet); | |
661 | } | |
cf7d2af9 A |
662 | #if DEPLOYMENT_TARGET_WINDOWS |
663 | __CFRunLoopLock(rl); | |
664 | //#warning Bug here - if rl->_currentMode is NULL and rlm == the default mode, we should also update | |
665 | if (rl->_currentMode == rlm) { | |
666 | if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) | |
667 | __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); | |
668 | else | |
669 | __CFRunLoopUpdateMsgWait(rl); | |
670 | } | |
671 | __CFRunLoopUnlock(rl); | |
672 | #endif | |
9ce05555 A |
673 | } |
674 | } | |
675 | ||
676 | /* rlm is not locked */ | |
677 | static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ | |
cf7d2af9 A |
678 | //printf("Cancelling source %p from mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl); |
679 | __CFRunLoopSourceLock(rls); | |
680 | if (NULL != rls->_runLoops) { | |
681 | CFBagRemoveValue(rls->_runLoops, rl); | |
682 | } | |
683 | __CFRunLoopSourceUnlock(rls); | |
9ce05555 A |
684 | if (0 == rls->_context.version0.version) { |
685 | if (NULL != rls->_context.version0.cancel) { | |
686 | rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */ | |
687 | } | |
9ce05555 | 688 | } else if (1 == rls->_context.version0.version) { |
d8925383 A |
689 | __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ |
690 | if (CFPORT_NULL != port) { | |
691 | __CFPortSetRemove(port, rlm->_portSet); | |
692 | } | |
cf7d2af9 A |
693 | #if DEPLOYMENT_TARGET_WINDOWS |
694 | __CFRunLoopLock(rl); | |
695 | //#warning Bug here - must also update if rl->_currentMode == NULL and rlm == default mode | |
696 | if (rl->_currentMode == rlm && rl->_msgUpdatePort != CFPORT_NULL) { | |
697 | if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) | |
698 | __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); | |
699 | else | |
700 | __CFRunLoopUpdateMsgWait(rl); | |
701 | } | |
702 | __CFRunLoopUnlock(rl); | |
703 | #endif | |
9ce05555 | 704 | } |
9ce05555 A |
705 | } |
706 | ||
707 | struct __CFRunLoopObserver { | |
708 | CFRuntimeBase _base; | |
709 | CFSpinLock_t _lock; | |
710 | CFRunLoopRef _runLoop; | |
711 | CFIndex _rlCount; | |
712 | CFOptionFlags _activities; /* immutable */ | |
713 | CFIndex _order; /* immutable */ | |
714 | CFRunLoopObserverCallBack _callout; /* immutable */ | |
715 | CFRunLoopObserverContext _context; /* immutable, except invalidation */ | |
716 | }; | |
717 | ||
718 | /* Bit 0 of the base reserved bits is used for firing state */ | |
719 | /* Bit 1 of the base reserved bits is used for repeats state */ | |
720 | ||
721 | CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) { | |
bd5b749c | 722 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0); |
9ce05555 A |
723 | } |
724 | ||
725 | CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) { | |
bd5b749c | 726 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1); |
9ce05555 A |
727 | } |
728 | ||
729 | CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) { | |
bd5b749c | 730 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0); |
9ce05555 A |
731 | } |
732 | ||
733 | CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) { | |
bd5b749c | 734 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1); |
9ce05555 A |
735 | } |
736 | ||
737 | CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) { | |
bd5b749c | 738 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1); |
9ce05555 A |
739 | } |
740 | ||
741 | CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) { | |
bd5b749c | 742 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0); |
9ce05555 A |
743 | } |
744 | ||
745 | CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) { | |
746 | __CFSpinLock(&(rlo->_lock)); | |
747 | } | |
748 | ||
749 | CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) { | |
750 | __CFSpinUnlock(&(rlo->_lock)); | |
751 | } | |
752 | ||
753 | static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
754 | __CFRunLoopObserverLock(rlo); | |
755 | if (0 == rlo->_rlCount) { | |
756 | rlo->_runLoop = rl; | |
757 | } | |
758 | rlo->_rlCount++; | |
759 | __CFRunLoopObserverUnlock(rlo); | |
760 | } | |
761 | ||
762 | static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
763 | __CFRunLoopObserverLock(rlo); | |
764 | rlo->_rlCount--; | |
765 | if (0 == rlo->_rlCount) { | |
766 | rlo->_runLoop = NULL; | |
767 | } | |
768 | __CFRunLoopObserverUnlock(rlo); | |
769 | } | |
770 | ||
771 | struct __CFRunLoopTimer { | |
772 | CFRuntimeBase _base; | |
773 | CFSpinLock_t _lock; | |
774 | CFRunLoopRef _runLoop; | |
cf7d2af9 A |
775 | CFMutableSetRef _rlModes; |
776 | CFAbsoluteTime _nextFireDate; | |
777 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
9ce05555 | 778 | mach_port_name_t _port; |
9ce05555 A |
779 | int64_t _fireTSR; /* TSR units */ |
780 | int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */ | |
cf7d2af9 A |
781 | #elif DEPLOYMENT_TARGET_WINDOWS |
782 | CFIndex _rlCount; | |
783 | int64_t _fireTSR; /* TSR units */ | |
784 | int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */ | |
785 | #endif | |
786 | CFTimeInterval _interval; /* immutable */ | |
787 | CFIndex _order; /* immutable */ | |
9ce05555 A |
788 | CFRunLoopTimerCallBack _callout; /* immutable */ |
789 | CFRunLoopTimerContext _context; /* immutable, except invalidation */ | |
790 | }; | |
791 | ||
792 | /* Bit 0 of the base reserved bits is used for firing state */ | |
d8925383 | 793 | /* Bit 1 of the base reserved bits is used for fired-during-callout state */ |
9ce05555 A |
794 | |
795 | CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) { | |
bd5b749c | 796 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0); |
9ce05555 A |
797 | } |
798 | ||
799 | CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) { | |
bd5b749c | 800 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 1); |
9ce05555 A |
801 | } |
802 | ||
803 | CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) { | |
bd5b749c | 804 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 0); |
9ce05555 A |
805 | } |
806 | ||
d8925383 | 807 | CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) { |
bd5b749c | 808 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1); |
d8925383 A |
809 | } |
810 | ||
811 | CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) { | |
bd5b749c | 812 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 1); |
d8925383 A |
813 | } |
814 | ||
815 | CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) { | |
bd5b749c | 816 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 0); |
d8925383 A |
817 | } |
818 | ||
cf7d2af9 A |
819 | CF_INLINE Boolean __CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt) { |
820 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 2, 2); | |
821 | } | |
822 | ||
823 | CF_INLINE void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt) { | |
824 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 2, 2, 1); | |
825 | } | |
826 | ||
9ce05555 A |
827 | CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) { |
828 | __CFSpinLock(&(rlt->_lock)); | |
829 | } | |
830 | ||
831 | CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) { | |
832 | __CFSpinUnlock(&(rlt->_lock)); | |
833 | } | |
834 | ||
bd5b749c | 835 | static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit; |
9ce05555 A |
836 | |
837 | CF_INLINE void __CFRunLoopTimerFireTSRLock(void) { | |
838 | __CFSpinLock(&__CFRLTFireTSRLock); | |
839 | } | |
840 | ||
841 | CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) { | |
842 | __CFSpinUnlock(&__CFRLTFireTSRLock); | |
843 | } | |
844 | ||
cf7d2af9 | 845 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 | 846 | static CFMutableDictionaryRef __CFRLTPortMap = NULL; |
bd5b749c | 847 | static CFSpinLock_t __CFRLTPortMapLock = CFSpinLockInit; |
9ce05555 A |
848 | |
849 | CF_INLINE void __CFRunLoopTimerPortMapLock(void) { | |
850 | __CFSpinLock(&__CFRLTPortMapLock); | |
851 | } | |
852 | ||
853 | CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) { | |
854 | __CFSpinUnlock(&__CFRLTPortMapLock); | |
855 | } | |
d8925383 | 856 | #endif |
9ce05555 | 857 | |
cf7d2af9 A |
858 | static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt); |
859 | ||
860 | // called with timer locked in libdispatch mode | |
861 | static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt) { | |
862 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
863 | mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR)); | |
864 | #endif | |
865 | } | |
866 | ||
9ce05555 | 867 | static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { |
cf7d2af9 A |
868 | //CFLog(4, CFSTR("__CFRunLoopTimerSchedule(%p, loop %p, mode %@) [%p, %p]"), rlt, rl, rlm->_name, rlt->_runLoop, rlt->_port); |
869 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
9ce05555 | 870 | __CFRunLoopTimerLock(rlt); |
cf7d2af9 | 871 | if (NULL == rlt->_runLoop) { |
9ce05555 A |
872 | rlt->_runLoop = rl; |
873 | if (MACH_PORT_NULL == rlt->_port) { | |
874 | rlt->_port = mk_timer_create(); | |
875 | } | |
876 | __CFRunLoopTimerPortMapLock(); | |
877 | if (NULL == __CFRLTPortMap) { | |
878 | __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); | |
879 | } | |
bd5b749c | 880 | CFDictionarySetValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port, rlt); |
9ce05555 | 881 | __CFRunLoopTimerPortMapUnlock(); |
cf7d2af9 | 882 | __CFRunLoopTimerRescheduleWithAllModes(rlt); |
9ce05555 | 883 | } |
9ce05555 | 884 | mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet); |
cf7d2af9 | 885 | CFSetAddValue(rlt->_rlModes, rlm->_name); |
9ce05555 | 886 | __CFRunLoopTimerUnlock(rlt); |
cf7d2af9 A |
887 | #elif DEPLOYMENT_TARGET_WINDOWS |
888 | if (0 == rlt->_rlCount) { | |
889 | rlt->_runLoop = rl; | |
890 | } | |
891 | rlt->_rlCount++; | |
9ce05555 A |
892 | #endif |
893 | } | |
894 | ||
895 | static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
cf7d2af9 A |
896 | //CFLog(6, CFSTR("__CFRunLoopTimerCancel(rlt %p, rl %p, rlm %@)"), rlt, rl, rlm->_name); |
897 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
9ce05555 | 898 | __CFRunLoopTimerLock(rlt); |
cf7d2af9 | 899 | CFSetRemoveValue(rlt->_rlModes, rlm->_name); |
d8925383 | 900 | __CFPortSetRemove(rlt->_port, rlm->_portSet); |
cf7d2af9 | 901 | if (0 == CFSetGetCount(rlt->_rlModes)) { |
9ce05555 A |
902 | __CFRunLoopTimerPortMapLock(); |
903 | if (NULL != __CFRLTPortMap) { | |
bd5b749c | 904 | CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); |
9ce05555 A |
905 | } |
906 | __CFRunLoopTimerPortMapUnlock(); | |
9ce05555 | 907 | mk_timer_cancel(rlt->_port, NULL); |
cf7d2af9 | 908 | rlt->_runLoop = NULL; |
9ce05555 A |
909 | } |
910 | __CFRunLoopTimerUnlock(rlt); | |
cf7d2af9 A |
911 | #elif DEPLOYMENT_TARGET_WINDOWS |
912 | CFRunLoopWakeUp(rl); | |
9ce05555 A |
913 | #endif |
914 | } | |
915 | ||
cf7d2af9 A |
916 | #if DEPLOYMENT_TARGET_WINDOWS |
917 | ||
918 | struct _collectTimersContext { | |
919 | CFMutableArrayRef results; | |
920 | int64_t cutoffTSR; | |
921 | }; | |
922 | ||
923 | static void __CFRunLoopCollectTimers(const void *value, void *ctx) { | |
924 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value; | |
925 | struct _collectTimersContext *context = (struct _collectTimersContext *)ctx; | |
926 | if (rlt->_fireTSR <= context->cutoffTSR) { | |
927 | if (NULL == context->results) | |
928 | context->results = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); | |
929 | CFArrayAppendValue(context->results, rlt); | |
930 | } | |
931 | } | |
932 | ||
933 | // RunLoop and RunLoopMode must be locked | |
934 | static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl, CFRunLoopModeRef rlm, struct _collectTimersContext *ctxt) { | |
935 | if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { | |
936 | __CFRunLoopTimerFireTSRLock(); | |
937 | CFSetApplyFunction(rlm->_timers, __CFRunLoopCollectTimers, ctxt); | |
938 | __CFRunLoopTimerFireTSRUnlock(); | |
939 | } | |
940 | if (NULL != rlm->_submodes) { | |
941 | CFIndex idx, cnt; | |
942 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
943 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
944 | CFRunLoopModeRef subrlm; | |
945 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
946 | if (NULL != subrlm) { | |
947 | __CFRunLoopTimersToFireRecursive(rl, subrlm, ctxt); | |
948 | __CFRunLoopModeUnlock(subrlm); | |
949 | } | |
950 | } | |
951 | } | |
9ce05555 A |
952 | } |
953 | ||
cf7d2af9 A |
954 | // RunLoop and RunLoopMode must be locked |
955 | static CFArrayRef __CFRunLoopTimersToFire(CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
956 | struct _collectTimersContext ctxt = {NULL, __CFReadTSR()}; | |
957 | __CFRunLoopTimersToFireRecursive(rl, rlm, &ctxt); | |
958 | return ctxt.results; | |
959 | } | |
960 | #endif | |
961 | ||
9ce05555 A |
962 | /* CFRunLoop */ |
963 | ||
964 | CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode") | |
965 | CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes") | |
966 | ||
9ce05555 | 967 | // call with rl and rlm locked |
d8925383 | 968 | static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) { /* DOES CALLOUT */ |
bd5b749c | 969 | CHECK_FOR_FORK(); |
cf7d2af9 A |
970 | CFRunLoopSourceRef found = rlm->_portToV1SourceMap ? (CFRunLoopSourceRef)CFDictionaryGetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)port) : NULL; |
971 | if (NULL == found && NULL != rlm->_submodes) { | |
9ce05555 A |
972 | CFIndex idx, cnt; |
973 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
9ce05555 A |
974 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); |
975 | CFRunLoopModeRef subrlm; | |
976 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
977 | if (NULL != subrlm) { | |
cf7d2af9 | 978 | found = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port); |
9ce05555 A |
979 | __CFRunLoopModeUnlock(subrlm); |
980 | } | |
cf7d2af9 | 981 | if (NULL != found) { |
9ce05555 A |
982 | break; |
983 | } | |
984 | } | |
985 | } | |
cf7d2af9 | 986 | return found; |
9ce05555 A |
987 | } |
988 | ||
cf7d2af9 | 989 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 | 990 | // call with rl and rlm locked |
d8925383 | 991 | static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, __CFPort port) { |
bd5b749c | 992 | CHECK_FOR_FORK(); |
9ce05555 A |
993 | CFRunLoopTimerRef result = NULL; |
994 | __CFRunLoopTimerPortMapLock(); | |
995 | if (NULL != __CFRLTPortMap) { | |
bd5b749c | 996 | result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)(uintptr_t)port); |
9ce05555 A |
997 | } |
998 | __CFRunLoopTimerPortMapUnlock(); | |
999 | return result; | |
1000 | } | |
1001 | #endif | |
1002 | ||
5645d61f A |
1003 | // Remove backreferences the mode's sources have to the rl (context); |
1004 | // the primary purpose of rls->_runLoops is so that Invalidation can remove | |
1005 | // the source from the run loops it is in, but during deallocation of a | |
1006 | // run loop, we already know that the sources are going to be punted | |
1007 | // from it, so invalidation of sources does not need to remove from a | |
1008 | // deallocating run loop. | |
1009 | static void __CFRunLoopCleanseSources(const void *value, void *context) { | |
1010 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
1011 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
1012 | CFIndex idx, cnt; | |
1013 | const void **list, *buffer[256]; | |
1014 | if (NULL == rlm->_sources) return; | |
1015 | cnt = CFSetGetCount(rlm->_sources); | |
cf7d2af9 | 1016 | list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); |
5645d61f A |
1017 | CFSetGetValues(rlm->_sources, list); |
1018 | for (idx = 0; idx < cnt; idx++) { | |
1019 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; | |
1020 | __CFRunLoopSourceLock(rls); | |
1021 | if (NULL != rls->_runLoops) { | |
1022 | CFBagRemoveValue(rls->_runLoops, rl); | |
1023 | } | |
1024 | __CFRunLoopSourceUnlock(rls); | |
1025 | } | |
1026 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1027 | } | |
1028 | ||
9ce05555 A |
1029 | static void __CFRunLoopDeallocateSources(const void *value, void *context) { |
1030 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
1031 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
1032 | CFIndex idx, cnt; | |
1033 | const void **list, *buffer[256]; | |
1034 | if (NULL == rlm->_sources) return; | |
1035 | cnt = CFSetGetCount(rlm->_sources); | |
cf7d2af9 | 1036 | list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); |
9ce05555 A |
1037 | CFSetGetValues(rlm->_sources, list); |
1038 | for (idx = 0; idx < cnt; idx++) { | |
1039 | CFRetain(list[idx]); | |
1040 | } | |
1041 | CFSetRemoveAllValues(rlm->_sources); | |
1042 | for (idx = 0; idx < cnt; idx++) { | |
1043 | __CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm); | |
1044 | CFRelease(list[idx]); | |
1045 | } | |
1046 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1047 | } | |
1048 | ||
1049 | static void __CFRunLoopDeallocateObservers(const void *value, void *context) { | |
1050 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
1051 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
1052 | CFIndex idx, cnt; | |
1053 | const void **list, *buffer[256]; | |
1054 | if (NULL == rlm->_observers) return; | |
1055 | cnt = CFSetGetCount(rlm->_observers); | |
cf7d2af9 | 1056 | list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); |
9ce05555 A |
1057 | CFSetGetValues(rlm->_observers, list); |
1058 | for (idx = 0; idx < cnt; idx++) { | |
1059 | CFRetain(list[idx]); | |
1060 | } | |
1061 | CFSetRemoveAllValues(rlm->_observers); | |
1062 | for (idx = 0; idx < cnt; idx++) { | |
1063 | __CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm); | |
1064 | CFRelease(list[idx]); | |
1065 | } | |
1066 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1067 | } | |
1068 | ||
1069 | static void __CFRunLoopDeallocateTimers(const void *value, void *context) { | |
1070 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
1071 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
1072 | CFIndex idx, cnt; | |
1073 | const void **list, *buffer[256]; | |
1074 | if (NULL == rlm->_timers) return; | |
1075 | cnt = CFSetGetCount(rlm->_timers); | |
cf7d2af9 | 1076 | list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); |
9ce05555 A |
1077 | CFSetGetValues(rlm->_timers, list); |
1078 | for (idx = 0; idx < cnt; idx++) { | |
1079 | CFRetain(list[idx]); | |
1080 | } | |
1081 | CFSetRemoveAllValues(rlm->_timers); | |
1082 | for (idx = 0; idx < cnt; idx++) { | |
1083 | __CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm); | |
1084 | CFRelease(list[idx]); | |
1085 | } | |
1086 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1087 | } | |
1088 | ||
cf7d2af9 A |
1089 | CF_EXPORT pthread_t _CFMainPThread; |
1090 | CF_EXPORT CFRunLoopRef _CFRunLoopGet0b(pthread_t t); | |
1091 | ||
9ce05555 A |
1092 | static void __CFRunLoopDeallocate(CFTypeRef cf) { |
1093 | CFRunLoopRef rl = (CFRunLoopRef)cf; | |
cf7d2af9 A |
1094 | |
1095 | if (_CFRunLoopGet0b(_CFMainPThread) == cf) HALT; | |
1096 | ||
9ce05555 A |
1097 | /* We try to keep the run loop in a valid state as long as possible, |
1098 | since sources may have non-retained references to the run loop. | |
1099 | Another reason is that we don't want to lock the run loop for | |
1100 | callback reasons, if we can get away without that. We start by | |
1101 | eliminating the sources, since they are the most likely to call | |
1102 | back into the run loop during their "cancellation". Common mode | |
1103 | items will be removed from the mode indirectly by the following | |
1104 | three lines. */ | |
1105 | __CFRunLoopSetDeallocating(rl); | |
1106 | if (NULL != rl->_modes) { | |
5645d61f | 1107 | CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); // remove references to rl |
9ce05555 A |
1108 | CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl); |
1109 | CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl); | |
1110 | CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl); | |
1111 | } | |
1112 | __CFRunLoopLock(rl); | |
cf7d2af9 A |
1113 | struct _block_item *item = rl->_blocks_head; |
1114 | while (item) { | |
1115 | struct _block_item *curr = item; | |
1116 | item = item->_next; | |
1117 | CFRelease(curr->_mode); | |
1118 | Block_release(curr->_block); | |
1119 | free(curr); | |
1120 | } | |
9ce05555 A |
1121 | if (NULL != rl->_commonModeItems) { |
1122 | CFRelease(rl->_commonModeItems); | |
1123 | } | |
1124 | if (NULL != rl->_commonModes) { | |
1125 | CFRelease(rl->_commonModes); | |
1126 | } | |
1127 | if (NULL != rl->_modes) { | |
1128 | CFRelease(rl->_modes); | |
1129 | } | |
d8925383 A |
1130 | __CFPortFree(rl->_wakeUpPort); |
1131 | rl->_wakeUpPort = CFPORT_NULL; | |
cf7d2af9 A |
1132 | #if DEPLOYMENT_TARGET_WINDOWS |
1133 | __CFPortFree(rl->_msgUpdatePort); | |
1134 | rl->_msgUpdatePort = CFPORT_NULL; | |
1135 | #endif | |
9ce05555 | 1136 | __CFRunLoopUnlock(rl); |
cf7d2af9 | 1137 | memset((char *)cf + sizeof(CFRuntimeBase), 0x8C, sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase)); |
9ce05555 A |
1138 | } |
1139 | ||
1140 | static const CFRuntimeClass __CFRunLoopModeClass = { | |
1141 | 0, | |
1142 | "CFRunLoopMode", | |
1143 | NULL, // init | |
1144 | NULL, // copy | |
1145 | __CFRunLoopModeDeallocate, | |
1146 | __CFRunLoopModeEqual, | |
1147 | __CFRunLoopModeHash, | |
1148 | NULL, // | |
1149 | __CFRunLoopModeCopyDescription | |
1150 | }; | |
1151 | ||
1152 | static const CFRuntimeClass __CFRunLoopClass = { | |
1153 | 0, | |
1154 | "CFRunLoop", | |
1155 | NULL, // init | |
1156 | NULL, // copy | |
1157 | __CFRunLoopDeallocate, | |
1158 | NULL, | |
1159 | NULL, | |
1160 | NULL, // | |
1161 | __CFRunLoopCopyDescription | |
1162 | }; | |
1163 | ||
cf7d2af9 A |
1164 | static void __CFFinalizeRunLoop(uintptr_t data); |
1165 | ||
9ce05555 A |
1166 | __private_extern__ void __CFRunLoopInitialize(void) { |
1167 | __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass); | |
1168 | __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass); | |
cf7d2af9 A |
1169 | #if DEPLOYMENT_TARGET_WINDOWS |
1170 | __kCFRunLoopWakeUpMessage = RegisterWindowMessageW((LPCWSTR)L"CFRunLoopWakeup"); | |
1171 | __kCFRunLoopV1SourceReadyMessage = RegisterWindowMessageW((LPCWSTR)L"CFRunLoopV1Ready"); | |
1172 | #endif | |
1173 | #if DEPLOYMENT_TARGET_WINDOWS | |
1174 | if (~0 == __CFTSDKeyRunLoopKey) __CFTSDKeyRunLoopKey = TlsAlloc(); | |
1175 | #else | |
1176 | pthread_key_init_np(__CFTSDKeyRunLoop, NULL); | |
1177 | pthread_key_init_np(__CFTSDKeyRunLoopCntr, (void *)__CFFinalizeRunLoop); | |
1178 | #endif | |
9ce05555 A |
1179 | } |
1180 | ||
1181 | CFTypeID CFRunLoopGetTypeID(void) { | |
1182 | return __kCFRunLoopTypeID; | |
1183 | } | |
1184 | ||
cf7d2af9 | 1185 | static CFRunLoopRef __CFRunLoopCreate(pthread_t t) { |
9ce05555 A |
1186 | CFRunLoopRef loop = NULL; |
1187 | CFRunLoopModeRef rlm; | |
1188 | uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase); | |
1189 | loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL); | |
1190 | if (NULL == loop) { | |
1191 | return NULL; | |
1192 | } | |
1193 | loop->_stopped = NULL; | |
bd5b749c | 1194 | CF_SPINLOCK_INIT_FOR_STRUCTS(loop->_lock); |
d8925383 A |
1195 | loop->_wakeUpPort = __CFPortAllocate(); |
1196 | if (CFPORT_NULL == loop->_wakeUpPort) HALT; | |
cf7d2af9 A |
1197 | #if DEPLOYMENT_TARGET_WINDOWS |
1198 | loop->_msgUpdatePort = CFPORT_NULL; | |
1199 | #endif | |
1200 | loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); | |
9ce05555 A |
1201 | CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode); |
1202 | loop->_commonModeItems = NULL; | |
1203 | loop->_currentMode = NULL; | |
cf7d2af9 | 1204 | loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
9ce05555 | 1205 | _CFSetSetCapacity(loop->_modes, 10); |
cf7d2af9 A |
1206 | loop->_blocks_head = NULL; |
1207 | loop->_blocks_tail = NULL; | |
bd5b749c | 1208 | loop->_counterpart = NULL; |
cf7d2af9 | 1209 | loop->_pthread = t; |
9ce05555 A |
1210 | rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true); |
1211 | if (NULL != rlm) __CFRunLoopModeUnlock(rlm); | |
1212 | return loop; | |
1213 | } | |
1214 | ||
5645d61f | 1215 | static CFMutableDictionaryRef __CFRunLoops = NULL; |
bd5b749c | 1216 | static CFSpinLock_t loopsLock = CFSpinLockInit; |
d8925383 | 1217 | |
cf7d2af9 | 1218 | // should only be called by Foundation |
bd5b749c | 1219 | // t==0 is a synonym for "main thread" that always works |
cf7d2af9 A |
1220 | CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) { |
1221 | if (pthread_equal(t, kNilPthreadT)) { | |
1222 | t = _CFMainPThread; | |
1223 | } | |
bd5b749c | 1224 | __CFSpinLock(&loopsLock); |
5645d61f | 1225 | if (!__CFRunLoops) { |
bd5b749c | 1226 | __CFSpinUnlock(&loopsLock); |
5645d61f | 1227 | CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); |
cf7d2af9 A |
1228 | CFRunLoopRef mainLoop = __CFRunLoopCreate(_CFMainPThread); |
1229 | CFDictionarySetValue(dict, pthreadPointer(_CFMainPThread), mainLoop); | |
5645d61f | 1230 | if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) { |
bd5b749c | 1231 | CFRelease(dict); |
bd5b749c | 1232 | } |
5645d61f | 1233 | CFRelease(mainLoop); |
bd5b749c A |
1234 | __CFSpinLock(&loopsLock); |
1235 | } | |
cf7d2af9 | 1236 | CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); |
bd5b749c A |
1237 | if (!loop) { |
1238 | __CFSpinUnlock(&loopsLock); | |
cf7d2af9 | 1239 | CFRunLoopRef newLoop = __CFRunLoopCreate(t); |
bd5b749c | 1240 | __CFSpinLock(&loopsLock); |
5645d61f A |
1241 | loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); |
1242 | if (!loop) { | |
1243 | CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); | |
bd5b749c A |
1244 | loop = newLoop; |
1245 | } | |
5645d61f | 1246 | CFRelease(newLoop); |
9ce05555 | 1247 | } |
cf7d2af9 A |
1248 | if (pthread_equal(t, pthread_self())) { |
1249 | #if DEPLOYMENT_TARGET_WINDOWS | |
1250 | TlsSetValue(__CFTSDKeyRunLoopKey, (LPVOID)(PTHREAD_DESTRUCTOR_ITERATIONS-1)); | |
1251 | #else | |
1252 | pthread_setspecific(__CFTSDKeyRunLoop, (void *)loop); | |
1253 | if (0 == pthread_getspecific(__CFTSDKeyRunLoopCntr)) { | |
1254 | pthread_setspecific(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1)); | |
1255 | } | |
1256 | #endif | |
1257 | #if DEPLOYMENT_TARGET_WINDOWS | |
1258 | // Install our message hook so we can spin the runloop | |
1259 | loop->_threadID = GetCurrentThreadId(); | |
1260 | //#if MARRY_MESSAGE_QUEUE | |
1261 | if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) { | |
1262 | #ifdef _DEBUG | |
1263 | __CFGetThreadSpecificData_inline()->_messageHook = SetWindowsHookExW(WH_GETMESSAGE, (HOOKPROC)pumpRunLoopFromMessageQueue, GetModuleHandleW((LPCWSTR)L"CoreFoundation_debug.dll"), loop->_threadID); | |
1264 | #else | |
1265 | __CFGetThreadSpecificData_inline()->_messageHook = SetWindowsHookExW(WH_GETMESSAGE, (HOOKPROC)pumpRunLoopFromMessageQueue, GetModuleHandleW((LPCWSTR)L"CoreFoundation.dll"), loop->_threadID); | |
1266 | #endif | |
1267 | } | |
1268 | //#endif | |
1269 | #endif | |
9ce05555 | 1270 | } |
bd5b749c A |
1271 | __CFSpinUnlock(&loopsLock); |
1272 | return loop; | |
9ce05555 A |
1273 | } |
1274 | ||
cf7d2af9 A |
1275 | // should only be called by Foundation |
1276 | CFRunLoopRef _CFRunLoopGet0b(pthread_t t) { | |
1277 | if (pthread_equal(t, kNilPthreadT)) { | |
1278 | t = _CFMainPThread; | |
1279 | } | |
bd5b749c | 1280 | __CFSpinLock(&loopsLock); |
cf7d2af9 | 1281 | CFRunLoopRef loop = NULL; |
5645d61f | 1282 | if (__CFRunLoops) { |
cf7d2af9 A |
1283 | loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); |
1284 | } | |
5645d61f | 1285 | __CFSpinUnlock(&loopsLock); |
cf7d2af9 A |
1286 | return loop; |
1287 | } | |
1288 | ||
1289 | static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName); | |
1290 | ||
1291 | // Called for each thread as it exits | |
1292 | static void __CFFinalizeRunLoop(uintptr_t data) { | |
1293 | CFRunLoopRef rl = NULL; | |
1294 | if (data <= 1) { | |
1295 | __CFSpinLock(&loopsLock); | |
1296 | if (__CFRunLoops) { | |
1297 | rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self())); | |
1298 | if (rl) CFRetain(rl); | |
1299 | CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self())); | |
1300 | } | |
1301 | __CFSpinUnlock(&loopsLock); | |
1302 | } else { | |
1303 | #if DEPLOYMENT_TARGET_WINDOWS | |
1304 | TlsSetValue(__CFTSDKeyRunLoopKey, (LPVOID)(data - 1)); | |
1305 | #else | |
1306 | pthread_setspecific(__CFTSDKeyRunLoopCntr, (void *)(data - 1)); | |
1307 | #endif | |
1308 | } | |
1309 | if (rl && CFRunLoopGetMain() != rl) { // protect against cooperative threads | |
1310 | if (NULL != rl->_counterpart) { | |
1311 | CFRelease(rl->_counterpart); | |
1312 | rl->_counterpart = NULL; | |
1313 | } | |
1314 | // purge all sources before deallocation | |
5645d61f A |
1315 | CFArrayRef array = CFRunLoopCopyAllModes(rl); |
1316 | for (CFIndex idx = CFArrayGetCount(array); idx--;) { | |
cf7d2af9 | 1317 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx); |
5645d61f A |
1318 | __CFRunLoopRemoveAllSources(rl, modeName); |
1319 | } | |
1320 | __CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes); | |
1321 | CFRelease(array); | |
1322 | } | |
cf7d2af9 A |
1323 | if (rl) CFRelease(rl); |
1324 | } | |
1325 | ||
1326 | pthread_t _CFRunLoopGet1(CFRunLoopRef rl) { | |
1327 | return rl->_pthread; | |
1328 | } | |
1329 | ||
1330 | // should only be called by Foundation | |
1331 | CF_EXPORT CFTypeRef _CFRunLoopGet2(CFRunLoopRef rl) { | |
1332 | CFTypeRef ret = NULL; | |
1333 | __CFSpinLock(&loopsLock); | |
1334 | if (NULL == rl->_counterpart) { | |
1335 | Class cls = (Class)objc_lookUpClass("NSRunLoop"); | |
1336 | if (cls) { | |
1337 | char hasMethod; | |
1338 | CF_OBJC_CALL1(char, hasMethod, cls, "respondsToSelector:", sel_registerName("_new:")); | |
1339 | if (hasMethod) { | |
1340 | void *ns; | |
1341 | CF_OBJC_CALL1(void *, ns, cls, "_new:", rl); | |
1342 | rl->_counterpart = ns ? CFRetain(ns) : NULL; | |
1343 | } | |
1344 | } | |
5645d61f | 1345 | } |
cf7d2af9 A |
1346 | ret = rl->_counterpart; |
1347 | __CFSpinUnlock(&loopsLock); | |
1348 | return ret; | |
5645d61f A |
1349 | } |
1350 | ||
cf7d2af9 A |
1351 | // should only be called by Foundation |
1352 | CF_EXPORT CFTypeRef _CFRunLoopGet2b(CFRunLoopRef rl) { | |
1353 | return rl->_counterpart; | |
1354 | } | |
5645d61f | 1355 | |
cf7d2af9 | 1356 | #if DEPLOYMENT_TARGET_MACOSX |
5645d61f | 1357 | void _CFRunLoopSetCurrent(CFRunLoopRef rl) { |
cf7d2af9 | 1358 | if (pthread_main_np()) return; |
5645d61f A |
1359 | CFRunLoopRef currentLoop = CFRunLoopGetCurrent(); |
1360 | if (rl != currentLoop) { | |
cf7d2af9 | 1361 | CFRetain(currentLoop); // avoid a deallocation of the currentLoop inside the lock |
5645d61f A |
1362 | __CFSpinLock(&loopsLock); |
1363 | if (rl) { | |
1364 | CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl); | |
1365 | } else { | |
1366 | CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self())); | |
cf7d2af9 A |
1367 | } |
1368 | __CFSpinUnlock(&loopsLock); | |
1369 | CFRelease(currentLoop); | |
1370 | pthread_setspecific(__CFTSDKeyRunLoop, NULL); | |
1371 | pthread_setspecific(__CFTSDKeyRunLoopCntr, 0); | |
5645d61f | 1372 | } |
bd5b749c | 1373 | } |
cf7d2af9 | 1374 | #endif |
bd5b749c A |
1375 | |
1376 | CFRunLoopRef CFRunLoopGetMain(void) { | |
1377 | CHECK_FOR_FORK(); | |
cf7d2af9 A |
1378 | static CFRunLoopRef __main = NULL; // no retain needed |
1379 | if (!__main) __main = _CFRunLoopGet0(_CFMainPThread); // no CAS needed | |
1380 | return __main; | |
9ce05555 A |
1381 | } |
1382 | ||
1383 | CFRunLoopRef CFRunLoopGetCurrent(void) { | |
bd5b749c | 1384 | CHECK_FOR_FORK(); |
cf7d2af9 A |
1385 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
1386 | CFRunLoopRef rl = (CFRunLoopRef)pthread_getspecific(__CFTSDKeyRunLoop); | |
1387 | if (rl) return rl; | |
1388 | #endif | |
1389 | return _CFRunLoopGet0(pthread_self()); | |
9ce05555 A |
1390 | } |
1391 | ||
9ce05555 | 1392 | CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) { |
bd5b749c | 1393 | CHECK_FOR_FORK(); |
9ce05555 A |
1394 | CFStringRef result = NULL; |
1395 | __CFRunLoopLock(rl); | |
1396 | if (NULL != rl->_currentMode) { | |
cf7d2af9 | 1397 | result = (CFStringRef)CFRetain(rl->_currentMode->_name); |
9ce05555 A |
1398 | } |
1399 | __CFRunLoopUnlock(rl); | |
1400 | return result; | |
1401 | } | |
1402 | ||
1403 | static void __CFRunLoopGetModeName(const void *value, void *context) { | |
1404 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
1405 | CFMutableArrayRef array = (CFMutableArrayRef)context; | |
1406 | CFArrayAppendValue(array, rlm->_name); | |
1407 | } | |
1408 | ||
1409 | CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) { | |
bd5b749c | 1410 | CHECK_FOR_FORK(); |
9ce05555 A |
1411 | CFMutableArrayRef array; |
1412 | __CFRunLoopLock(rl); | |
bd5b749c | 1413 | array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks); |
9ce05555 A |
1414 | CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array); |
1415 | __CFRunLoopUnlock(rl); | |
1416 | return array; | |
1417 | } | |
1418 | ||
1419 | static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) { | |
1420 | CFTypeRef item = (CFTypeRef)value; | |
1421 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
1422 | CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]); | |
1423 | if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) { | |
1424 | CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName); | |
1425 | } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) { | |
1426 | CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName); | |
1427 | } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) { | |
1428 | CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName); | |
1429 | } | |
1430 | } | |
1431 | ||
1432 | static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) { | |
1433 | CFStringRef modeName = (CFStringRef)value; | |
1434 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
1435 | CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]); | |
1436 | if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) { | |
1437 | CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName); | |
1438 | } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) { | |
1439 | CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName); | |
1440 | } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) { | |
1441 | CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName); | |
1442 | } | |
1443 | } | |
1444 | ||
1445 | static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) { | |
1446 | CFStringRef modeName = (CFStringRef)value; | |
1447 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
1448 | CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]); | |
1449 | if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) { | |
1450 | CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName); | |
1451 | } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) { | |
1452 | CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName); | |
1453 | } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) { | |
1454 | CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName); | |
1455 | } | |
1456 | } | |
1457 | ||
cf7d2af9 | 1458 | CF_EXPORT Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) { |
bd5b749c A |
1459 | __CFRunLoopLock(rl); |
1460 | Boolean present = CFSetContainsValue(rl->_commonModes, modeName); | |
1461 | __CFRunLoopUnlock(rl); | |
1462 | return present; | |
1463 | } | |
1464 | ||
9ce05555 | 1465 | void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) { |
bd5b749c | 1466 | CHECK_FOR_FORK(); |
9ce05555 A |
1467 | if (__CFRunLoopIsDeallocating(rl)) return; |
1468 | __CFRunLoopLock(rl); | |
1469 | if (!CFSetContainsValue(rl->_commonModes, modeName)) { | |
1470 | CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL; | |
1471 | CFSetAddValue(rl->_commonModes, modeName); | |
1472 | __CFRunLoopUnlock(rl); | |
1473 | if (NULL != set) { | |
1474 | CFTypeRef context[2] = {rl, modeName}; | |
1475 | /* add all common-modes items to new mode */ | |
1476 | CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context); | |
1477 | CFRelease(set); | |
1478 | } | |
1479 | } else { | |
1480 | __CFRunLoopUnlock(rl); | |
1481 | } | |
1482 | } | |
1483 | ||
cf7d2af9 A |
1484 | static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFStringRef curMode) { // Call with rl locked |
1485 | if (!rl->_blocks_head) return false; | |
1486 | if (!curMode) return false; | |
1487 | Boolean did = false; | |
1488 | CFAbsoluteTime deadline = CFAbsoluteTimeGetCurrent() + 0.0009765625; | |
1489 | struct _block_item *head = rl->_blocks_head; | |
1490 | struct _block_item *tail = rl->_blocks_tail; | |
1491 | rl->_blocks_head = NULL; | |
1492 | rl->_blocks_tail = NULL; | |
1493 | CFSetRef commonModes = rl->_commonModes; | |
1494 | __CFRunLoopUnlock(rl); | |
1495 | struct _block_item *prev = NULL; | |
1496 | struct _block_item *item = head; | |
1497 | while (item && CFAbsoluteTimeGetCurrent() < deadline) { | |
1498 | struct _block_item *curr = item; | |
1499 | item = item->_next; | |
1500 | Boolean doit = false; | |
1501 | if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) { | |
1502 | doit = CFEqual(curr->_mode, curMode) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode)); | |
1503 | } else { | |
1504 | doit = CFSetContainsValue((CFSetRef)curr->_mode, curMode) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(commonModes, curMode)); | |
1505 | } | |
1506 | if (!doit) prev = curr; | |
1507 | if (doit) { | |
1508 | if (prev) prev->_next = item; | |
1509 | if (curr == head) head = item; | |
1510 | if (curr == tail) tail = prev; | |
1511 | void (^block)(void) = curr->_block; | |
1512 | CFRelease(curr->_mode); | |
1513 | free(curr); | |
1514 | if (doit) { | |
1515 | block(); // rl is not locked, mode is not locked | |
1516 | did = true; | |
1517 | } | |
1518 | Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc | |
1519 | } | |
1520 | } | |
1521 | __CFRunLoopLock(rl); | |
1522 | if (head) { | |
1523 | tail->_next = rl->_blocks_head; | |
1524 | rl->_blocks_head = head; | |
1525 | if (!rl->_blocks_tail) rl->_blocks_tail = tail; | |
1526 | } | |
1527 | return did; | |
1528 | } | |
1529 | ||
bd5b749c A |
1530 | static CFComparisonResult __CFRunLoopObserverQSortComparator(const void *val1, const void *val2, void *context) { |
1531 | CFRunLoopObserverRef o1 = *((CFRunLoopObserverRef *)val1); | |
1532 | CFRunLoopObserverRef o2 = *((CFRunLoopObserverRef *)val2); | |
1533 | if (!o1) { | |
1534 | return (!o2) ? kCFCompareEqualTo : kCFCompareLessThan; | |
1535 | } | |
1536 | if (!o2) { | |
1537 | return kCFCompareGreaterThan; | |
1538 | } | |
9ce05555 A |
1539 | if (o1->_order < o2->_order) return kCFCompareLessThan; |
1540 | if (o2->_order < o1->_order) return kCFCompareGreaterThan; | |
1541 | return kCFCompareEqualTo; | |
1542 | } | |
1543 | ||
9ce05555 A |
1544 | |
1545 | /* rl is unlocked, rlm is locked on entrance and exit */ | |
1546 | /* ALERT: this should collect all the candidate observers from the top level | |
1547 | * and all submodes, recursively, THEN start calling them, in order to obey | |
1548 | * the ordering parameter. */ | |
1549 | static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */ | |
bd5b749c | 1550 | CHECK_FOR_FORK(); |
9ce05555 | 1551 | CFIndex idx, cnt; |
9ce05555 | 1552 | CFArrayRef submodes; |
9ce05555 A |
1553 | |
1554 | /* Fire the observers */ | |
1555 | submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; | |
1556 | if (NULL != rlm->_observers) { | |
bd5b749c | 1557 | cnt = CFSetGetCount(rlm->_observers); |
9ce05555 | 1558 | if (0 < cnt) { |
cf7d2af9 A |
1559 | STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1); |
1560 | CFRunLoopObserverRef *collectedObservers = (CFRunLoopObserverRef *)((cnt <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFRunLoopObserverRef), 0)); | |
bd5b749c | 1561 | CFSetGetValues(rlm->_observers, (const void **)collectedObservers); |
9ce05555 | 1562 | for (idx = 0; idx < cnt; idx++) { |
bd5b749c A |
1563 | CFRunLoopObserverRef rlo = collectedObservers[idx]; |
1564 | if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { | |
1565 | CFRetain(rlo); | |
9ce05555 | 1566 | } else { |
bd5b749c A |
1567 | /* We're not interested in this one - set it to NULL so we don't process it later */ |
1568 | collectedObservers[idx] = NULL; | |
9ce05555 A |
1569 | } |
1570 | } | |
bd5b749c A |
1571 | __CFRunLoopModeUnlock(rlm); |
1572 | CFQSortArray(collectedObservers, cnt, sizeof(CFRunLoopObserverRef), __CFRunLoopObserverQSortComparator, NULL); | |
1573 | for (idx = 0; idx < cnt; idx++) { | |
1574 | CFRunLoopObserverRef rlo = collectedObservers[idx]; | |
1575 | if (rlo) { | |
1576 | __CFRunLoopObserverLock(rlo); | |
1577 | if (__CFIsValid(rlo)) { | |
1578 | __CFRunLoopObserverUnlock(rlo); | |
1579 | __CFRunLoopObserverSetFiring(rlo); | |
1580 | rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */ | |
1581 | __CFRunLoopObserverUnsetFiring(rlo); | |
1582 | if (!__CFRunLoopObserverRepeats(rlo)) { | |
1583 | CFRunLoopObserverInvalidate(rlo); | |
1584 | } | |
1585 | } else { | |
1586 | __CFRunLoopObserverUnlock(rlo); | |
1587 | } | |
1588 | CFRelease(rlo); | |
1589 | } | |
1590 | } | |
9ce05555 | 1591 | __CFRunLoopModeLock(rlm); |
bd5b749c | 1592 | if (collectedObservers != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, collectedObservers); |
9ce05555 | 1593 | } |
9ce05555 A |
1594 | } |
1595 | if (NULL != submodes) { | |
1596 | __CFRunLoopModeUnlock(rlm); | |
1597 | for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) { | |
1598 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx); | |
1599 | CFRunLoopModeRef subrlm; | |
1600 | __CFRunLoopLock(rl); | |
1601 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1602 | __CFRunLoopUnlock(rl); | |
1603 | if (NULL != subrlm) { | |
1604 | __CFRunLoopDoObservers(rl, subrlm, activity); | |
1605 | __CFRunLoopModeUnlock(subrlm); | |
1606 | } | |
1607 | } | |
1608 | CFRelease(submodes); | |
1609 | __CFRunLoopModeLock(rlm); | |
1610 | } | |
1611 | } | |
1612 | ||
1613 | static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) { | |
1614 | CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1; | |
1615 | CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2; | |
1616 | if (o1->_order < o2->_order) return kCFCompareLessThan; | |
1617 | if (o2->_order < o1->_order) return kCFCompareGreaterThan; | |
1618 | return kCFCompareEqualTo; | |
1619 | } | |
1620 | ||
1621 | static void __CFRunLoopCollectSources0(const void *value, void *context) { | |
1622 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value; | |
1623 | CFTypeRef *sources = (CFTypeRef *)context; | |
1624 | if (0 == rls->_context.version0.version && __CFIsValid(rls) && __CFRunLoopSourceIsSignaled(rls)) { | |
1625 | if (NULL == *sources) { | |
1626 | *sources = CFRetain(rls); | |
1627 | } else if (CFGetTypeID(*sources) == __kCFRunLoopSourceTypeID) { | |
1628 | CFTypeRef oldrls = *sources; | |
1629 | *sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); | |
1630 | CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls); | |
1631 | CFArrayAppendValue((CFMutableArrayRef)*sources, rls); | |
1632 | CFRelease(oldrls); | |
1633 | } else { | |
1634 | CFArrayAppendValue((CFMutableArrayRef)*sources, rls); | |
1635 | } | |
1636 | } | |
1637 | } | |
1638 | ||
1639 | /* rl is unlocked, rlm is locked on entrance and exit */ | |
1640 | static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */ | |
bd5b749c | 1641 | CHECK_FOR_FORK(); |
9ce05555 A |
1642 | CFTypeRef sources = NULL; |
1643 | Boolean sourceHandled = false; | |
1644 | CFIndex idx, cnt; | |
1645 | ||
1646 | __CFRunLoopModeUnlock(rlm); // locks have to be taken in order | |
1647 | __CFRunLoopLock(rl); | |
1648 | __CFRunLoopModeLock(rlm); | |
1649 | /* Fire the version 0 sources */ | |
1650 | if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) { | |
1651 | CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources); | |
1652 | } | |
1653 | for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) { | |
1654 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
1655 | CFRunLoopModeRef subrlm; | |
1656 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1657 | if (NULL != subrlm) { | |
1658 | if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) { | |
1659 | CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources); | |
1660 | } | |
1661 | __CFRunLoopModeUnlock(subrlm); | |
1662 | } | |
1663 | } | |
1664 | __CFRunLoopUnlock(rl); | |
1665 | if (NULL != sources) { | |
1666 | // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef | |
1667 | __CFRunLoopModeUnlock(rlm); | |
1668 | if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) { | |
1669 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources; | |
1670 | __CFRunLoopSourceLock(rls); | |
cf7d2af9 A |
1671 | #if DEPLOYMENT_TARGET_WINDOWS |
1672 | if (__CFRunLoopSourceIsSignaled(rls)) { | |
1673 | #endif | |
9ce05555 A |
1674 | __CFRunLoopSourceUnsetSignaled(rls); |
1675 | if (__CFIsValid(rls)) { | |
1676 | __CFRunLoopSourceUnlock(rls); | |
1677 | if (NULL != rls->_context.version0.perform) { | |
1678 | rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ | |
bd5b749c | 1679 | CHECK_FOR_FORK(); |
9ce05555 A |
1680 | } |
1681 | sourceHandled = true; | |
1682 | } else { | |
1683 | __CFRunLoopSourceUnlock(rls); | |
1684 | } | |
cf7d2af9 A |
1685 | #if DEPLOYMENT_TARGET_WINDOWS |
1686 | } else { | |
1687 | __CFRunLoopSourceUnlock(rls); | |
1688 | } | |
1689 | #endif | |
9ce05555 | 1690 | } else { |
cf7d2af9 | 1691 | cnt = CFArrayGetCount((CFArrayRef)sources); |
9ce05555 A |
1692 | CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL); |
1693 | for (idx = 0; idx < cnt; idx++) { | |
cf7d2af9 | 1694 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx); |
9ce05555 | 1695 | __CFRunLoopSourceLock(rls); |
cf7d2af9 A |
1696 | #if DEPLOYMENT_TARGET_WINDOWS |
1697 | if (__CFRunLoopSourceIsSignaled(rls)) { | |
1698 | #endif | |
9ce05555 A |
1699 | __CFRunLoopSourceUnsetSignaled(rls); |
1700 | if (__CFIsValid(rls)) { | |
1701 | __CFRunLoopSourceUnlock(rls); | |
1702 | if (NULL != rls->_context.version0.perform) { | |
1703 | rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ | |
bd5b749c | 1704 | CHECK_FOR_FORK(); |
9ce05555 A |
1705 | } |
1706 | sourceHandled = true; | |
1707 | } else { | |
1708 | __CFRunLoopSourceUnlock(rls); | |
1709 | } | |
cf7d2af9 A |
1710 | #if DEPLOYMENT_TARGET_WINDOWS |
1711 | } else { | |
1712 | __CFRunLoopSourceUnlock(rls); | |
1713 | } | |
1714 | #endif | |
9ce05555 A |
1715 | if (stopAfterHandle && sourceHandled) { |
1716 | break; | |
1717 | } | |
1718 | } | |
1719 | } | |
1720 | CFRelease(sources); | |
1721 | __CFRunLoopModeLock(rlm); | |
1722 | } | |
1723 | return sourceHandled; | |
1724 | } | |
1725 | ||
d8925383 A |
1726 | // msg, size and reply are unused on Windows |
1727 | static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls | |
cf7d2af9 | 1728 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 A |
1729 | , mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply |
1730 | #endif | |
1731 | ) { /* DOES CALLOUT */ | |
bd5b749c | 1732 | CHECK_FOR_FORK(); |
9ce05555 A |
1733 | Boolean sourceHandled = false; |
1734 | ||
1735 | /* Fire a version 1 source */ | |
1736 | CFRetain(rls); | |
1737 | __CFRunLoopModeUnlock(rlm); | |
1738 | __CFRunLoopSourceLock(rls); | |
1739 | if (__CFIsValid(rls)) { | |
1740 | __CFRunLoopSourceUnsetSignaled(rls); | |
1741 | __CFRunLoopSourceUnlock(rls); | |
1742 | if (NULL != rls->_context.version1.perform) { | |
cf7d2af9 | 1743 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 | 1744 | *reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info); /* CALLOUT */ |
bd5b749c | 1745 | CHECK_FOR_FORK(); |
d8925383 | 1746 | #else |
bd5b749c | 1747 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } |
d8925383 | 1748 | rls->_context.version1.perform(rls->_context.version1.info); /* CALLOUT */ |
bd5b749c | 1749 | CHECK_FOR_FORK(); |
d8925383 | 1750 | #endif |
bd5b749c A |
1751 | } else { |
1752 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); } | |
1753 | } | |
9ce05555 A |
1754 | sourceHandled = true; |
1755 | } else { | |
bd5b749c | 1756 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } |
9ce05555 A |
1757 | __CFRunLoopSourceUnlock(rls); |
1758 | } | |
1759 | CFRelease(rls); | |
1760 | __CFRunLoopModeLock(rlm); | |
1761 | return sourceHandled; | |
1762 | } | |
9ce05555 | 1763 | |
cf7d2af9 | 1764 | // mode is locked on entry and exit |
9ce05555 | 1765 | static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ |
cf7d2af9 | 1766 | Boolean timerHandled = false, timerEarly = false; |
9ce05555 A |
1767 | int64_t oldFireTSR = 0; |
1768 | ||
1769 | /* Fire a timer */ | |
1770 | CFRetain(rlt); | |
1771 | __CFRunLoopModeUnlock(rlm); | |
9ce05555 | 1772 | if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) { |
cf7d2af9 A |
1773 | void *context_info = NULL; |
1774 | void (*context_release)(const void *) = NULL; | |
1775 | if (rlt->_context.retain) { | |
1776 | context_info = (void *)rlt->_context.retain(rlt->_context.info); | |
1777 | context_release = rlt->_context.release; | |
1778 | } else { | |
1779 | context_info = rlt->_context.info; | |
1780 | } | |
d8925383 | 1781 | __CFRunLoopTimerUnsetDidFire(rlt); |
9ce05555 | 1782 | __CFRunLoopTimerSetFiring(rlt); |
cf7d2af9 | 1783 | //CFLog(4, CFSTR("Firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name); |
9ce05555 A |
1784 | __CFRunLoopTimerFireTSRLock(); |
1785 | oldFireTSR = rlt->_fireTSR; | |
1786 | __CFRunLoopTimerFireTSRUnlock(); | |
cf7d2af9 A |
1787 | if (0 && CFAbsoluteTimeGetCurrent() < rlt->_nextFireDate) { // not enabled at this time -- causes trouble when clock goes backwards |
1788 | timerEarly = true; | |
1789 | } else { | |
1790 | rlt->_callout(rlt, context_info); /* CALLOUT */ | |
1791 | CHECK_FOR_FORK(); | |
1792 | timerHandled = true; | |
1793 | } | |
1794 | //CFLog(4, CFSTR("Done firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name); | |
9ce05555 | 1795 | __CFRunLoopTimerUnsetFiring(rlt); |
cf7d2af9 A |
1796 | if (context_release) { |
1797 | context_release(context_info); | |
1798 | } | |
9ce05555 | 1799 | } else { |
d8925383 A |
1800 | // If the timer fires while it is firing in a higher activiation, |
1801 | // it is not allowed to fire, but we have to remember that fact. | |
1802 | // Later, if the timer's fire date is being handled manually, we | |
1803 | // need to re-arm the kernel timer, since it has possibly already | |
1804 | // fired (this firing which is being skipped, say) and the timer | |
1805 | // will permanently stop if we completely drop this firing. | |
1806 | if (__CFRunLoopTimerIsFiring(rlt)) __CFRunLoopTimerSetDidFire(rlt); | |
9ce05555 A |
1807 | } |
1808 | if (__CFIsValid(rlt) && timerHandled) { | |
cf7d2af9 | 1809 | if (0.0 == rlt->_interval) { |
9ce05555 A |
1810 | CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ |
1811 | } else { | |
1812 | /* This is just a little bit tricky: we want to support calling | |
1813 | * CFRunLoopTimerSetNextFireDate() from within the callout and | |
1814 | * honor that new time here if it is a later date, otherwise | |
1815 | * it is completely ignored. */ | |
9ce05555 | 1816 | __CFRunLoopTimerFireTSRLock(); |
cf7d2af9 | 1817 | int64_t currentFireTSR = rlt->_fireTSR; |
9ce05555 A |
1818 | if (oldFireTSR < currentFireTSR) { |
1819 | /* Next fire TSR was set, and set to a date after the previous | |
1820 | * fire date, so we honor it. */ | |
d8925383 | 1821 | if (__CFRunLoopTimerDidFire(rlt)) { |
cf7d2af9 | 1822 | __CFRunLoopTimerRescheduleWithAllModes(rlt); |
d8925383 A |
1823 | __CFRunLoopTimerUnsetDidFire(rlt); |
1824 | } | |
9ce05555 A |
1825 | } else { |
1826 | if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) { | |
1827 | currentFireTSR = LLONG_MAX; | |
1828 | } else { | |
1829 | int64_t currentTSR = (int64_t)__CFReadTSR(); | |
1830 | currentFireTSR = oldFireTSR; | |
1831 | while (currentFireTSR <= currentTSR) { | |
1832 | currentFireTSR += rlt->_intervalTSR; | |
1833 | } | |
1834 | } | |
d8925383 | 1835 | rlt->_fireTSR = currentFireTSR; |
cf7d2af9 | 1836 | __CFRunLoopTimerRescheduleWithAllModes(rlt); |
9ce05555 | 1837 | } |
9ce05555 | 1838 | __CFRunLoopTimerFireTSRUnlock(); |
9ce05555 A |
1839 | } |
1840 | } | |
cf7d2af9 A |
1841 | if (__CFIsValid(rlt) && timerEarly) { |
1842 | int64_t now2 = (int64_t)mach_absolute_time(); | |
1843 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
1844 | __CFRunLoopTimerFireTSRLock(); | |
1845 | if (rlt->_nextFireDate < now1) { | |
1846 | rlt->_fireTSR = now2; | |
1847 | } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < rlt->_nextFireDate) { | |
1848 | rlt->_fireTSR = LLONG_MAX; | |
1849 | } else { | |
1850 | rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(rlt->_nextFireDate - now1); | |
1851 | } | |
1852 | __CFRunLoopTimerRescheduleWithAllModes(rlt); | |
1853 | __CFRunLoopTimerFireTSRUnlock(); | |
1854 | } | |
9ce05555 A |
1855 | CFRelease(rlt); |
1856 | __CFRunLoopModeLock(rlm); | |
1857 | return timerHandled; | |
1858 | } | |
1859 | ||
1860 | CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) { | |
bd5b749c | 1861 | CHECK_FOR_FORK(); |
9ce05555 A |
1862 | CFRunLoopModeRef rlm; |
1863 | Boolean result = false; | |
1864 | __CFRunLoopLock(rl); | |
1865 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
cf7d2af9 | 1866 | if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm, NULL)) { |
9ce05555 A |
1867 | result = true; |
1868 | } | |
1869 | __CFRunLoopUnlock(rl); | |
1870 | if (rlm) __CFRunLoopModeUnlock(rlm); | |
1871 | return result; | |
1872 | } | |
1873 | ||
1874 | // rl is locked, rlm is locked on entry and exit | |
d8925383 | 1875 | static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPortSet portSet) { |
9ce05555 A |
1876 | CFIndex idx, cnt; |
1877 | const void **list, *buffer[256]; | |
1878 | ||
1879 | // Timers and version 1 sources go into the portSet currently | |
1880 | if (NULL != rlm->_sources) { | |
1881 | cnt = CFSetGetCount(rlm->_sources); | |
cf7d2af9 | 1882 | list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); |
9ce05555 A |
1883 | CFSetGetValues(rlm->_sources, list); |
1884 | for (idx = 0; idx < cnt; idx++) { | |
1885 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; | |
d8925383 A |
1886 | if (1 == rls->_context.version0.version) { |
1887 | __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ | |
1888 | if (CFPORT_NULL != port) { | |
1889 | __CFPortSetInsert(port, portSet); | |
1890 | } | |
9ce05555 A |
1891 | } |
1892 | } | |
1893 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1894 | } | |
cf7d2af9 | 1895 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 A |
1896 | if (NULL != rlm->_timers) { |
1897 | cnt = CFSetGetCount(rlm->_timers); | |
1898 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
1899 | CFSetGetValues(rlm->_timers, list); | |
1900 | for (idx = 0; idx < cnt; idx++) { | |
1901 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx]; | |
1902 | if (MACH_PORT_NULL != rlt->_port) { | |
1903 | mach_port_insert_member(mach_task_self(), rlt->_port, portSet); | |
1904 | } | |
1905 | } | |
1906 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1907 | } | |
d8925383 | 1908 | #endif |
9ce05555 A |
1909 | // iterate over submodes |
1910 | for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) { | |
1911 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
1912 | CFRunLoopModeRef subrlm; | |
1913 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1914 | if (NULL != subrlm) { | |
1915 | __CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet); | |
1916 | __CFRunLoopModeUnlock(subrlm); | |
1917 | } | |
1918 | } | |
1919 | } | |
d8925383 | 1920 | |
bd5b749c | 1921 | static __CFPortSet _LastMainWaitSet = 0; |
d8925383 | 1922 | |
cf7d2af9 | 1923 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 A |
1924 | // return NO if we're the main runloop and there are no messages waiting on the port set |
1925 | int _CFRunLoopInputsReady(void) { | |
bd5b749c | 1926 | CHECK_FOR_FORK(); |
d8925383 | 1927 | if (!pthread_main_np()) return true; |
9ce05555 | 1928 | |
d8925383 A |
1929 | // XXX_PCB: can't be any messages waiting if the wait set is NULL. |
1930 | if (_LastMainWaitSet == MACH_PORT_NULL) return false; | |
1931 | ||
1932 | // prepare a message header with no space for any data, nor a trailer | |
1933 | mach_msg_header_t msg; | |
1934 | msg.msgh_size = sizeof(msg); // just the header, ma'am | |
1935 | // need the waitset, actually XXX | |
1936 | msg.msgh_local_port = _LastMainWaitSet; | |
1937 | msg.msgh_remote_port = MACH_PORT_NULL; | |
1938 | msg.msgh_id = 0; | |
1939 | ||
1940 | 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); | |
1941 | ||
1942 | return (MACH_RCV_TOO_LARGE == ret); | |
bd5b749c A |
1943 | return true; |
1944 | } | |
cf7d2af9 | 1945 | #endif |
bd5b749c A |
1946 | |
1947 | #if 0 | |
1948 | static void print_msg_scan_header(void) { | |
1949 | printf("======== ======== ======== ========\n"); | |
1950 | printf("description\tport\tport type\t\treferences\n"); | |
1951 | } | |
1952 | ||
1953 | static void print_one_port_info(const char *desc, mach_port_t port, mach_msg_type_name_t type) { | |
1954 | mach_port_urefs_t refs; | |
1955 | kern_return_t ret = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs); | |
1956 | if (ret != KERN_SUCCESS) refs = 0; | |
1957 | const char *type_name = "???"; | |
1958 | switch (type) { | |
1959 | case MACH_MSG_TYPE_MOVE_SEND: type_name = "MACH_MSG_TYPE_MOVE_SEND"; break; | |
1960 | case MACH_MSG_TYPE_MOVE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break; | |
1961 | case MACH_MSG_TYPE_MOVE_RECEIVE: type_name = "MACH_MSG_TYPE_MOVE_RECEIVE"; break; | |
1962 | case MACH_MSG_TYPE_MAKE_SEND: type_name = "MACH_MSG_TYPE_MAKE_SEND"; break; | |
1963 | case MACH_MSG_TYPE_MAKE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break; | |
1964 | } | |
1965 | printf("%s\t%p\t%-20s\t%u\n", desc, port, type_name, refs); | |
1966 | } | |
1967 | ||
1968 | static void mach_msg_scan(mach_msg_header_t *msg, int clean) { | |
1969 | Boolean printed_header = false; | |
1970 | /* | |
1971 | * The msgh_local_port field doesn't hold a port right. | |
1972 | * The receive operation consumes the destination port right. | |
1973 | */ | |
1974 | if (MACH_PORT_NULL != msg->msgh_remote_port) { | |
1975 | if (! printed_header) print_msg_scan_header(); | |
1976 | printed_header = true; | |
1977 | print_one_port_info("msg->msgh_remote_port", msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(msg->msgh_bits)); | |
1978 | } | |
1979 | if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) { | |
1980 | mach_msg_body_t *body = (mach_msg_body_t *) (msg + 1); | |
1981 | mach_msg_descriptor_t *saddr = (mach_msg_descriptor_t *) ((mach_msg_base_t *) msg + 1); | |
1982 | mach_msg_descriptor_t *eaddr = saddr + body->msgh_descriptor_count; | |
1983 | for ( ; saddr < eaddr; saddr++) { | |
1984 | switch (saddr->type.type) { | |
1985 | case MACH_MSG_PORT_DESCRIPTOR:; | |
1986 | mach_msg_port_descriptor_t *dsc = &saddr->port; | |
1987 | if (! printed_header) print_msg_scan_header(); | |
1988 | printed_header = true; | |
1989 | print_one_port_info("port in body", dsc->name, dsc->disposition); | |
1990 | // if (clean) mach_port_deallocate(mach_task_self(), dsc->name); | |
1991 | break; | |
1992 | case MACH_MSG_OOL_PORTS_DESCRIPTOR:; | |
1993 | mach_msg_ool_ports_descriptor_t *dsc2 = &saddr->ool_ports; | |
1994 | mach_port_t *ports = (mach_port_t *) dsc2->address; | |
1995 | for (mach_msg_type_number_t j = 0; j < dsc2->count; j++, ports++) { | |
1996 | if (! printed_header) print_msg_scan_header(); | |
1997 | printed_header = true; | |
1998 | print_one_port_info("port in OOL ports", *ports, dsc2->disposition); | |
1999 | } | |
2000 | break; | |
2001 | } | |
2002 | } | |
2003 | } | |
d8925383 | 2004 | } |
bd5b749c | 2005 | #endif |
d8925383 | 2006 | |
cf7d2af9 A |
2007 | static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode, Boolean waitIfEmpty) __attribute__((noinline)); |
2008 | #if DEPLOYMENT_TARGET_WINDOWS | |
2009 | static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm); | |
2010 | #endif | |
2011 | ||
9ce05555 | 2012 | /* rl is unlocked, rlm locked on entrance and exit */ |
cf7d2af9 | 2013 | static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode, Boolean waitIfEmpty) { /* DOES CALLOUT */ |
9ce05555 | 2014 | int64_t termTSR; |
cf7d2af9 | 2015 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 | 2016 | mach_port_name_t timeoutPort = MACH_PORT_NULL; |
cf7d2af9 A |
2017 | mach_port_name_t dispatchPort = MACH_PORT_NULL; |
2018 | Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ))); | |
2019 | if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF(); | |
9ce05555 A |
2020 | #endif |
2021 | Boolean poll = false; | |
d8925383 | 2022 | Boolean firstPass = true; |
9ce05555 A |
2023 | |
2024 | if (__CFRunLoopIsStopped(rl)) { | |
cf7d2af9 | 2025 | __CFRunLoopUnsetStopped(rl); |
9ce05555 A |
2026 | return kCFRunLoopRunStopped; |
2027 | } else if (rlm->_stopped) { | |
2028 | rlm->_stopped = false; | |
2029 | return kCFRunLoopRunStopped; | |
2030 | } | |
9ce05555 A |
2031 | if (seconds <= 0.0) { |
2032 | termTSR = 0; | |
cf7d2af9 | 2033 | } else if (TIMER_INTERVAL_LIMIT < seconds) { |
9ce05555 A |
2034 | termTSR = LLONG_MAX; |
2035 | } else { | |
2036 | termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds); | |
cf7d2af9 | 2037 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 A |
2038 | timeoutPort = mk_timer_create(); |
2039 | mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR)); | |
9ce05555 | 2040 | #endif |
d8925383 | 2041 | } |
9ce05555 A |
2042 | if (seconds <= 0.0) { |
2043 | poll = true; | |
2044 | } | |
5645d61f | 2045 | if (rl == CFRunLoopGetMain()) _LastMainWaitSet = CFPORT_NULL; |
9ce05555 | 2046 | for (;;) { |
d8925383 | 2047 | __CFPortSet waitSet = CFPORT_NULL; |
d8925383 A |
2048 | Boolean destroyWaitSet = false; |
2049 | CFRunLoopSourceRef rls; | |
cf7d2af9 | 2050 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 A |
2051 | mach_msg_header_t *msg; |
2052 | kern_return_t ret; | |
cf7d2af9 | 2053 | uint8_t buffer[2048]; |
d8925383 A |
2054 | #else |
2055 | CFArrayRef timersToCall = NULL; | |
9ce05555 | 2056 | #endif |
9ce05555 | 2057 | int32_t returnValue = 0; |
cf7d2af9 A |
2058 | Boolean sourceHandledThisLoop = false; |
2059 | ||
2060 | // Do not handle blocks here, as there is already a handling at | |
2061 | // the end of this loop, and that just makes for two handlings | |
2062 | // in a row when the loop cycles. | |
2063 | if (rlm->_observerMask & kCFRunLoopBeforeTimers || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); | |
2064 | if (rlm->_observerMask & kCFRunLoopBeforeSources || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); | |
2065 | if (rl->_blocks_head) { | |
2066 | __CFRunLoopModeUnlock(rlm); | |
2067 | __CFRunLoopLock(rl); | |
2068 | __CFRunLoopDoBlocks(rl, rlm->_name); | |
2069 | __CFRunLoopModeLock(rlm); | |
2070 | __CFRunLoopUnlock(rl); | |
2071 | } | |
9ce05555 | 2072 | |
cf7d2af9 | 2073 | sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle) || sourceHandledThisLoop; |
9ce05555 | 2074 | |
f64f9b69 A |
2075 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
2076 | if (MACH_PORT_NULL != dispatchPort) { | |
2077 | msg = (mach_msg_header_t *)buffer; | |
2078 | msg->msgh_size = sizeof(buffer); | |
2079 | msg->msgh_bits = 0; | |
2080 | msg->msgh_local_port = dispatchPort; | |
2081 | msg->msgh_remote_port = MACH_PORT_NULL; | |
2082 | msg->msgh_id = 0; | |
2083 | ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TIMEOUT|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, dispatchPort, 0, MACH_PORT_NULL); | |
2084 | ||
2085 | if (MACH_MSG_SUCCESS == ret) { | |
2086 | __CFRunLoopModeUnlock(rlm); | |
2087 | pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)3); | |
2088 | _dispatch_main_queue_callback_4CF(msg); | |
2089 | sourceHandledThisLoop = true; | |
2090 | pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)0); | |
2091 | __CFRunLoopLock(rl); | |
2092 | __CFRunLoopModeLock(rlm); | |
2093 | __CFRunLoopUnlock(rl); | |
2094 | } else if (MACH_RCV_TIMED_OUT == ret) { | |
2095 | msg = NULL; | |
2096 | } else { | |
2097 | HALT; | |
2098 | } | |
2099 | } | |
2100 | #endif | |
2101 | ||
9ce05555 A |
2102 | if (sourceHandledThisLoop) { |
2103 | poll = true; | |
cf7d2af9 A |
2104 | if (rl->_blocks_head) { |
2105 | __CFRunLoopModeUnlock(rlm); | |
2106 | __CFRunLoopLock(rl); | |
2107 | __CFRunLoopDoBlocks(rl, rlm->_name); | |
2108 | __CFRunLoopModeLock(rlm); | |
2109 | __CFRunLoopUnlock(rl); | |
2110 | } | |
9ce05555 A |
2111 | } |
2112 | ||
2113 | if (!poll) { | |
cf7d2af9 A |
2114 | if (rlm->_observerMask & kCFRunLoopBeforeWaiting || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); |
2115 | // do not do any user callouts after this point (after notifying of sleeping) | |
9ce05555 A |
2116 | __CFRunLoopSetSleeping(rl); |
2117 | } | |
9ce05555 A |
2118 | if (NULL != rlm->_submodes) { |
2119 | // !!! what do we do if this doesn't succeed? | |
d8925383 A |
2120 | waitSet = __CFPortSetAllocate(); |
2121 | if (CFPORT_NULL == waitSet) HALT; | |
9ce05555 A |
2122 | __CFRunLoopModeUnlock(rlm); |
2123 | __CFRunLoopLock(rl); | |
2124 | __CFRunLoopModeLock(rlm); | |
2125 | __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet); | |
2126 | __CFRunLoopUnlock(rl); | |
d8925383 | 2127 | destroyWaitSet = true; |
9ce05555 A |
2128 | } else { |
2129 | waitSet = rlm->_portSet; | |
9ce05555 | 2130 | } |
cf7d2af9 A |
2131 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
2132 | if (CFPORT_NULL != timeoutPort) { | |
2133 | __CFPortSetInsert(timeoutPort, waitSet); | |
2134 | } | |
2135 | if (CFPORT_NULL != dispatchPort) { | |
2136 | __CFPortSetInsert(dispatchPort, waitSet); | |
2137 | } | |
2138 | #endif | |
5645d61f | 2139 | if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet; |
9ce05555 A |
2140 | __CFRunLoopModeUnlock(rlm); |
2141 | ||
cf7d2af9 A |
2142 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
2143 | if (kCFUseCollectableAllocator && !poll) { | |
2144 | memset(buffer, 0, sizeof(buffer)); | |
2145 | objc_clear_stack(0); | |
2146 | } | |
2147 | ||
d8925383 | 2148 | msg = (mach_msg_header_t *)buffer; |
9ce05555 A |
2149 | msg->msgh_size = sizeof(buffer); |
2150 | ||
cf7d2af9 A |
2151 | //static uint64_t _last_value = 0; |
2152 | //uint64_t new_val = mach_absolute_time(); | |
2153 | //printf(". %d before %qd (%qd)\n", getpid(), new_val, new_val - _last_value); | |
2154 | //_last_value = new_val; | |
2155 | ||
9ce05555 | 2156 | /* In that sleep of death what nightmares may come ... */ |
cf7d2af9 | 2157 | try_receive:; |
9ce05555 A |
2158 | msg->msgh_bits = 0; |
2159 | msg->msgh_local_port = waitSet; | |
2160 | msg->msgh_remote_port = MACH_PORT_NULL; | |
2161 | msg->msgh_id = 0; | |
cf7d2af9 A |
2162 | 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_AV), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL); |
2163 | ||
9ce05555 | 2164 | if (MACH_RCV_TOO_LARGE == ret) { |
cf7d2af9 | 2165 | uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); |
9ce05555 A |
2166 | if (msg == (mach_msg_header_t *)buffer) msg = NULL; |
2167 | msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0); | |
2168 | msg->msgh_size = newSize; | |
2169 | goto try_receive; | |
2170 | } else if (MACH_RCV_TIMED_OUT == ret) { | |
2171 | // timeout, for poll | |
2172 | if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); | |
2173 | msg = NULL; | |
2174 | } else if (MACH_MSG_SUCCESS != ret) { | |
2175 | HALT; | |
2176 | } | |
cf7d2af9 A |
2177 | //new_val = mach_absolute_time(); |
2178 | //printf(". %d after %qd (%qd)\n", getpid(), new_val, new_val - _last_value); | |
2179 | //_last_value = new_val; | |
2180 | #elif DEPLOYMENT_TARGET_WINDOWS | |
d8925383 A |
2181 | DWORD waitResult = WAIT_TIMEOUT; |
2182 | HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; | |
2183 | HANDLE *handles; | |
2184 | uint32_t handleCount; | |
2185 | Boolean freeHandles; | |
2186 | if (destroyWaitSet) { | |
2187 | // wait set is a local, no one else could modify it, no need to copy handles | |
2188 | handles = waitSet->handles; | |
2189 | handleCount = waitSet->used; | |
2190 | freeHandles = FALSE; | |
2191 | } else { | |
2192 | // copy out the handles to be safe from other threads at work | |
2193 | handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount); | |
2194 | freeHandles = (handles != handleBuf); | |
2195 | } | |
2196 | // should msgQMask be an OR'ing of this and all submodes' masks? | |
9ce05555 | 2197 | if (0 == GetQueueStatus(rlm->_msgQMask)) { |
cf7d2af9 A |
2198 | DWORD timeout; |
2199 | if (poll) | |
2200 | timeout = 0; | |
2201 | else { | |
2202 | int64_t nextStop; | |
bd5b749c | 2203 | __CFRunLoopModeLock(rlm); |
cf7d2af9 A |
2204 | nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm); |
2205 | if (nextStop <= 0) | |
2206 | nextStop = termTSR; | |
2207 | else if (nextStop > termTSR) | |
2208 | nextStop = termTSR; | |
2209 | // else the next stop is dictated by the next timer | |
2210 | int64_t timeoutTSR = nextStop - __CFReadTSR(); | |
2211 | if (timeoutTSR < 0) | |
2212 | timeout = 0; | |
2213 | else { | |
2214 | CFTimeInterval timeoutCF = __CFTSRToTimeInterval(timeoutTSR) * 1000; | |
2215 | if (timeoutCF > MAXDWORD) | |
2216 | timeout = INFINITE; | |
2217 | else | |
2218 | timeout = (DWORD)timeoutCF; | |
2219 | } | |
2220 | } | |
2221 | waitResult = WaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout); | |
d8925383 A |
2222 | } |
2223 | ResetEvent(rl->_wakeUpPort); | |
9ce05555 | 2224 | #endif |
cf7d2af9 A |
2225 | __CFRunLoopLock(rl); |
2226 | __CFRunLoopModeLock(rlm); | |
2227 | __CFRunLoopUnlock(rl); | |
9ce05555 | 2228 | if (destroyWaitSet) { |
d8925383 | 2229 | __CFPortSetFree(waitSet); |
5645d61f | 2230 | if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0; |
cf7d2af9 A |
2231 | } else { |
2232 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
2233 | if (CFPORT_NULL != timeoutPort) { | |
2234 | __CFPortSetRemove(timeoutPort, waitSet); | |
2235 | } | |
2236 | if (CFPORT_NULL != dispatchPort) { | |
2237 | __CFPortSetRemove(dispatchPort, waitSet); | |
2238 | } | |
2239 | #endif | |
9ce05555 | 2240 | } |
cf7d2af9 | 2241 | |
9ce05555 A |
2242 | if (!poll) { |
2243 | __CFRunLoopUnsetSleeping(rl); | |
cf7d2af9 | 2244 | if (rlm->_observerMask & kCFRunLoopAfterWaiting || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); |
9ce05555 A |
2245 | } |
2246 | poll = false; | |
2247 | __CFRunLoopModeUnlock(rlm); | |
2248 | __CFRunLoopLock(rl); | |
2249 | __CFRunLoopModeLock(rlm); | |
2250 | ||
d8925383 | 2251 | __CFPort livePort = CFPORT_NULL; |
cf7d2af9 | 2252 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 | 2253 | if (NULL != msg) { |
d8925383 A |
2254 | livePort = msg->msgh_local_port; |
2255 | } | |
cf7d2af9 | 2256 | #elif DEPLOYMENT_TARGET_WINDOWS |
d8925383 A |
2257 | CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError()); |
2258 | if (waitResult == WAIT_TIMEOUT) { | |
2259 | // do nothing, just return to caller | |
2260 | } else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) { | |
cf7d2af9 | 2261 | // a handle was signaled |
d8925383 A |
2262 | livePort = handles[waitResult-WAIT_OBJECT_0]; |
2263 | } else if (waitResult == WAIT_OBJECT_0+handleCount) { | |
2264 | // windows message received - the CFWindowsMessageQueue will pick this up when | |
2265 | // the v0 RunLoopSources get their chance | |
2266 | } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) { | |
2267 | // an "abandoned mutex object" | |
2268 | livePort = handles[waitResult-WAIT_ABANDONED_0]; | |
2269 | } else { | |
2270 | CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult); | |
2271 | } | |
2272 | if (freeHandles) | |
2273 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles); | |
2274 | timersToCall = __CFRunLoopTimersToFire(rl, rlm); | |
2275 | #endif | |
2276 | ||
2277 | if (CFPORT_NULL == livePort) { | |
2278 | __CFRunLoopUnlock(rl); | |
d8925383 A |
2279 | } else if (livePort == rl->_wakeUpPort) { |
2280 | // wakeup | |
cf7d2af9 A |
2281 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("wakeupPort was signalled")); } |
2282 | __CFRunLoopUnlock(rl); // leave run loop unlocked | |
d8925383 | 2283 | } |
cf7d2af9 | 2284 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 A |
2285 | else if (livePort == timeoutPort) { |
2286 | returnValue = kCFRunLoopRunTimedOut; | |
2287 | __CFRunLoopUnlock(rl); | |
cf7d2af9 A |
2288 | } else if (dispatchPort == livePort) { |
2289 | __CFRunLoopModeUnlock(rlm); | |
2290 | __CFRunLoopUnlock(rl); | |
2291 | pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)3); | |
2292 | _dispatch_main_queue_callback_4CF(msg); | |
2293 | sourceHandledThisLoop = true; | |
2294 | pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)0); | |
2295 | __CFRunLoopLock(rl); | |
2296 | __CFRunLoopModeLock(rlm); | |
2297 | __CFRunLoopUnlock(rl); // leave run loop unlocked | |
d8925383 A |
2298 | } else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) { |
2299 | mach_msg_header_t *reply = NULL; | |
2300 | __CFRunLoopUnlock(rl); | |
bd5b749c | 2301 | // mach_msg_scan(msg, 0); |
d8925383 A |
2302 | if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) { |
2303 | sourceHandledThisLoop = true; | |
2304 | } | |
bd5b749c | 2305 | // mach_msg_scan(msg, 1); |
d8925383 A |
2306 | if (NULL != reply) { |
2307 | ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); | |
9ce05555 | 2308 | //#warning CF: what should be done with the return value? |
d8925383 | 2309 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); |
9ce05555 | 2310 | } |
9ce05555 | 2311 | } else { |
d8925383 A |
2312 | CFRunLoopTimerRef rlt; |
2313 | rlt = __CFRunLoopModeFindTimerForMachPort(rlm, livePort); | |
2314 | __CFRunLoopUnlock(rl); | |
2315 | if (NULL != rlt) { | |
2316 | __CFRunLoopDoTimer(rl, rlm, rlt); | |
2317 | } | |
2318 | } | |
2319 | if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); | |
2320 | #else | |
2321 | else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) { | |
9ce05555 | 2322 | __CFRunLoopUnlock(rl); |
bd5b749c | 2323 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("Source %@ was signalled"), rls); } |
d8925383 A |
2324 | if (__CFRunLoopDoSource1(rl, rlm, rls)) { |
2325 | sourceHandledThisLoop = true; | |
2326 | } | |
2327 | } | |
2328 | #endif | |
2329 | ||
cf7d2af9 A |
2330 | #if DEPLOYMENT_TARGET_WINDOWS |
2331 | if (NULL != timersToCall) { | |
2332 | int i; | |
2333 | for (i = CFArrayGetCount(timersToCall)-1; i >= 0; i--) | |
2334 | __CFRunLoopDoTimer(rl, rlm, (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timersToCall, i)); | |
2335 | CFRelease(timersToCall); | |
2336 | } | |
2337 | #endif | |
2338 | ||
2339 | if (rl->_blocks_head) { | |
2340 | __CFRunLoopModeUnlock(rlm); // locks must be taken in order | |
2341 | __CFRunLoopLock(rl); | |
2342 | __CFRunLoopDoBlocks(rl, rlm->_name); | |
2343 | __CFRunLoopModeLock(rlm); | |
2344 | __CFRunLoopUnlock(rl); | |
2345 | } | |
9ce05555 A |
2346 | if (sourceHandledThisLoop && stopAfterHandle) { |
2347 | returnValue = kCFRunLoopRunHandledSource; | |
d8925383 A |
2348 | // If we're about to timeout, but we just did a zero-timeout poll that only found our own |
2349 | // internal wakeup signal on the first look at the portset, we'll go around the loop one | |
2350 | // more time, so as not to starve a v1 source that was just added along with a runloop wakeup. | |
2351 | } else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) { | |
9ce05555 A |
2352 | returnValue = kCFRunLoopRunTimedOut; |
2353 | } else if (__CFRunLoopIsStopped(rl)) { | |
cf7d2af9 | 2354 | __CFRunLoopUnsetStopped(rl); |
9ce05555 A |
2355 | returnValue = kCFRunLoopRunStopped; |
2356 | } else if (rlm->_stopped) { | |
2357 | rlm->_stopped = false; | |
2358 | returnValue = kCFRunLoopRunStopped; | |
cf7d2af9 | 2359 | } else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm, previousMode)) { |
9ce05555 A |
2360 | returnValue = kCFRunLoopRunFinished; |
2361 | } | |
9ce05555 | 2362 | if (0 != returnValue) { |
cf7d2af9 | 2363 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 | 2364 | if (MACH_PORT_NULL != timeoutPort) { |
9ce05555 A |
2365 | mk_timer_destroy(timeoutPort); |
2366 | } | |
2367 | #endif | |
2368 | return returnValue; | |
2369 | } | |
d8925383 | 2370 | firstPass = false; |
9ce05555 A |
2371 | } |
2372 | } | |
2373 | ||
9ce05555 | 2374 | SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ |
bd5b749c | 2375 | CHECK_FOR_FORK(); |
9ce05555 A |
2376 | if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished; |
2377 | __CFRunLoopLock(rl); | |
bd5b749c | 2378 | CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false); |
cf7d2af9 A |
2379 | if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) { |
2380 | Boolean did = false; | |
9ce05555 | 2381 | if (currentMode) __CFRunLoopModeUnlock(currentMode); |
cf7d2af9 A |
2382 | #if 0 |
2383 | if (rl->_blocks_head) { | |
2384 | __CFRunLoopDoBlocks(rl, modeName); | |
2385 | } | |
2386 | #endif | |
9ce05555 | 2387 | __CFRunLoopUnlock(rl); |
cf7d2af9 | 2388 | return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished; |
9ce05555 | 2389 | } |
bd5b749c | 2390 | uint32_t *previousStopped = (uint32_t *)rl->_stopped; |
cf7d2af9 | 2391 | rl->_stopped = NULL; |
bd5b749c | 2392 | CFRunLoopModeRef previousMode = rl->_currentMode; |
9ce05555 | 2393 | rl->_currentMode = currentMode; |
cf7d2af9 A |
2394 | #if DEPLOYMENT_TARGET_WINDOWS |
2395 | if (previousMode && currentMode != previousMode) { | |
2396 | if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) | |
2397 | __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); | |
2398 | else | |
2399 | __CFRunLoopUpdateMsgWait(rl); | |
2400 | } | |
2401 | #endif | |
9ce05555 | 2402 | __CFRunLoopUnlock(rl); |
bd5b749c | 2403 | int32_t result; |
cf7d2af9 A |
2404 | @try { |
2405 | if (currentMode->_observerMask & kCFRunLoopEntry || currentMode->_submodes) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); | |
2406 | result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode, false); | |
2407 | if (currentMode->_observerMask & kCFRunLoopExit || currentMode->_submodes) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); | |
2408 | } @finally { | |
2409 | // this kvetches if an exception was raised during a run loop callout, because the mode is not locked | |
2410 | if (0 != currentMode->_lock) { | |
2411 | __CFRunLoopModeUnlock(currentMode); | |
2412 | } | |
2413 | __CFRunLoopLock(rl); | |
2414 | if (rl->_stopped) CFAllocatorDeallocate(kCFAllocatorSystemDefault, (uint32_t *)rl->_stopped); | |
2415 | rl->_stopped = previousStopped; | |
2416 | rl->_currentMode = previousMode; | |
2417 | #if DEPLOYMENT_TARGET_WINDOWS | |
2418 | if (previousMode && currentMode != previousMode) { | |
2419 | if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) | |
2420 | __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); | |
2421 | else | |
2422 | __CFRunLoopUpdateMsgWait(rl); | |
2423 | } | |
2424 | #endif | |
2425 | __CFRunLoopUnlock(rl); | |
2426 | } | |
9ce05555 A |
2427 | return result; |
2428 | } | |
2429 | ||
d8925383 A |
2430 | void CFRunLoopRun(void) { /* DOES CALLOUT */ |
2431 | int32_t result; | |
2432 | do { | |
2433 | result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false); | |
bd5b749c | 2434 | CHECK_FOR_FORK(); |
d8925383 A |
2435 | } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); |
2436 | } | |
2437 | ||
9ce05555 | 2438 | SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ |
bd5b749c | 2439 | CHECK_FOR_FORK(); |
9ce05555 A |
2440 | return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled); |
2441 | } | |
2442 | ||
2443 | static void __CFRunLoopFindMinTimer(const void *value, void *ctx) { | |
2444 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value; | |
d8925383 | 2445 | if (__CFIsValid(rlt)) { |
cf7d2af9 | 2446 | CFRunLoopTimerRef *result = (CFRunLoopTimerRef *)ctx; |
d8925383 A |
2447 | if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) { |
2448 | *result = rlt; | |
2449 | } | |
9ce05555 A |
2450 | } |
2451 | } | |
2452 | ||
cf7d2af9 | 2453 | #if DEPLOYMENT_TARGET_WINDOWS |
d8925383 | 2454 | static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm) { |
9ce05555 A |
2455 | CFRunLoopTimerRef result = NULL; |
2456 | int64_t fireTime = 0; | |
9ce05555 | 2457 | if (rlm) { |
cf7d2af9 A |
2458 | if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { |
2459 | __CFRunLoopTimerFireTSRLock(); | |
2460 | CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result); | |
d8925383 A |
2461 | if (result) |
2462 | fireTime = result->_fireTSR; | |
cf7d2af9 A |
2463 | __CFRunLoopTimerFireTSRUnlock(); |
2464 | } | |
d8925383 A |
2465 | if (NULL != rlm->_submodes) { |
2466 | CFIndex idx, cnt; | |
2467 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
2468 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
2469 | CFRunLoopModeRef subrlm; | |
2470 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
2471 | if (NULL != subrlm) { | |
2472 | int64_t newFireTime = __CFRunLoopGetNextTimerFireTSR(rl, subrlm); | |
2473 | __CFRunLoopModeUnlock(subrlm); | |
2474 | if (fireTime == 0 || (newFireTime != 0 && newFireTime < fireTime)) | |
2475 | fireTime = newFireTime; | |
2476 | } | |
2477 | } | |
2478 | } | |
2479 | __CFRunLoopModeUnlock(rlm); | |
bd5b749c | 2480 | } |
d8925383 A |
2481 | return fireTime; |
2482 | } | |
cf7d2af9 A |
2483 | #endif |
2484 | ||
2485 | // called with rlm locked, if not NULL | |
2486 | static CFAbsoluteTime __CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
2487 | CFRunLoopTimerRef result = NULL; | |
2488 | CFAbsoluteTime fireDate = 0.0; | |
2489 | int64_t now2 = (int64_t)mach_absolute_time(); | |
2490 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
2491 | if (rlm) { | |
2492 | if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { | |
2493 | __CFRunLoopTimerFireTSRLock(); | |
2494 | CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result); | |
2495 | if (result) { | |
2496 | fireDate = (0 == result->_fireTSR) ? 0.0 : (now1 + __CFTSRToTimeInterval(result->_fireTSR - now2)); | |
2497 | } | |
2498 | __CFRunLoopTimerFireTSRUnlock(); | |
2499 | } | |
2500 | if (NULL != rlm->_submodes) { | |
2501 | CFIndex idx, cnt; | |
2502 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
2503 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
2504 | CFRunLoopModeRef subrlm; | |
2505 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
2506 | if (NULL != subrlm) { | |
2507 | CFAbsoluteTime newFireDate = __CFRunLoopGetNextTimerFireDate(rl, subrlm); | |
2508 | __CFRunLoopModeUnlock(subrlm); | |
2509 | if (fireDate == 0 || (newFireDate != 0.0 && newFireDate < fireDate)) | |
2510 | fireDate = newFireDate; | |
2511 | } | |
2512 | } | |
2513 | } | |
2514 | __CFRunLoopModeUnlock(rlm); | |
2515 | } | |
2516 | return fireDate; | |
2517 | } | |
d8925383 A |
2518 | |
2519 | CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) { | |
bd5b749c | 2520 | CHECK_FOR_FORK(); |
d8925383 | 2521 | CFRunLoopModeRef rlm; |
d8925383 A |
2522 | __CFRunLoopLock(rl); |
2523 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2524 | __CFRunLoopUnlock(rl); | |
cf7d2af9 | 2525 | return __CFRunLoopGetNextTimerFireDate(rl, rlm); |
9ce05555 A |
2526 | } |
2527 | ||
2528 | Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) { | |
bd5b749c | 2529 | CHECK_FOR_FORK(); |
9ce05555 A |
2530 | return __CFRunLoopIsSleeping(rl); |
2531 | } | |
2532 | ||
2533 | void CFRunLoopWakeUp(CFRunLoopRef rl) { | |
bd5b749c | 2534 | CHECK_FOR_FORK(); |
cf7d2af9 | 2535 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 A |
2536 | kern_return_t ret; |
2537 | /* We unconditionally try to send the message, since we don't want | |
2538 | * to lose a wakeup, but the send may fail if there is already a | |
2539 | * wakeup pending, since the queue length is 1. */ | |
d8925383 | 2540 | ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0); |
9ce05555 A |
2541 | if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) { |
2542 | HALT; | |
2543 | } | |
2544 | #else | |
d8925383 | 2545 | SetEvent(rl->_wakeUpPort); |
cf7d2af9 A |
2546 | __CFRunLoopLock(rl); |
2547 | if (rl->_threadID == GetCurrentThreadId()) { | |
2548 | PostMessageW(NULL, __kCFRunLoopWakeUpMessage, NULL, NULL); | |
2549 | } else { | |
2550 | PostThreadMessageW(rl->_threadID, __kCFRunLoopWakeUpMessage, NULL, NULL); | |
2551 | } | |
2552 | __CFRunLoopUnlock(rl); | |
9ce05555 A |
2553 | #endif |
2554 | } | |
2555 | ||
2556 | void CFRunLoopStop(CFRunLoopRef rl) { | |
cf7d2af9 | 2557 | Boolean doWake = false; |
bd5b749c | 2558 | CHECK_FOR_FORK(); |
9ce05555 | 2559 | __CFRunLoopLock(rl); |
cf7d2af9 A |
2560 | if (rl->_currentMode) { |
2561 | __CFRunLoopSetStopped(rl); | |
2562 | doWake = true; | |
2563 | } | |
9ce05555 | 2564 | __CFRunLoopUnlock(rl); |
cf7d2af9 A |
2565 | if (doWake) { |
2566 | CFRunLoopWakeUp(rl); | |
2567 | } | |
9ce05555 A |
2568 | } |
2569 | ||
2570 | CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) { | |
bd5b749c | 2571 | CHECK_FOR_FORK(); |
9ce05555 A |
2572 | CFRunLoopModeRef rlm; |
2573 | __CFRunLoopLock(rl); | |
2574 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2575 | __CFRunLoopUnlock(rl); | |
2576 | if (NULL != rlm) { | |
2577 | rlm->_stopped = true; | |
2578 | __CFRunLoopModeUnlock(rlm); | |
2579 | } | |
2580 | CFRunLoopWakeUp(rl); | |
2581 | } | |
2582 | ||
2583 | CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) { | |
bd5b749c | 2584 | CHECK_FOR_FORK(); |
9ce05555 A |
2585 | CFRunLoopModeRef rlm; |
2586 | if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) { | |
2587 | return false; | |
2588 | } else if (CFEqual(modeName, candidateContainedName)) { | |
2589 | return true; | |
2590 | } | |
2591 | __CFRunLoopLock(rl); | |
2592 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2593 | __CFRunLoopUnlock(rl); | |
2594 | if (NULL != rlm) { | |
2595 | CFArrayRef submodes; | |
2596 | if (NULL == rlm->_submodes) { | |
2597 | __CFRunLoopModeUnlock(rlm); | |
2598 | return false; | |
2599 | } | |
2600 | if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) { | |
2601 | __CFRunLoopModeUnlock(rlm); | |
2602 | return true; | |
2603 | } | |
2604 | submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; | |
2605 | __CFRunLoopModeUnlock(rlm); | |
2606 | if (NULL != submodes) { | |
2607 | CFIndex idx, cnt; | |
2608 | for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) { | |
2609 | CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx); | |
2610 | if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) { | |
2611 | CFRelease(submodes); | |
2612 | return true; | |
2613 | } | |
2614 | } | |
2615 | CFRelease(submodes); | |
2616 | } | |
2617 | } | |
2618 | return false; | |
2619 | } | |
2620 | ||
2621 | CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) { | |
bd5b749c | 2622 | CHECK_FOR_FORK(); |
9ce05555 A |
2623 | CFRunLoopModeRef rlm; |
2624 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2625 | // should really do a recursive check here, to make sure that a cycle isn't | |
2626 | // introduced; of course, if that happens, you aren't going to get very far. | |
2627 | if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) { | |
2628 | return; | |
2629 | } else { | |
2630 | __CFRunLoopLock(rl); | |
2631 | rlm = __CFRunLoopFindMode(rl, toModeName, true); | |
2632 | __CFRunLoopUnlock(rl); | |
2633 | if (NULL != rlm) { | |
2634 | if (NULL == rlm->_submodes) { | |
cf7d2af9 | 2635 | rlm->_submodes = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); |
9ce05555 A |
2636 | } |
2637 | if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) { | |
2638 | CFArrayAppendValue(rlm->_submodes, modeName); | |
2639 | } | |
2640 | __CFRunLoopModeUnlock(rlm); | |
2641 | } | |
2642 | } | |
2643 | } | |
2644 | ||
2645 | CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) { | |
bd5b749c | 2646 | CHECK_FOR_FORK(); |
9ce05555 A |
2647 | CFRunLoopModeRef rlm; |
2648 | // should really do a recursive check here, to make sure that a cycle isn't | |
2649 | // introduced; of course, if that happens, you aren't going to get very far. | |
2650 | if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) { | |
2651 | return; | |
2652 | } else { | |
2653 | __CFRunLoopLock(rl); | |
2654 | rlm = __CFRunLoopFindMode(rl, fromModeName, true); | |
2655 | __CFRunLoopUnlock(rl); | |
2656 | if (NULL != rlm) { | |
2657 | if (NULL != rlm->_submodes) { | |
2658 | CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes); | |
2659 | idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName); | |
2660 | if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx); | |
2661 | } | |
2662 | __CFRunLoopModeUnlock(rlm); | |
2663 | } | |
2664 | } | |
2665 | } | |
2666 | ||
cf7d2af9 A |
2667 | void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) { |
2668 | CHECK_FOR_FORK(); | |
2669 | if (CFStringGetTypeID() == CFGetTypeID(mode)) { | |
2670 | mode = CFStringCreateCopy(kCFAllocatorSystemDefault, (CFStringRef)mode); | |
2671 | __CFRunLoopLock(rl); | |
2672 | // ensure mode exists | |
2673 | CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)mode, true); | |
2674 | if (currentMode) __CFRunLoopModeUnlock(currentMode); | |
2675 | __CFRunLoopUnlock(rl); | |
2676 | } else if (CFArrayGetTypeID() == CFGetTypeID(mode)) { | |
2677 | CFIndex cnt = CFArrayGetCount((CFArrayRef)mode); | |
2678 | const void **values = (const void **)malloc(sizeof(const void *) * cnt); | |
2679 | CFArrayGetValues((CFArrayRef)mode, CFRangeMake(0, cnt), values); | |
2680 | mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks); | |
2681 | __CFRunLoopLock(rl); | |
2682 | // ensure modes exist | |
2683 | for (CFIndex idx = 0; idx < cnt; idx++) { | |
2684 | CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true); | |
2685 | if (currentMode) __CFRunLoopModeUnlock(currentMode); | |
2686 | } | |
2687 | __CFRunLoopUnlock(rl); | |
2688 | free(values); | |
2689 | } else if (CFSetGetTypeID() == CFGetTypeID(mode)) { | |
2690 | CFIndex cnt = CFSetGetCount((CFSetRef)mode); | |
2691 | const void **values = (const void **)malloc(sizeof(const void *) * cnt); | |
2692 | CFSetGetValues((CFSetRef)mode, values); | |
2693 | mode = CFSetCreate(kCFAllocatorSystemDefault, values, cnt, &kCFTypeSetCallBacks); | |
2694 | __CFRunLoopLock(rl); | |
2695 | // ensure modes exist | |
2696 | for (CFIndex idx = 0; idx < cnt; idx++) { | |
2697 | CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, (CFStringRef)values[idx], true); | |
2698 | if (currentMode) __CFRunLoopModeUnlock(currentMode); | |
2699 | } | |
2700 | __CFRunLoopUnlock(rl); | |
2701 | free(values); | |
2702 | } else { | |
2703 | mode = NULL; | |
2704 | } | |
2705 | #if DEPLOYMENT_TARGET_WINDOWS | |
2706 | // <rdar://problem/6496715> Block.h uses "typeof", which is not available when using Visual Studio on Windows | |
2707 | block = (void (^)(void))_Block_copy(block); | |
2708 | #else | |
2709 | block = Block_copy(block); | |
2710 | #endif | |
2711 | if (!mode || !block) { | |
2712 | if (mode) CFRelease(mode); | |
2713 | if (block) Block_release(block); | |
2714 | return; | |
2715 | } | |
2716 | __CFRunLoopLock(rl); | |
2717 | struct _block_item *new_item = (struct _block_item *)malloc(sizeof(struct _block_item)); | |
2718 | new_item->_next = NULL; | |
2719 | new_item->_mode = mode; | |
2720 | new_item->_block = block; | |
2721 | if (!rl->_blocks_tail) { | |
2722 | rl->_blocks_head = new_item; | |
2723 | } else { | |
2724 | rl->_blocks_tail->_next = new_item; | |
2725 | } | |
2726 | rl->_blocks_tail = new_item; | |
2727 | __CFRunLoopUnlock(rl); | |
2728 | } | |
2729 | ||
9ce05555 | 2730 | Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { |
bd5b749c | 2731 | CHECK_FOR_FORK(); |
9ce05555 A |
2732 | CFRunLoopModeRef rlm; |
2733 | Boolean hasValue = false; | |
2734 | __CFRunLoopLock(rl); | |
2735 | if (modeName == kCFRunLoopCommonModes) { | |
2736 | if (NULL != rl->_commonModeItems) { | |
2737 | hasValue = CFSetContainsValue(rl->_commonModeItems, rls); | |
2738 | } | |
2739 | __CFRunLoopUnlock(rl); | |
2740 | } else { | |
2741 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2742 | __CFRunLoopUnlock(rl); | |
2743 | if (NULL != rlm && NULL != rlm->_sources) { | |
2744 | hasValue = CFSetContainsValue(rlm->_sources, rls); | |
2745 | __CFRunLoopModeUnlock(rlm); | |
2746 | } else if (NULL != rlm) { | |
2747 | __CFRunLoopModeUnlock(rlm); | |
2748 | } | |
2749 | } | |
2750 | return hasValue; | |
2751 | } | |
2752 | ||
2753 | void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ | |
bd5b749c | 2754 | CHECK_FOR_FORK(); |
9ce05555 A |
2755 | CFRunLoopModeRef rlm; |
2756 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2757 | if (!__CFIsValid(rls)) return; | |
2758 | __CFRunLoopLock(rl); | |
2759 | if (modeName == kCFRunLoopCommonModes) { | |
2760 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2761 | if (NULL == rl->_commonModeItems) { | |
cf7d2af9 | 2762 | rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
9ce05555 A |
2763 | _CFSetSetCapacity(rl->_commonModeItems, 20); |
2764 | } | |
2765 | CFSetAddValue(rl->_commonModeItems, rls); | |
2766 | __CFRunLoopUnlock(rl); | |
2767 | if (NULL != set) { | |
2768 | CFTypeRef context[2] = {rl, rls}; | |
2769 | /* add new item to all common-modes */ | |
2770 | CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); | |
2771 | CFRelease(set); | |
2772 | } | |
2773 | } else { | |
2774 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2775 | __CFRunLoopUnlock(rl); | |
2776 | if (NULL != rlm && NULL == rlm->_sources) { | |
cf7d2af9 A |
2777 | rlm->_sources = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
2778 | rlm->_portToV1SourceMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); | |
9ce05555 A |
2779 | _CFSetSetCapacity(rlm->_sources, 10); |
2780 | } | |
2781 | if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) { | |
2782 | CFSetAddValue(rlm->_sources, rls); | |
cf7d2af9 A |
2783 | if (1 == rls->_context.version0.version) { |
2784 | __CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info); | |
2785 | CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls); | |
2786 | } | |
9ce05555 A |
2787 | __CFRunLoopModeUnlock(rlm); |
2788 | __CFRunLoopSourceSchedule(rls, rl, rlm); /* DOES CALLOUT */ | |
2789 | } else if (NULL != rlm) { | |
2790 | __CFRunLoopModeUnlock(rlm); | |
2791 | } | |
2792 | } | |
2793 | } | |
2794 | ||
2795 | void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ | |
bd5b749c | 2796 | CHECK_FOR_FORK(); |
9ce05555 A |
2797 | CFRunLoopModeRef rlm; |
2798 | __CFRunLoopLock(rl); | |
2799 | if (modeName == kCFRunLoopCommonModes) { | |
2800 | if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) { | |
2801 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2802 | CFSetRemoveValue(rl->_commonModeItems, rls); | |
2803 | __CFRunLoopUnlock(rl); | |
2804 | if (NULL != set) { | |
2805 | CFTypeRef context[2] = {rl, rls}; | |
2806 | /* remove new item from all common-modes */ | |
2807 | CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context); | |
2808 | CFRelease(set); | |
2809 | } | |
2810 | } else { | |
2811 | __CFRunLoopUnlock(rl); | |
2812 | } | |
2813 | } else { | |
2814 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2815 | __CFRunLoopUnlock(rl); | |
2816 | if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) { | |
2817 | CFRetain(rls); | |
cf7d2af9 A |
2818 | if (1 == rls->_context.version0.version) { |
2819 | __CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info); | |
2820 | CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port); | |
2821 | } | |
9ce05555 A |
2822 | CFSetRemoveValue(rlm->_sources, rls); |
2823 | __CFRunLoopModeUnlock(rlm); | |
2824 | __CFRunLoopSourceCancel(rls, rl, rlm); /* DOES CALLOUT */ | |
2825 | CFRelease(rls); | |
2826 | } else if (NULL != rlm) { | |
2827 | __CFRunLoopModeUnlock(rlm); | |
2828 | } | |
2829 | } | |
2830 | } | |
2831 | ||
5645d61f A |
2832 | static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) { |
2833 | CFStringRef modeName = (CFStringRef)value; | |
2834 | CFRunLoopRef rl = (CFRunLoopRef)ctx; | |
2835 | __CFRunLoopRemoveAllSources(rl, modeName); | |
2836 | } | |
2837 | ||
2838 | static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) { | |
2839 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value; | |
2840 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
2841 | CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]); | |
2842 | CFRunLoopRemoveSource(rl, rls, modeName); | |
2843 | } | |
2844 | ||
2845 | static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) { | |
2846 | CHECK_FOR_FORK(); | |
2847 | CFRunLoopModeRef rlm; | |
2848 | __CFRunLoopLock(rl); | |
2849 | if (modeName == kCFRunLoopCommonModes) { | |
2850 | if (NULL != rl->_commonModeItems) { | |
2851 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2852 | __CFRunLoopUnlock(rl); | |
2853 | if (NULL != set) { | |
2854 | CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl); | |
2855 | CFRelease(set); | |
2856 | } | |
2857 | } else { | |
2858 | __CFRunLoopUnlock(rl); | |
2859 | } | |
2860 | } else { | |
2861 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2862 | __CFRunLoopUnlock(rl); | |
2863 | if (NULL != rlm && NULL != rlm->_sources) { | |
2864 | CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources); | |
2865 | __CFRunLoopModeUnlock(rlm); | |
2866 | CFTypeRef context[2] = {rl, modeName}; | |
2867 | CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context); | |
cf7d2af9 A |
2868 | CFRelease(set); |
2869 | } else if (NULL != rlm) { | |
5645d61f A |
2870 | __CFRunLoopModeUnlock(rlm); |
2871 | } | |
2872 | } | |
2873 | } | |
2874 | ||
9ce05555 | 2875 | Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { |
bd5b749c | 2876 | CHECK_FOR_FORK(); |
9ce05555 A |
2877 | CFRunLoopModeRef rlm; |
2878 | Boolean hasValue = false; | |
2879 | __CFRunLoopLock(rl); | |
2880 | if (modeName == kCFRunLoopCommonModes) { | |
2881 | if (NULL != rl->_commonModeItems) { | |
2882 | hasValue = CFSetContainsValue(rl->_commonModeItems, rlo); | |
2883 | } | |
2884 | __CFRunLoopUnlock(rl); | |
2885 | } else { | |
2886 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2887 | __CFRunLoopUnlock(rl); | |
2888 | if (NULL != rlm && NULL != rlm->_observers) { | |
2889 | hasValue = CFSetContainsValue(rlm->_observers, rlo); | |
2890 | __CFRunLoopModeUnlock(rlm); | |
2891 | } else if (NULL != rlm) { | |
2892 | __CFRunLoopModeUnlock(rlm); | |
2893 | } | |
2894 | } | |
2895 | return hasValue; | |
2896 | } | |
2897 | ||
2898 | void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { | |
bd5b749c | 2899 | CHECK_FOR_FORK(); |
9ce05555 A |
2900 | CFRunLoopModeRef rlm; |
2901 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2902 | if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return; | |
2903 | __CFRunLoopLock(rl); | |
2904 | if (modeName == kCFRunLoopCommonModes) { | |
2905 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2906 | if (NULL == rl->_commonModeItems) { | |
cf7d2af9 | 2907 | rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
9ce05555 A |
2908 | } |
2909 | CFSetAddValue(rl->_commonModeItems, rlo); | |
2910 | __CFRunLoopUnlock(rl); | |
2911 | if (NULL != set) { | |
2912 | CFTypeRef context[2] = {rl, rlo}; | |
2913 | /* add new item to all common-modes */ | |
2914 | CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); | |
2915 | CFRelease(set); | |
2916 | } | |
2917 | } else { | |
2918 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2919 | __CFRunLoopUnlock(rl); | |
2920 | if (NULL != rlm && NULL == rlm->_observers) { | |
cf7d2af9 | 2921 | rlm->_observers = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
9ce05555 A |
2922 | } |
2923 | if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) { | |
2924 | CFSetAddValue(rlm->_observers, rlo); | |
cf7d2af9 | 2925 | rlm->_observerMask |= rlo->_activities; |
9ce05555 A |
2926 | __CFRunLoopModeUnlock(rlm); |
2927 | __CFRunLoopObserverSchedule(rlo, rl, rlm); | |
2928 | } else if (NULL != rlm) { | |
2929 | __CFRunLoopModeUnlock(rlm); | |
2930 | } | |
2931 | } | |
2932 | } | |
2933 | ||
2934 | void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { | |
bd5b749c | 2935 | CHECK_FOR_FORK(); |
9ce05555 A |
2936 | CFRunLoopModeRef rlm; |
2937 | __CFRunLoopLock(rl); | |
2938 | if (modeName == kCFRunLoopCommonModes) { | |
2939 | if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) { | |
2940 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2941 | CFSetRemoveValue(rl->_commonModeItems, rlo); | |
2942 | __CFRunLoopUnlock(rl); | |
2943 | if (NULL != set) { | |
2944 | CFTypeRef context[2] = {rl, rlo}; | |
2945 | /* remove new item from all common-modes */ | |
2946 | CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context); | |
2947 | CFRelease(set); | |
2948 | } | |
2949 | } else { | |
2950 | __CFRunLoopUnlock(rl); | |
2951 | } | |
2952 | } else { | |
2953 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2954 | __CFRunLoopUnlock(rl); | |
2955 | if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) { | |
2956 | CFRetain(rlo); | |
2957 | CFSetRemoveValue(rlm->_observers, rlo); | |
2958 | __CFRunLoopModeUnlock(rlm); | |
2959 | __CFRunLoopObserverCancel(rlo, rl, rlm); | |
2960 | CFRelease(rlo); | |
2961 | } else if (NULL != rlm) { | |
2962 | __CFRunLoopModeUnlock(rlm); | |
2963 | } | |
2964 | } | |
2965 | } | |
2966 | ||
2967 | Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { | |
bd5b749c | 2968 | CHECK_FOR_FORK(); |
9ce05555 A |
2969 | CFRunLoopModeRef rlm; |
2970 | Boolean hasValue = false; | |
2971 | __CFRunLoopLock(rl); | |
2972 | if (modeName == kCFRunLoopCommonModes) { | |
2973 | if (NULL != rl->_commonModeItems) { | |
2974 | hasValue = CFSetContainsValue(rl->_commonModeItems, rlt); | |
2975 | } | |
2976 | __CFRunLoopUnlock(rl); | |
2977 | } else { | |
2978 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2979 | __CFRunLoopUnlock(rl); | |
2980 | if (NULL != rlm && NULL != rlm->_timers) { | |
2981 | hasValue = CFSetContainsValue(rlm->_timers, rlt); | |
2982 | __CFRunLoopModeUnlock(rlm); | |
2983 | } else if (NULL != rlm) { | |
2984 | __CFRunLoopModeUnlock(rlm); | |
2985 | } | |
2986 | } | |
2987 | return hasValue; | |
2988 | } | |
2989 | ||
2990 | void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { | |
bd5b749c | 2991 | CHECK_FOR_FORK(); |
cf7d2af9 | 2992 | //CFLog(4, CFSTR("CFRunLoopAddTimer(%p, timer %p, %@)"), rl, rlt, modeName); |
9ce05555 A |
2993 | CFRunLoopModeRef rlm; |
2994 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2995 | if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return; | |
2996 | __CFRunLoopLock(rl); | |
2997 | if (modeName == kCFRunLoopCommonModes) { | |
2998 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2999 | if (NULL == rl->_commonModeItems) { | |
cf7d2af9 | 3000 | rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
9ce05555 A |
3001 | } |
3002 | CFSetAddValue(rl->_commonModeItems, rlt); | |
3003 | __CFRunLoopUnlock(rl); | |
3004 | if (NULL != set) { | |
3005 | CFTypeRef context[2] = {rl, rlt}; | |
3006 | /* add new item to all common-modes */ | |
3007 | CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); | |
3008 | CFRelease(set); | |
3009 | } | |
3010 | } else { | |
3011 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
3012 | __CFRunLoopUnlock(rl); | |
3013 | if (NULL != rlm && NULL == rlm->_timers) { | |
cf7d2af9 | 3014 | rlm->_timers = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
9ce05555 A |
3015 | } |
3016 | if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) { | |
3017 | CFSetAddValue(rlm->_timers, rlt); | |
3018 | __CFRunLoopModeUnlock(rlm); | |
3019 | __CFRunLoopTimerSchedule(rlt, rl, rlm); | |
3020 | } else if (NULL != rlm) { | |
3021 | __CFRunLoopModeUnlock(rlm); | |
3022 | } | |
3023 | } | |
3024 | } | |
3025 | ||
3026 | void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { | |
bd5b749c | 3027 | CHECK_FOR_FORK(); |
cf7d2af9 | 3028 | //CFLog(4, CFSTR("CFRunLoopRemoveTimer(%p, timer %p, %@)"), rl, rlt, modeName); |
9ce05555 A |
3029 | CFRunLoopModeRef rlm; |
3030 | __CFRunLoopLock(rl); | |
3031 | if (modeName == kCFRunLoopCommonModes) { | |
3032 | if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) { | |
3033 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
3034 | CFSetRemoveValue(rl->_commonModeItems, rlt); | |
3035 | __CFRunLoopUnlock(rl); | |
3036 | if (NULL != set) { | |
3037 | CFTypeRef context[2] = {rl, rlt}; | |
3038 | /* remove new item from all common-modes */ | |
3039 | CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context); | |
3040 | CFRelease(set); | |
3041 | } | |
3042 | } else { | |
3043 | __CFRunLoopUnlock(rl); | |
3044 | } | |
3045 | } else { | |
3046 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
3047 | __CFRunLoopUnlock(rl); | |
3048 | if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) { | |
3049 | CFRetain(rlt); | |
3050 | CFSetRemoveValue(rlm->_timers, rlt); | |
3051 | __CFRunLoopModeUnlock(rlm); | |
3052 | __CFRunLoopTimerCancel(rlt, rl, rlm); | |
3053 | CFRelease(rlt); | |
3054 | } else if (NULL != rlm) { | |
3055 | __CFRunLoopModeUnlock(rlm); | |
3056 | } | |
3057 | } | |
3058 | } | |
3059 | ||
3060 | ||
3061 | /* CFRunLoopSource */ | |
3062 | ||
3063 | static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CALLOUT */ | |
3064 | CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1; | |
3065 | CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2; | |
3066 | if (rls1 == rls2) return true; | |
cf7d2af9 | 3067 | if (__CFIsValid(rls1) != __CFIsValid(rls2)) return false; |
9ce05555 A |
3068 | if (rls1->_order != rls2->_order) return false; |
3069 | if (rls1->_context.version0.version != rls2->_context.version0.version) return false; | |
3070 | if (rls1->_context.version0.hash != rls2->_context.version0.hash) return false; | |
3071 | if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false; | |
3072 | if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false; | |
3073 | if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false; | |
3074 | if (rls1->_context.version0.equal) | |
3075 | return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info); | |
3076 | return (rls1->_context.version0.info == rls2->_context.version0.info); | |
3077 | } | |
3078 | ||
3079 | static CFHashCode __CFRunLoopSourceHash(CFTypeRef cf) { /* DOES CALLOUT */ | |
3080 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf; | |
3081 | if (rls->_context.version0.hash) | |
3082 | return rls->_context.version0.hash(rls->_context.version0.info); | |
3083 | return (CFHashCode)rls->_context.version0.info; | |
3084 | } | |
3085 | ||
3086 | static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ | |
3087 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf; | |
3088 | CFStringRef result; | |
3089 | CFStringRef contextDesc = NULL; | |
3090 | if (NULL != rls->_context.version0.copyDescription) { | |
3091 | contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info); | |
3092 | } | |
3093 | if (NULL == contextDesc) { | |
bd5b749c | 3094 | void *addr = rls->_context.version0.version == 0 ? (void *)rls->_context.version0.perform : (rls->_context.version0.version == 1 ? (void *)rls->_context.version1.perform : NULL); |
cf7d2af9 A |
3095 | #if DEPLOYMENT_TARGET_WINDOWS |
3096 | contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %p}"), rls->_context.version0.version, rls->_context.version0.info, addr); | |
3097 | #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
bd5b749c A |
3098 | Dl_info info; |
3099 | const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; | |
cf7d2af9 | 3100 | contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls->_context.version0.version, rls->_context.version0.info, name, addr); |
bd5b749c A |
3101 | #else |
3102 | #error Unknown or unspecified DEPLOYMENT_TARGET | |
3103 | #endif | |
9ce05555 | 3104 | } |
cf7d2af9 A |
3105 | #if DEPLOYMENT_TARGET_WINDOWS |
3106 | result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), "unknown", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); | |
3107 | #else | |
3108 | result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, 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); | |
3109 | #endif | |
9ce05555 A |
3110 | CFRelease(contextDesc); |
3111 | return result; | |
3112 | } | |
3113 | ||
3114 | static void __CFRunLoopSourceDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ | |
3115 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf; | |
3116 | CFRunLoopSourceInvalidate(rls); | |
3117 | if (rls->_context.version0.release) { | |
3118 | rls->_context.version0.release(rls->_context.version0.info); | |
3119 | } | |
cf7d2af9 | 3120 | memset((char *)cf + sizeof(CFRuntimeBase), 0, sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase)); |
9ce05555 A |
3121 | } |
3122 | ||
3123 | static const CFRuntimeClass __CFRunLoopSourceClass = { | |
d8925383 | 3124 | _kCFRuntimeScannedObject, |
9ce05555 A |
3125 | "CFRunLoopSource", |
3126 | NULL, // init | |
3127 | NULL, // copy | |
3128 | __CFRunLoopSourceDeallocate, | |
3129 | __CFRunLoopSourceEqual, | |
3130 | __CFRunLoopSourceHash, | |
3131 | NULL, // | |
3132 | __CFRunLoopSourceCopyDescription | |
3133 | }; | |
3134 | ||
3135 | __private_extern__ void __CFRunLoopSourceInitialize(void) { | |
3136 | __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass); | |
3137 | } | |
3138 | ||
3139 | CFTypeID CFRunLoopSourceGetTypeID(void) { | |
3140 | return __kCFRunLoopSourceTypeID; | |
3141 | } | |
3142 | ||
3143 | CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) { | |
bd5b749c | 3144 | CHECK_FOR_FORK(); |
9ce05555 A |
3145 | CFRunLoopSourceRef memory; |
3146 | uint32_t size; | |
3147 | if (NULL == context) HALT; | |
3148 | size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase); | |
3149 | memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL); | |
3150 | if (NULL == memory) { | |
3151 | return NULL; | |
3152 | } | |
3153 | __CFSetValid(memory); | |
3154 | __CFRunLoopSourceUnsetSignaled(memory); | |
bd5b749c | 3155 | CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); |
9ce05555 A |
3156 | memory->_bits = 0; |
3157 | memory->_order = order; | |
3158 | memory->_runLoops = NULL; | |
d8925383 A |
3159 | size = 0; |
3160 | switch (context->version) { | |
3161 | case 0: | |
3162 | size = sizeof(CFRunLoopSourceContext); | |
3163 | break; | |
3164 | case 1: | |
3165 | size = sizeof(CFRunLoopSourceContext1); | |
3166 | break; | |
cf7d2af9 | 3167 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 A |
3168 | case 2: |
3169 | size = sizeof(CFRunLoopSourceContext2); | |
3170 | break; | |
bd5b749c | 3171 | #endif |
d8925383 | 3172 | } |
cf7d2af9 | 3173 | objc_memmove_collectable(&memory->_context, context, size); |
9ce05555 A |
3174 | if (context->retain) { |
3175 | memory->_context.version0.info = (void *)context->retain(context->info); | |
3176 | } | |
3177 | return memory; | |
3178 | } | |
3179 | ||
3180 | CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) { | |
bd5b749c | 3181 | CHECK_FOR_FORK(); |
9ce05555 A |
3182 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
3183 | return rls->_order; | |
3184 | } | |
3185 | ||
cf7d2af9 A |
3186 | static void __CFRunLoopSourceWakeUpLoop(const void *value, void *context) { |
3187 | CFRunLoopWakeUp((CFRunLoopRef)value); | |
3188 | } | |
3189 | ||
9ce05555 A |
3190 | static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) { |
3191 | CFRunLoopRef rl = (CFRunLoopRef)value; | |
cf7d2af9 | 3192 | CFTypeRef *params = (CFTypeRef *)context; |
9ce05555 A |
3193 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0]; |
3194 | CFArrayRef array; | |
3195 | CFIndex idx; | |
3196 | if (rl == params[1]) return; | |
3197 | array = CFRunLoopCopyAllModes(rl); | |
3198 | for (idx = CFArrayGetCount(array); idx--;) { | |
cf7d2af9 | 3199 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx); |
9ce05555 A |
3200 | CFRunLoopRemoveSource(rl, rls, modeName); |
3201 | } | |
3202 | CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes); | |
3203 | CFRelease(array); | |
3204 | params[1] = rl; | |
3205 | } | |
3206 | ||
3207 | void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) { | |
bd5b749c | 3208 | CHECK_FOR_FORK(); |
9ce05555 A |
3209 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
3210 | CFRetain(rls); | |
3211 | __CFRunLoopSourceLock(rls); | |
3212 | if (__CFIsValid(rls)) { | |
3213 | __CFUnsetValid(rls); | |
bd5b749c | 3214 | __CFRunLoopSourceUnsetSignaled(rls); |
9ce05555 A |
3215 | if (NULL != rls->_runLoops) { |
3216 | CFTypeRef params[2] = {rls, NULL}; | |
cf7d2af9 | 3217 | CFBagRef bag = rls->_runLoops; |
9ce05555 A |
3218 | rls->_runLoops = NULL; |
3219 | __CFRunLoopSourceUnlock(rls); | |
3220 | CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params); | |
3221 | CFRelease(bag); | |
3222 | } else { | |
3223 | __CFRunLoopSourceUnlock(rls); | |
3224 | } | |
3225 | /* for hashing- and equality-use purposes, can't actually release the context here */ | |
3226 | } else { | |
3227 | __CFRunLoopSourceUnlock(rls); | |
3228 | } | |
3229 | CFRelease(rls); | |
3230 | } | |
3231 | ||
3232 | Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) { | |
bd5b749c | 3233 | CHECK_FOR_FORK(); |
9ce05555 A |
3234 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
3235 | return __CFIsValid(rls); | |
3236 | } | |
3237 | ||
3238 | void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) { | |
bd5b749c | 3239 | CHECK_FOR_FORK(); |
9ce05555 | 3240 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
bd5b749c | 3241 | CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__); |
d8925383 A |
3242 | CFIndex size = 0; |
3243 | switch (context->version) { | |
3244 | case 0: | |
3245 | size = sizeof(CFRunLoopSourceContext); | |
3246 | break; | |
3247 | case 1: | |
3248 | size = sizeof(CFRunLoopSourceContext1); | |
3249 | break; | |
cf7d2af9 | 3250 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
d8925383 A |
3251 | case 2: |
3252 | size = sizeof(CFRunLoopSourceContext2); | |
3253 | break; | |
bd5b749c | 3254 | #endif |
d8925383 A |
3255 | } |
3256 | memmove(context, &rls->_context, size); | |
9ce05555 A |
3257 | } |
3258 | ||
3259 | void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) { | |
bd5b749c | 3260 | CHECK_FOR_FORK(); |
9ce05555 A |
3261 | __CFRunLoopSourceLock(rls); |
3262 | if (__CFIsValid(rls)) { | |
3263 | __CFRunLoopSourceSetSignaled(rls); | |
3264 | } | |
3265 | __CFRunLoopSourceUnlock(rls); | |
3266 | } | |
3267 | ||
bd5b749c A |
3268 | Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) { |
3269 | CHECK_FOR_FORK(); | |
3270 | __CFRunLoopSourceLock(rls); | |
3271 | Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false; | |
3272 | __CFRunLoopSourceUnlock(rls); | |
3273 | return ret; | |
3274 | } | |
9ce05555 | 3275 | |
cf7d2af9 A |
3276 | __private_extern__ void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls) { |
3277 | __CFRunLoopSourceLock(rls); | |
3278 | if (__CFIsValid(rls) && NULL != rls->_runLoops) { | |
3279 | CFBagApplyFunction(rls->_runLoops, __CFRunLoopSourceWakeUpLoop, NULL); | |
3280 | } | |
3281 | __CFRunLoopSourceUnlock(rls); | |
3282 | } | |
3283 | ||
9ce05555 A |
3284 | /* CFRunLoopObserver */ |
3285 | ||
3286 | static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ | |
3287 | CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf; | |
3288 | CFStringRef result; | |
3289 | CFStringRef contextDesc = NULL; | |
9ce05555 A |
3290 | if (NULL != rlo->_context.copyDescription) { |
3291 | contextDesc = rlo->_context.copyDescription(rlo->_context.info); | |
3292 | } | |
3293 | if (!contextDesc) { | |
cf7d2af9 | 3294 | contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info); |
9ce05555 | 3295 | } |
cf7d2af9 A |
3296 | #if DEPLOYMENT_TARGET_WINDOWS |
3297 | result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), "unknown", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc); | |
3298 | #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
bd5b749c A |
3299 | void *addr = rlo->_callout; |
3300 | Dl_info info; | |
3301 | const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; | |
cf7d2af9 | 3302 | result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, 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); |
bd5b749c A |
3303 | #else |
3304 | #error Unknown or unspecified DEPLOYMENT_TARGET | |
3305 | #endif | |
9ce05555 A |
3306 | CFRelease(contextDesc); |
3307 | return result; | |
3308 | } | |
3309 | ||
3310 | static void __CFRunLoopObserverDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ | |
3311 | CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf; | |
3312 | CFRunLoopObserverInvalidate(rlo); | |
3313 | } | |
3314 | ||
3315 | static const CFRuntimeClass __CFRunLoopObserverClass = { | |
3316 | 0, | |
3317 | "CFRunLoopObserver", | |
3318 | NULL, // init | |
3319 | NULL, // copy | |
3320 | __CFRunLoopObserverDeallocate, | |
3321 | NULL, | |
3322 | NULL, | |
3323 | NULL, // | |
3324 | __CFRunLoopObserverCopyDescription | |
3325 | }; | |
3326 | ||
3327 | __private_extern__ void __CFRunLoopObserverInitialize(void) { | |
3328 | __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass); | |
3329 | } | |
3330 | ||
3331 | CFTypeID CFRunLoopObserverGetTypeID(void) { | |
3332 | return __kCFRunLoopObserverTypeID; | |
3333 | } | |
3334 | ||
3335 | CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) { | |
bd5b749c | 3336 | CHECK_FOR_FORK(); |
9ce05555 A |
3337 | CFRunLoopObserverRef memory; |
3338 | UInt32 size; | |
3339 | size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase); | |
3340 | memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL); | |
3341 | if (NULL == memory) { | |
3342 | return NULL; | |
3343 | } | |
3344 | __CFSetValid(memory); | |
3345 | __CFRunLoopObserverUnsetFiring(memory); | |
3346 | if (repeats) { | |
3347 | __CFRunLoopObserverSetRepeats(memory); | |
3348 | } else { | |
3349 | __CFRunLoopObserverUnsetRepeats(memory); | |
3350 | } | |
bd5b749c | 3351 | CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); |
9ce05555 A |
3352 | memory->_runLoop = NULL; |
3353 | memory->_rlCount = 0; | |
3354 | memory->_activities = activities; | |
3355 | memory->_order = order; | |
3356 | memory->_callout = callout; | |
3357 | if (context) { | |
3358 | if (context->retain) { | |
3359 | memory->_context.info = (void *)context->retain(context->info); | |
3360 | } else { | |
3361 | memory->_context.info = context->info; | |
3362 | } | |
3363 | memory->_context.retain = context->retain; | |
3364 | memory->_context.release = context->release; | |
3365 | memory->_context.copyDescription = context->copyDescription; | |
3366 | } else { | |
3367 | memory->_context.info = 0; | |
3368 | memory->_context.retain = 0; | |
3369 | memory->_context.release = 0; | |
3370 | memory->_context.copyDescription = 0; | |
3371 | } | |
3372 | return memory; | |
3373 | } | |
3374 | ||
3375 | CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) { | |
bd5b749c | 3376 | CHECK_FOR_FORK(); |
9ce05555 A |
3377 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
3378 | return rlo->_activities; | |
3379 | } | |
3380 | ||
3381 | CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) { | |
bd5b749c | 3382 | CHECK_FOR_FORK(); |
9ce05555 A |
3383 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
3384 | return rlo->_order; | |
3385 | } | |
3386 | ||
3387 | Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) { | |
bd5b749c | 3388 | CHECK_FOR_FORK(); |
9ce05555 A |
3389 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
3390 | return __CFRunLoopObserverRepeats(rlo); | |
3391 | } | |
3392 | ||
3393 | void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */ | |
bd5b749c | 3394 | CHECK_FOR_FORK(); |
9ce05555 A |
3395 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
3396 | CFRetain(rlo); | |
3397 | __CFRunLoopObserverLock(rlo); | |
3398 | if (__CFIsValid(rlo)) { | |
3399 | CFRunLoopRef rl = rlo->_runLoop; | |
3400 | __CFUnsetValid(rlo); | |
3401 | __CFRunLoopObserverUnlock(rlo); | |
3402 | if (NULL != rl) { | |
3403 | CFArrayRef array; | |
3404 | CFIndex idx; | |
3405 | array = CFRunLoopCopyAllModes(rl); | |
3406 | for (idx = CFArrayGetCount(array); idx--;) { | |
cf7d2af9 | 3407 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx); |
9ce05555 A |
3408 | CFRunLoopRemoveObserver(rl, rlo, modeName); |
3409 | } | |
3410 | CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes); | |
3411 | CFRelease(array); | |
3412 | } | |
3413 | if (rlo->_context.release) | |
3414 | rlo->_context.release(rlo->_context.info); /* CALLOUT */ | |
3415 | rlo->_context.info = NULL; | |
3416 | } else { | |
3417 | __CFRunLoopObserverUnlock(rlo); | |
3418 | } | |
3419 | CFRelease(rlo); | |
3420 | } | |
3421 | ||
3422 | Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) { | |
bd5b749c | 3423 | CHECK_FOR_FORK(); |
9ce05555 A |
3424 | return __CFIsValid(rlo); |
3425 | } | |
3426 | ||
3427 | void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) { | |
bd5b749c | 3428 | CHECK_FOR_FORK(); |
9ce05555 A |
3429 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
3430 | CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); | |
3431 | *context = rlo->_context; | |
3432 | } | |
3433 | ||
3434 | /* CFRunLoopTimer */ | |
3435 | ||
3436 | static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ | |
3437 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf; | |
3438 | CFStringRef result; | |
cf7d2af9 A |
3439 | int64_t now2 = (int64_t)mach_absolute_time(); |
3440 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
9ce05555 | 3441 | __CFRunLoopTimerFireTSRLock(); |
cf7d2af9 | 3442 | int64_t fireTime = rlt->_fireTSR; |
9ce05555 | 3443 | __CFRunLoopTimerFireTSRUnlock(); |
cf7d2af9 A |
3444 | CFAbsoluteTime fireDate = now1 + __CFTSRToTimeInterval(fireTime - now2); |
3445 | CFStringRef contextDesc = NULL; | |
9ce05555 A |
3446 | if (NULL != rlt->_context.copyDescription) { |
3447 | contextDesc = rlt->_context.copyDescription(rlt->_context.info); | |
3448 | } | |
3449 | if (NULL == contextDesc) { | |
cf7d2af9 | 3450 | contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info); |
9ce05555 | 3451 | } |
cf7d2af9 A |
3452 | #if DEPLOYMENT_TARGET_WINDOWS |
3453 | result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlt), "unknown", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, rlt->_callout, contextDesc); | |
3454 | #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
bd5b749c A |
3455 | void *addr = rlt->_callout; |
3456 | Dl_info info; | |
3457 | const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; | |
cf7d2af9 | 3458 | result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, 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", rlt->_interval, fireDate, rlt->_order, name, addr, contextDesc); |
bd5b749c A |
3459 | #else |
3460 | #error Unknown or unspecified DEPLOYMENT_TARGET | |
3461 | #endif | |
9ce05555 A |
3462 | CFRelease(contextDesc); |
3463 | return result; | |
3464 | } | |
3465 | ||
3466 | static void __CFRunLoopTimerDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ | |
cf7d2af9 | 3467 | //CFLog(6, CFSTR("__CFRunLoopTimerDeallocate(%p)"), cf); |
9ce05555 | 3468 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf; |
cf7d2af9 | 3469 | __CFRunLoopTimerSetDeallocating(rlt); |
9ce05555 | 3470 | CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ |
cf7d2af9 A |
3471 | CFRelease(rlt->_rlModes); |
3472 | rlt->_rlModes = NULL; | |
9ce05555 A |
3473 | } |
3474 | ||
3475 | static const CFRuntimeClass __CFRunLoopTimerClass = { | |
3476 | 0, | |
3477 | "CFRunLoopTimer", | |
3478 | NULL, // init | |
3479 | NULL, // copy | |
3480 | __CFRunLoopTimerDeallocate, | |
3481 | NULL, // equal | |
3482 | NULL, | |
3483 | NULL, // | |
3484 | __CFRunLoopTimerCopyDescription | |
3485 | }; | |
3486 | ||
3487 | __private_extern__ void __CFRunLoopTimerInitialize(void) { | |
3488 | __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass); | |
3489 | } | |
3490 | ||
3491 | CFTypeID CFRunLoopTimerGetTypeID(void) { | |
3492 | return __kCFRunLoopTimerTypeID; | |
3493 | } | |
3494 | ||
3495 | CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) { | |
bd5b749c | 3496 | CHECK_FOR_FORK(); |
9ce05555 A |
3497 | CFRunLoopTimerRef memory; |
3498 | UInt32 size; | |
3499 | size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase); | |
3500 | memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL); | |
3501 | if (NULL == memory) { | |
3502 | return NULL; | |
3503 | } | |
3504 | __CFSetValid(memory); | |
3505 | __CFRunLoopTimerUnsetFiring(memory); | |
d8925383 | 3506 | __CFRunLoopTimerUnsetDidFire(memory); |
bd5b749c | 3507 | CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); |
9ce05555 | 3508 | memory->_runLoop = NULL; |
cf7d2af9 A |
3509 | memory->_rlModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
3510 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED | |
9ce05555 A |
3511 | memory->_port = MACH_PORT_NULL; |
3512 | #endif | |
3513 | memory->_order = order; | |
cf7d2af9 A |
3514 | if (interval < 0.0) interval = 0.0; |
3515 | memory->_interval = interval; | |
3516 | if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT; | |
3517 | if (TIMER_INTERVAL_LIMIT < interval) interval = TIMER_INTERVAL_LIMIT; | |
3518 | memory->_nextFireDate = fireDate; | |
d8925383 A |
3519 | int64_t now2 = (int64_t)mach_absolute_time(); |
3520 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
3521 | if (fireDate < now1) { | |
3522 | memory->_fireTSR = now2; | |
3523 | } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { | |
9ce05555 A |
3524 | memory->_fireTSR = LLONG_MAX; |
3525 | } else { | |
d8925383 | 3526 | memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); |
9ce05555 A |
3527 | } |
3528 | if (interval <= 0.0) { | |
3529 | memory->_intervalTSR = 0; | |
3530 | } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) { | |
3531 | memory->_intervalTSR = LLONG_MAX; | |
3532 | } else { | |
3533 | memory->_intervalTSR = __CFTimeIntervalToTSR(interval); | |
3534 | } | |
3535 | memory->_callout = callout; | |
3536 | if (NULL != context) { | |
3537 | if (context->retain) { | |
3538 | memory->_context.info = (void *)context->retain(context->info); | |
3539 | } else { | |
3540 | memory->_context.info = context->info; | |
3541 | } | |
3542 | memory->_context.retain = context->retain; | |
3543 | memory->_context.release = context->release; | |
3544 | memory->_context.copyDescription = context->copyDescription; | |
3545 | } else { | |
3546 | memory->_context.info = 0; | |
3547 | memory->_context.retain = 0; | |
3548 | memory->_context.release = 0; | |
3549 | memory->_context.copyDescription = 0; | |
3550 | } | |
cf7d2af9 | 3551 | //CFLog(4, CFSTR("CFRunLoopTimerCreate(%p, %f, %f, 0x%lx, %ld, %p, %p) => %p"), allocator, fireDate, interval, flags, order, callout, context, memory); |
9ce05555 A |
3552 | return memory; |
3553 | } | |
3554 | ||
3555 | CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) { | |
bd5b749c | 3556 | CHECK_FOR_FORK(); |
9ce05555 A |
3557 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime"); |
3558 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
cf7d2af9 | 3559 | int64_t fireTime, result = 0; |
9ce05555 A |
3560 | __CFRunLoopTimerFireTSRLock(); |
3561 | fireTime = rlt->_fireTSR; | |
3562 | __CFRunLoopTimerFireTSRUnlock(); | |
3563 | __CFRunLoopTimerLock(rlt); | |
3564 | if (__CFIsValid(rlt)) { | |
3565 | result = fireTime; | |
3566 | } | |
3567 | __CFRunLoopTimerUnlock(rlt); | |
d8925383 A |
3568 | int64_t now2 = (int64_t)mach_absolute_time(); |
3569 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
3570 | return (0 == result) ? 0.0 : now1 + __CFTSRToTimeInterval(result - now2); | |
9ce05555 A |
3571 | } |
3572 | ||
3573 | void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) { | |
cf7d2af9 | 3574 | //CFLog(6, CFSTR("CFRunLoopTimerSetNextFireDate(rlt %p, fireDate %f)"), rlt, fireDate); |
bd5b749c | 3575 | CHECK_FOR_FORK(); |
cf7d2af9 A |
3576 | //CFLog(4, CFSTR("CFRunLoopTimerSetNextFireDate(%p, %f) [limit: %f]"), rlt, fireDate, TIMER_DATE_LIMIT); |
3577 | if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT; | |
3578 | rlt->_nextFireDate = fireDate; | |
d8925383 A |
3579 | int64_t now2 = (int64_t)mach_absolute_time(); |
3580 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
cf7d2af9 | 3581 | __CFRunLoopTimerFireTSRLock(); |
d8925383 A |
3582 | if (fireDate < now1) { |
3583 | rlt->_fireTSR = now2; | |
3584 | } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { | |
9ce05555 A |
3585 | rlt->_fireTSR = LLONG_MAX; |
3586 | } else { | |
d8925383 A |
3587 | rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); |
3588 | } | |
9ce05555 | 3589 | if (rlt->_runLoop != NULL) { |
cf7d2af9 | 3590 | __CFRunLoopTimerRescheduleWithAllModes(rlt); |
9ce05555 | 3591 | } |
d8925383 | 3592 | __CFRunLoopTimerFireTSRUnlock(); |
9ce05555 A |
3593 | } |
3594 | ||
3595 | CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) { | |
bd5b749c | 3596 | CHECK_FOR_FORK(); |
9ce05555 A |
3597 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval"); |
3598 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
cf7d2af9 | 3599 | return rlt->_interval; |
9ce05555 A |
3600 | } |
3601 | ||
3602 | Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) { | |
bd5b749c | 3603 | CHECK_FOR_FORK(); |
9ce05555 | 3604 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); |
cf7d2af9 | 3605 | return (0.0 < rlt->_interval); |
9ce05555 A |
3606 | } |
3607 | ||
3608 | CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) { | |
bd5b749c | 3609 | CHECK_FOR_FORK(); |
9ce05555 A |
3610 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order"); |
3611 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
3612 | return rlt->_order; | |
3613 | } | |
3614 | ||
3615 | void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ | |
bd5b749c | 3616 | CHECK_FOR_FORK(); |
cf7d2af9 | 3617 | //CFLog(4, CFSTR("CFRunLoopTimerInvalidate(%p)"), rlt); |
9ce05555 A |
3618 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate"); |
3619 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
cf7d2af9 A |
3620 | if (!__CFRunLoopTimerIsDeallocating(rlt)) { |
3621 | CFRetain(rlt); | |
3622 | } | |
9ce05555 A |
3623 | __CFRunLoopTimerLock(rlt); |
3624 | if (__CFIsValid(rlt)) { | |
3625 | CFRunLoopRef rl = rlt->_runLoop; | |
3626 | void *info = rlt->_context.info; | |
3627 | __CFUnsetValid(rlt); | |
cf7d2af9 | 3628 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED |
9ce05555 A |
3629 | __CFRunLoopTimerPortMapLock(); |
3630 | if (NULL != __CFRLTPortMap) { | |
bd5b749c | 3631 | CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); |
9ce05555 A |
3632 | } |
3633 | __CFRunLoopTimerPortMapUnlock(); | |
3634 | mk_timer_destroy(rlt->_port); | |
3635 | rlt->_port = MACH_PORT_NULL; | |
3636 | #endif | |
3637 | rlt->_context.info = NULL; | |
3638 | __CFRunLoopTimerUnlock(rlt); | |
3639 | if (NULL != rl) { | |
cf7d2af9 A |
3640 | CFIndex cnt = CFSetGetCount(rlt->_rlModes); |
3641 | STACK_BUFFER_DECL(CFStringRef, modes, cnt); | |
3642 | CFSetGetValues(rlt->_rlModes, (const void **)modes); | |
3643 | for (CFIndex idx = 0; idx < cnt; idx++) { | |
3644 | CFRunLoopRemoveTimer(rl, rlt, modes[idx]); | |
9ce05555 A |
3645 | } |
3646 | CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes); | |
9ce05555 A |
3647 | } |
3648 | if (NULL != rlt->_context.release) { | |
3649 | rlt->_context.release(info); /* CALLOUT */ | |
3650 | } | |
3651 | } else { | |
3652 | __CFRunLoopTimerUnlock(rlt); | |
3653 | } | |
cf7d2af9 A |
3654 | if (!__CFRunLoopTimerIsDeallocating(rlt)) { |
3655 | CFRelease(rlt); | |
3656 | } | |
9ce05555 A |
3657 | } |
3658 | ||
3659 | Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) { | |
bd5b749c | 3660 | CHECK_FOR_FORK(); |
9ce05555 A |
3661 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid"); |
3662 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
3663 | return __CFIsValid(rlt); | |
3664 | } | |
3665 | ||
3666 | void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) { | |
bd5b749c | 3667 | CHECK_FOR_FORK(); |
9ce05555 A |
3668 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); |
3669 | CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); | |
3670 | *context = rlt->_context; | |
3671 | } | |
3672 | ||
9ce05555 | 3673 | |
cf7d2af9 A |
3674 | #if DEPLOYMENT_TARGET_WINDOWS |
3675 | ||
3676 | //#if MARRY_MESSAGE_QUEUE | |
3677 | ||
3678 | // Do we need to make sure it's not CFRunLoopRun processing the message queue? | |
3679 | CF_EXPORT LRESULT CALLBACK pumpRunLoopFromMessageQueue(int nCode, WPARAM wParam, LPARAM lParam) { | |
3680 | //if nCode < 0, we're supposed to blindly call CallNexthookEx instead of processing the message ourselves | |
3681 | if (nCode >= 0) { | |
3682 | MSG *msgPtr = (MSG *)lParam; | |
3683 | CFRunLoopRef rl = CFRunLoopGetCurrent(); | |
3684 | CFStringRef currMode; | |
3685 | ||
3686 | if (msgPtr->message == __kCFRunLoopV1SourceReadyMessage) { | |
3687 | CFRunLoopModeRef rlm; | |
3688 | CFRunLoopSourceRef rls; | |
3689 | __CFRunLoopLock(rl); | |
3690 | rlm = rl->_currentMode; | |
3691 | if (!rlm) { | |
3692 | rlm = __CFRunLoopFindMode(rl, kCFRunLoopDefaultMode, true); // returns the mode locked | |
3693 | } else { | |
3694 | __CFRunLoopModeLock(rlm); | |
3695 | } | |
3696 | rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, (__CFPort)msgPtr->lParam); | |
3697 | __CFRunLoopUnlock(rl); | |
3698 | if (rls) { | |
3699 | // Must still hold the mode lock when calling DoSource1 | |
3700 | __CFRunLoopDoSource1(rl, rlm, rls); | |
3701 | } | |
3702 | __CFRunLoopModeUnlock(rlm); | |
3703 | } | |
3704 | if (msgPtr->message == __kCFRunLoopV1SourceReadyMessage || msgPtr->message == __kCFRunLoopWakeUpMessage) { | |
3705 | // Must always pump the RL regardless of whether we received the wakeup message because whomever processed the v1 source may be assuming that the RL is running and will see further callouts. | |
3706 | currMode = CFRunLoopCopyCurrentMode(rl); | |
3707 | if (!currMode) { | |
3708 | currMode = kCFRunLoopDefaultMode; | |
3709 | CFRetain(currMode); | |
3710 | } | |
3711 | while (CFRunLoopRunInMode(currMode, 0.0, true) == kCFRunLoopRunHandledSource) { | |
3712 | ; | |
3713 | } | |
3714 | CFRelease(currMode); | |
3715 | } | |
3716 | } | |
3717 | return CallNextHookEx(__CFGetThreadSpecificData_inline()->_messageHook, nCode, wParam, lParam); | |
3718 | } | |
3719 | ||
3720 | void __CFRunLoopMsgWaitThread(void *theRL) { | |
3721 | CFRunLoopRef rl = (CFRunLoopRef)theRL; | |
3722 | Boolean allDone = FALSE; | |
3723 | ||
3724 | while (!allDone) { | |
3725 | ||
3726 | CFRunLoopModeRef rlm; | |
3727 | __CFPortSet waitSet; | |
3728 | DWORD waitResult = WAIT_TIMEOUT; | |
3729 | DWORD qMask; | |
3730 | HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; | |
3731 | HANDLE *handles, *currHandle; | |
3732 | uint32_t handleCount, handleIndex; | |
3733 | Boolean freeHandles; | |
3734 | ||
3735 | __CFRunLoopLock(rl); | |
3736 | rlm = rl->_currentMode; | |
3737 | if (!rlm) { | |
3738 | rlm = __CFRunLoopFindMode(rl, kCFRunLoopDefaultMode, true); // Returns a locked mode | |
3739 | } else { | |
3740 | __CFRunLoopModeLock(rlm); | |
3741 | } | |
3742 | CFRetain(rlm); | |
3743 | waitSet = rlm->_portSet; | |
3744 | ||
3745 | // copy out the handles to be safe from other threads at work | |
3746 | handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount); | |
3747 | freeHandles = (handles != handleBuf); | |
3748 | // Replace the wakeup port with our own update port | |
3749 | for (handleIndex = 0, currHandle = handles; handleIndex < handleCount; handleIndex ++, currHandle++) { | |
3750 | if (*currHandle == rl->_wakeUpPort) { | |
3751 | *currHandle = rl->_msgUpdatePort; | |
3752 | break; | |
3753 | } | |
3754 | } | |
3755 | ||
3756 | // Not sure what to do with this.... | |
3757 | // handles[handleCount] = rl->_msgShutdownPort; | |
3758 | // handleCount ++; | |
3759 | ||
3760 | qMask = rlm->_msgQMask; | |
3761 | ||
3762 | while (1) { | |
3763 | Boolean shuttingDown = false; | |
3764 | __CFRunLoopModeUnlock(rlm); | |
3765 | __CFRunLoopUnlock(rl); | |
3766 | ||
3767 | // What do we do if there are more than MAXIMUM_WAIT_OBJECTS | |
3768 | //waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE, qMask); | |
3769 | waitResult = WaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE); | |
3770 | // Need to poll here to see if we've been told to die; if so, we must not touch rl. I think. | |
3771 | __CFRunLoopLock(rl); | |
3772 | __CFRunLoopModeLock(rlm); | |
3773 | ResetEvent(rl->_msgUpdatePort); | |
3774 | ||
3775 | __CFPort livePort = CFPORT_NULL; | |
3776 | if (waitResult == WAIT_FAILED) { | |
3777 | DWORD error = GetLastError(); | |
3778 | if (error == ERROR_INVALID_HANDLE) { | |
3779 | // A handle got freed out from underneath us. Force an update of our handle watch list. | |
3780 | livePort = rl->_msgUpdatePort; | |
3781 | } else { | |
3782 | CFAssert2(true, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects\n", __PRETTY_FUNCTION__,error); | |
3783 | } | |
3784 | } | |
3785 | if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) { | |
3786 | // a handle was signaled | |
3787 | livePort = handles[waitResult-WAIT_OBJECT_0]; | |
3788 | } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) { | |
3789 | // an "abandoned mutex object" | |
3790 | livePort = handles[waitResult-WAIT_ABANDONED_0]; | |
3791 | } | |
3792 | if (freeHandles){ | |
3793 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles); | |
3794 | } | |
3795 | ||
3796 | if (livePort == rl->_msgUpdatePort) { | |
3797 | break; | |
3798 | // } else if (livePort == rl->_msgShutdownPort) { | |
3799 | // allDone = true; | |
3800 | // break; | |
3801 | } else { | |
3802 | // OutputDebugStr(L"Posting v1 source ready msg\n"); | |
3803 | ResetEvent(livePort); | |
3804 | PostThreadMessageW(rl->_threadID, __kCFRunLoopV1SourceReadyMessage, NULL, (LPARAM)livePort); | |
3805 | } | |
3806 | } | |
3807 | __CFRunLoopModeUnlock(rlm); | |
3808 | CFRelease(rlm); | |
3809 | __CFRunLoopUnlock(rl); | |
3810 | } | |
3811 | } | |
3812 | ||
3813 | // #endif | |
3814 | ||
3815 | // Called while holding the run loop lock | |
3816 | ||
3817 | //#if MARRY_MESSAGE_QUEUE | |
3818 | ||
3819 | void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl) { | |
3820 | if (rl->_msgUpdatePort == CFPORT_NULL) { | |
3821 | rl->_msgUpdatePort = __CFPortAllocate(); | |
3822 | if (CFPORT_NULL == rl->_msgUpdatePort) HALT; | |
3823 | ||
3824 | // Kick off the MsgWaitThread | |
3825 | _beginthread(__CFRunLoopMsgWaitThread, 0, rl); | |
3826 | } | |
3827 | SetEvent(rl->_msgUpdatePort); | |
3828 | } | |
3829 | //#else | |
3830 | CF_INLINE void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl) {} | |
3831 | //#endif | |
3832 | ||
3833 | #endif |