]>
Commit | Line | Data |
---|---|---|
9ce05555 | 1 | /* |
bd5b749c | 2 | * Copyright (c) 2008 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 | */ | |
23 | /* CFRunLoop.c | |
24 | Copyright 1998-2002, Apple, Inc. All rights reserved. | |
25 | Responsibility: Christopher Kane | |
26 | */ | |
27 | ||
bd5b749c A |
28 | #if (DEPLOYMENT_TARGET_MACOSX) || defined(__WIN32__) |
29 | ||
9ce05555 A |
30 | #include <CoreFoundation/CFRunLoop.h> |
31 | #include <CoreFoundation/CFSet.h> | |
32 | #include <CoreFoundation/CFBag.h> | |
33 | #include "CFInternal.h" | |
34 | #include <math.h> | |
d8925383 | 35 | #include <stdio.h> |
9ce05555 | 36 | #include <limits.h> |
bd5b749c | 37 | #if DEPLOYMENT_TARGET_MACOSX |
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> | |
9ce05555 | 43 | #else |
d8925383 A |
44 | #if !defined(__MINGW32__) && !defined(__CYGWIN__) |
45 | // With the MS headers, turning off Standard-C gets you macros for stat vs _stat. | |
46 | // Strictly speaking, this is supposed to control traditional vs ANSI C features. | |
47 | #undef __STDC__ | |
48 | #endif | |
9ce05555 | 49 | #include <windows.h> |
bd5b749c | 50 | #include <pthread.h> |
d8925383 A |
51 | #include <process.h> |
52 | #if !defined(__MINGW32__) && !defined(__CYGWIN__) | |
53 | #define __STDC__ | |
54 | #endif | |
9ce05555 A |
55 | #endif |
56 | ||
bd5b749c A |
57 | static int _LogCFRunLoop = 0; |
58 | ||
59 | #if 0 || 0 | |
60 | static pthread_t kNilPthreadT = { nil, nil }; | |
61 | #define pthreadPointer(a) a.p | |
62 | #define lockCount(a) a.LockCount | |
63 | #else | |
64 | static pthread_t kNilPthreadT = (pthread_t)0; | |
65 | #define pthreadPointer(a) a | |
66 | #define lockCount(a) a | |
67 | #endif | |
68 | ||
69 | ||
70 | #if DEPLOYMENT_TARGET_MACOSX | |
71 | #include <sys/types.h> | |
72 | #include <sys/event.h> | |
73 | ||
74 | typedef struct { | |
75 | CFIndex version; | |
76 | void * info; | |
77 | const void *(*retain)(const void *info); | |
78 | void (*release)(const void *info); | |
79 | CFStringRef (*copyDescription)(const void *info); | |
80 | Boolean (*equal)(const void *info1, const void *info2); | |
81 | CFHashCode (*hash)(const void *info); | |
82 | void (*perform)(const struct kevent *kev, void *info); | |
83 | struct kevent event; | |
84 | } CFRunLoopSourceContext2; | |
85 | ||
86 | // The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR. | |
87 | // Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop. | |
88 | // There is no way to EV_ENABLE or EV_DISABLE a kevent. | |
89 | // The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet. | |
90 | // The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet. | |
91 | // There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos). | |
92 | #endif | |
d8925383 | 93 | |
9ce05555 A |
94 | extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey); |
95 | ||
d8925383 A |
96 | // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a |
97 | // simple abstraction layer spanning Mach ports and Windows HANDLES | |
bd5b749c | 98 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
99 | |
100 | typedef mach_port_t __CFPort; | |
101 | #define CFPORT_NULL MACH_PORT_NULL | |
102 | typedef mach_port_t __CFPortSet; | |
103 | ||
104 | static __CFPort __CFPortAllocate(void) { | |
105 | __CFPort result; | |
106 | kern_return_t ret; | |
107 | ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &result); | |
108 | if (KERN_SUCCESS == ret) { | |
109 | ret = mach_port_insert_right(mach_task_self(), result, result, MACH_MSG_TYPE_MAKE_SEND); | |
110 | } | |
111 | if (KERN_SUCCESS == ret) { | |
112 | mach_port_limits_t limits; | |
113 | limits.mpl_qlimit = 1; | |
114 | ret = mach_port_set_attributes(mach_task_self(), result, MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT); | |
115 | } | |
116 | return (KERN_SUCCESS == ret) ? result : CFPORT_NULL; | |
117 | } | |
118 | ||
119 | CF_INLINE void __CFPortFree(__CFPort port) { | |
120 | mach_port_destroy(mach_task_self(), port); | |
121 | } | |
122 | ||
123 | CF_INLINE __CFPortSet __CFPortSetAllocate(void) { | |
124 | __CFPortSet result; | |
125 | kern_return_t ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &result); | |
126 | return (KERN_SUCCESS == ret) ? result : CFPORT_NULL; | |
127 | } | |
128 | ||
129 | CF_INLINE Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { | |
130 | kern_return_t ret = mach_port_insert_member(mach_task_self(), port, portSet); | |
131 | return (KERN_SUCCESS == ret); | |
132 | } | |
133 | ||
134 | CF_INLINE Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { | |
135 | kern_return_t ret = mach_port_extract_member(mach_task_self(), port, portSet); | |
136 | return (KERN_SUCCESS == ret); | |
137 | } | |
138 | ||
139 | CF_INLINE void __CFPortSetFree(__CFPortSet portSet) { | |
140 | kern_return_t ret; | |
141 | mach_port_name_array_t array; | |
142 | mach_msg_type_number_t idx, number; | |
143 | ||
144 | ret = mach_port_get_set_status(mach_task_self(), portSet, &array, &number); | |
145 | if (KERN_SUCCESS == ret) { | |
146 | for (idx = 0; idx < number; idx++) { | |
147 | mach_port_extract_member(mach_task_self(), array[idx], portSet); | |
148 | } | |
149 | vm_deallocate(mach_task_self(), (vm_address_t)array, number * sizeof(mach_port_name_t)); | |
150 | } | |
151 | mach_port_destroy(mach_task_self(), portSet); | |
152 | } | |
153 | ||
154 | #elif defined(__WIN32__) | |
155 | ||
156 | typedef HANDLE __CFPort; | |
157 | #define CFPORT_NULL NULL | |
158 | ||
159 | // A simple dynamic array of HANDLEs, which grows to a high-water mark | |
160 | typedef struct ___CFPortSet { | |
161 | uint16_t used; | |
162 | uint16_t size; | |
163 | HANDLE *handles; | |
164 | CFSpinLock_t lock; // insert and remove must be thread safe, like the Mach calls | |
165 | } *__CFPortSet; | |
166 | ||
167 | CF_INLINE __CFPort __CFPortAllocate(void) { | |
168 | return CreateEvent(NULL, true, false, NULL); | |
169 | } | |
170 | ||
171 | CF_INLINE void __CFPortFree(__CFPort port) { | |
172 | CloseHandle(port); | |
173 | } | |
174 | ||
175 | static __CFPortSet __CFPortSetAllocate(void) { | |
176 | __CFPortSet result = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct ___CFPortSet), 0); | |
177 | result->used = 0; | |
178 | result->size = 4; | |
179 | result->handles = CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0); | |
bd5b749c | 180 | CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock); |
d8925383 A |
181 | return result; |
182 | } | |
183 | ||
184 | static void __CFPortSetFree(__CFPortSet portSet) { | |
185 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet->handles); | |
186 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, portSet); | |
187 | } | |
188 | ||
189 | // Returns portBuf if ports fit in that space, else returns another ptr that must be freed | |
190 | static __CFPort *__CFPortSetGetPorts(__CFPortSet portSet, __CFPort *portBuf, uint32_t bufSize, uint32_t *portsUsed) { | |
191 | __CFSpinLock(&(portSet->lock)); | |
192 | __CFPort *result = portBuf; | |
193 | if (bufSize > portSet->used) | |
194 | result = CFAllocatorAllocate(kCFAllocatorSystemDefault, portSet->used * sizeof(HANDLE), 0); | |
195 | memmove(result, portSet->handles, portSet->used * sizeof(HANDLE)); | |
196 | *portsUsed = portSet->used; | |
197 | __CFSpinUnlock(&(portSet->lock)); | |
198 | return result; | |
199 | } | |
200 | ||
201 | static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { | |
202 | __CFSpinLock(&(portSet->lock)); | |
203 | if (portSet->used >= portSet->size) { | |
204 | portSet->size += 4; | |
205 | portSet->handles = CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0); | |
206 | } | |
207 | if (portSet->used >= MAXIMUM_WAIT_OBJECTS) | |
bd5b749c | 208 | CFLog(kCFLogLevelWarning, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS); |
d8925383 A |
209 | portSet->handles[portSet->used++] = port; |
210 | __CFSpinUnlock(&(portSet->lock)); | |
211 | return true; | |
212 | } | |
213 | ||
214 | static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { | |
215 | int i, j; | |
216 | __CFSpinLock(&(portSet->lock)); | |
217 | for (i = 0; i < portSet->used; i++) { | |
218 | if (portSet->handles[i] == port) { | |
219 | for (j = i+1; j < portSet->used; j++) { | |
220 | portSet->handles[j-1] = portSet->handles[j]; | |
221 | } | |
222 | portSet->used--; | |
223 | __CFSpinUnlock(&(portSet->lock)); | |
224 | return true; | |
225 | } | |
226 | } | |
227 | __CFSpinUnlock(&(portSet->lock)); | |
228 | return false; | |
229 | } | |
230 | ||
231 | #endif | |
232 | ||
bd5b749c | 233 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
234 | extern mach_port_name_t mk_timer_create(void); |
235 | extern kern_return_t mk_timer_destroy(mach_port_name_t name); | |
236 | extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time); | |
237 | extern kern_return_t mk_timer_cancel(mach_port_name_t name, AbsoluteTime *result_time); | |
238 | ||
239 | CF_INLINE AbsoluteTime __CFUInt64ToAbsoluteTime(int64_t x) { | |
240 | AbsoluteTime a; | |
241 | a.hi = x >> 32; | |
242 | a.lo = x & (int64_t)0xFFFFFFFF; | |
243 | return a; | |
244 | } | |
9ce05555 | 245 | |
9ce05555 A |
246 | static uint32_t __CFSendTrivialMachMessage(mach_port_t port, uint32_t msg_id, CFOptionFlags options, uint32_t timeout) { |
247 | kern_return_t result; | |
248 | mach_msg_header_t header; | |
249 | header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); | |
250 | header.msgh_size = sizeof(mach_msg_header_t); | |
251 | header.msgh_remote_port = port; | |
252 | header.msgh_local_port = MACH_PORT_NULL; | |
253 | header.msgh_id = msg_id; | |
254 | result = mach_msg(&header, MACH_SEND_MSG|options, header.msgh_size, 0, MACH_PORT_NULL, timeout, MACH_PORT_NULL); | |
d8925383 | 255 | if (result == MACH_SEND_TIMED_OUT) mach_msg_destroy(&header); |
9ce05555 A |
256 | return result; |
257 | } | |
9ce05555 A |
258 | #endif |
259 | ||
260 | /* unlock a run loop and modes before doing callouts/sleeping */ | |
261 | /* never try to take the run loop lock with a mode locked */ | |
262 | /* be very careful of common subexpression elimination and compacting code, particular across locks and unlocks! */ | |
263 | /* run loop mode structures should never be deallocated, even if they become empty */ | |
264 | ||
265 | static CFTypeID __kCFRunLoopModeTypeID = _kCFRuntimeNotATypeID; | |
266 | static CFTypeID __kCFRunLoopTypeID = _kCFRuntimeNotATypeID; | |
267 | static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID; | |
268 | static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID; | |
269 | static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID; | |
270 | ||
271 | typedef struct __CFRunLoopMode *CFRunLoopModeRef; | |
272 | ||
273 | struct __CFRunLoopMode { | |
274 | CFRuntimeBase _base; | |
275 | CFSpinLock_t _lock; /* must have the run loop locked before locking this */ | |
276 | CFStringRef _name; | |
277 | Boolean _stopped; | |
278 | char _padding[3]; | |
279 | CFMutableSetRef _sources; | |
280 | CFMutableSetRef _observers; | |
281 | CFMutableSetRef _timers; | |
282 | CFMutableArrayRef _submodes; // names of the submodes | |
d8925383 | 283 | __CFPortSet _portSet; |
bd5b749c | 284 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 | 285 | int _kq; |
9ce05555 | 286 | #endif |
9ce05555 A |
287 | }; |
288 | ||
d8925383 A |
289 | static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm); |
290 | ||
9ce05555 A |
291 | CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) { |
292 | __CFSpinLock(&(rlm->_lock)); | |
293 | } | |
294 | ||
295 | CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) { | |
296 | __CFSpinUnlock(&(rlm->_lock)); | |
297 | } | |
298 | ||
299 | static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) { | |
300 | CFRunLoopModeRef rlm1 = (CFRunLoopModeRef)cf1; | |
301 | CFRunLoopModeRef rlm2 = (CFRunLoopModeRef)cf2; | |
302 | return CFEqual(rlm1->_name, rlm2->_name); | |
303 | } | |
304 | ||
305 | static CFHashCode __CFRunLoopModeHash(CFTypeRef cf) { | |
306 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; | |
307 | return CFHash(rlm->_name); | |
308 | } | |
309 | ||
310 | static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) { | |
311 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; | |
312 | CFMutableStringRef result; | |
313 | result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); | |
bd5b749c | 314 | CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoopMode %p [%p]>{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, lockCount(rlm->_lock) ? "true" : "false"); |
9ce05555 | 315 | CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet); |
9ce05555 A |
316 | CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers == %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers); |
317 | return result; | |
318 | } | |
319 | ||
320 | static void __CFRunLoopModeDeallocate(CFTypeRef cf) { | |
321 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; | |
322 | if (NULL != rlm->_sources) CFRelease(rlm->_sources); | |
323 | if (NULL != rlm->_observers) CFRelease(rlm->_observers); | |
324 | if (NULL != rlm->_timers) CFRelease(rlm->_timers); | |
325 | if (NULL != rlm->_submodes) CFRelease(rlm->_submodes); | |
326 | CFRelease(rlm->_name); | |
d8925383 | 327 | __CFPortSetFree(rlm->_portSet); |
bd5b749c | 328 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 | 329 | if (-1 != rlm->_kq) close(rlm->_kq); |
9ce05555 A |
330 | #endif |
331 | } | |
332 | ||
333 | struct __CFRunLoop { | |
334 | CFRuntimeBase _base; | |
335 | CFSpinLock_t _lock; /* locked for accessing mode list */ | |
d8925383 | 336 | __CFPort _wakeUpPort; // used for CFRunLoopWakeUp |
bd5b749c | 337 | volatile uint32_t *_stopped; |
9ce05555 A |
338 | CFMutableSetRef _commonModes; |
339 | CFMutableSetRef _commonModeItems; | |
340 | CFRunLoopModeRef _currentMode; | |
341 | CFMutableSetRef _modes; | |
bd5b749c | 342 | void *_counterpart; |
9ce05555 A |
343 | }; |
344 | ||
345 | /* Bit 0 of the base reserved bits is used for stopped state */ | |
346 | /* Bit 1 of the base reserved bits is used for sleeping state */ | |
347 | /* Bit 2 of the base reserved bits is used for deallocating state */ | |
348 | ||
349 | CF_INLINE Boolean __CFRunLoopIsStopped(CFRunLoopRef rl) { | |
350 | return (rl->_stopped && rl->_stopped[2]) ? true : false; | |
351 | } | |
352 | ||
353 | CF_INLINE void __CFRunLoopSetStopped(CFRunLoopRef rl) { | |
354 | if (rl->_stopped) rl->_stopped[2] = 0x53544F50; // 'STOP' | |
355 | } | |
356 | ||
357 | CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) { | |
358 | if (rl->_stopped) rl->_stopped[2] = 0x0; | |
359 | } | |
360 | ||
361 | CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) { | |
bd5b749c | 362 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1); |
9ce05555 A |
363 | } |
364 | ||
365 | CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) { | |
bd5b749c | 366 | __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1); |
9ce05555 A |
367 | } |
368 | ||
369 | CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) { | |
bd5b749c | 370 | __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0); |
9ce05555 A |
371 | } |
372 | ||
373 | CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) { | |
bd5b749c | 374 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2); |
9ce05555 A |
375 | } |
376 | ||
377 | CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) { | |
bd5b749c | 378 | __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1); |
9ce05555 A |
379 | } |
380 | ||
381 | CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) { | |
382 | __CFSpinLock(&(((CFRunLoopRef)rl)->_lock)); | |
383 | } | |
384 | ||
385 | CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) { | |
386 | __CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock)); | |
387 | } | |
388 | ||
389 | static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) { | |
390 | CFRunLoopRef rl = (CFRunLoopRef)cf; | |
391 | CFMutableStringRef result; | |
392 | result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); | |
bd5b749c | 393 | CFStringAppendFormat(result, NULL, CFSTR("<CFRunLoop %p [%p]>{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), lockCount(rl->_lock) ? "true" : "false", rl->_wakeUpPort, (rl->_stopped && (rl->_stopped[2] == 0x53544F50)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); |
9ce05555 A |
394 | CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes); |
395 | return result; | |
396 | } | |
397 | ||
398 | /* call with rl locked */ | |
399 | static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) { | |
bd5b749c | 400 | CHECK_FOR_FORK(); |
9ce05555 A |
401 | CFRunLoopModeRef rlm; |
402 | struct __CFRunLoopMode srlm; | |
bd5b749c A |
403 | srlm._base._cfisa = __CFISAForTypeID(__kCFRunLoopModeTypeID); |
404 | srlm._base._cfinfo[CF_INFO_BITS] = 0; | |
9ce05555 A |
405 | _CFRuntimeSetInstanceTypeID(&srlm, __kCFRunLoopModeTypeID); |
406 | srlm._name = modeName; | |
407 | rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm); | |
408 | if (NULL != rlm) { | |
409 | __CFRunLoopModeLock(rlm); | |
410 | return rlm; | |
411 | } | |
412 | if (!create) { | |
413 | return NULL; | |
414 | } | |
415 | rlm = (CFRunLoopModeRef)_CFRuntimeCreateInstance(CFGetAllocator(rl), __kCFRunLoopModeTypeID, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase), NULL); | |
416 | if (NULL == rlm) { | |
417 | return NULL; | |
418 | } | |
bd5b749c | 419 | CF_SPINLOCK_INIT_FOR_STRUCTS(rlm->_lock); |
9ce05555 A |
420 | rlm->_name = CFStringCreateCopy(CFGetAllocator(rlm), modeName); |
421 | rlm->_stopped = false; | |
422 | rlm->_sources = NULL; | |
423 | rlm->_observers = NULL; | |
424 | rlm->_timers = NULL; | |
425 | rlm->_submodes = NULL; | |
d8925383 A |
426 | rlm->_portSet = __CFPortSetAllocate(); |
427 | if (CFPORT_NULL == rlm->_portSet) HALT; | |
428 | if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT; | |
bd5b749c | 429 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 | 430 | rlm->_kq = -1; |
9ce05555 A |
431 | #endif |
432 | CFSetAddValue(rl->_modes, rlm); | |
433 | CFRelease(rlm); | |
434 | __CFRunLoopModeLock(rlm); /* return mode locked */ | |
435 | return rlm; | |
436 | } | |
437 | ||
9ce05555 A |
438 | |
439 | // expects rl and rlm locked | |
440 | static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
bd5b749c | 441 | CHECK_FOR_FORK(); |
9ce05555 | 442 | if (NULL == rlm) return true; |
9ce05555 A |
443 | if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false; |
444 | if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false; | |
445 | if (NULL != rlm->_submodes) { | |
446 | CFIndex idx, cnt; | |
447 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
448 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
449 | CFRunLoopModeRef subrlm; | |
450 | Boolean subIsEmpty; | |
451 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
452 | subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm) : true; | |
453 | if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm); | |
454 | if (!subIsEmpty) return false; | |
455 | } | |
456 | } | |
457 | return true; | |
458 | } | |
459 | ||
9ce05555 A |
460 | /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */ |
461 | ||
462 | CF_INLINE Boolean __CFIsValid(const void *cf) { | |
bd5b749c | 463 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3); |
9ce05555 A |
464 | } |
465 | ||
466 | CF_INLINE void __CFSetValid(void *cf) { | |
bd5b749c | 467 | __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1); |
9ce05555 A |
468 | } |
469 | ||
470 | CF_INLINE void __CFUnsetValid(void *cf) { | |
bd5b749c | 471 | __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0); |
9ce05555 A |
472 | } |
473 | ||
474 | struct __CFRunLoopSource { | |
475 | CFRuntimeBase _base; | |
476 | uint32_t _bits; | |
477 | CFSpinLock_t _lock; | |
478 | CFIndex _order; /* immutable */ | |
479 | CFMutableBagRef _runLoops; | |
480 | union { | |
481 | CFRunLoopSourceContext version0; /* immutable, except invalidation */ | |
d8925383 | 482 | CFRunLoopSourceContext1 version1; /* immutable, except invalidation */ |
9ce05555 A |
483 | } _context; |
484 | }; | |
485 | ||
bd5b749c | 486 | /* Bit 1 of the base reserved bits is used for signalled state */ |
9ce05555 A |
487 | |
488 | CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) { | |
489 | return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1); | |
490 | } | |
491 | ||
492 | CF_INLINE void __CFRunLoopSourceSetSignaled(CFRunLoopSourceRef rls) { | |
493 | __CFBitfieldSetValue(rls->_bits, 1, 1, 1); | |
494 | } | |
495 | ||
496 | CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) { | |
497 | __CFBitfieldSetValue(rls->_bits, 1, 1, 0); | |
498 | } | |
499 | ||
500 | CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) { | |
501 | __CFSpinLock(&(rls->_lock)); | |
502 | } | |
503 | ||
504 | CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) { | |
505 | __CFSpinUnlock(&(rls->_lock)); | |
506 | } | |
507 | ||
508 | /* rlm is not locked */ | |
509 | static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ | |
510 | __CFRunLoopSourceLock(rls); | |
511 | if (NULL == rls->_runLoops) { | |
5645d61f | 512 | rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, NULL); |
9ce05555 A |
513 | } |
514 | CFBagAddValue(rls->_runLoops, rl); | |
515 | __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety | |
516 | if (0 == rls->_context.version0.version) { | |
517 | if (NULL != rls->_context.version0.schedule) { | |
518 | rls->_context.version0.schedule(rls->_context.version0.info, rl, rlm->_name); | |
519 | } | |
9ce05555 | 520 | } else if (1 == rls->_context.version0.version) { |
d8925383 A |
521 | __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ |
522 | if (CFPORT_NULL != port) { | |
523 | __CFPortSetInsert(port, rlm->_portSet); | |
524 | } | |
9ce05555 A |
525 | } |
526 | } | |
527 | ||
528 | /* rlm is not locked */ | |
529 | static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ | |
530 | if (0 == rls->_context.version0.version) { | |
531 | if (NULL != rls->_context.version0.cancel) { | |
532 | rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */ | |
533 | } | |
9ce05555 | 534 | } else if (1 == rls->_context.version0.version) { |
d8925383 A |
535 | __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ |
536 | if (CFPORT_NULL != port) { | |
537 | __CFPortSetRemove(port, rlm->_portSet); | |
538 | } | |
9ce05555 A |
539 | } |
540 | __CFRunLoopSourceLock(rls); | |
541 | if (NULL != rls->_runLoops) { | |
542 | CFBagRemoveValue(rls->_runLoops, rl); | |
543 | } | |
544 | __CFRunLoopSourceUnlock(rls); | |
545 | } | |
546 | ||
547 | struct __CFRunLoopObserver { | |
548 | CFRuntimeBase _base; | |
549 | CFSpinLock_t _lock; | |
550 | CFRunLoopRef _runLoop; | |
551 | CFIndex _rlCount; | |
552 | CFOptionFlags _activities; /* immutable */ | |
553 | CFIndex _order; /* immutable */ | |
554 | CFRunLoopObserverCallBack _callout; /* immutable */ | |
555 | CFRunLoopObserverContext _context; /* immutable, except invalidation */ | |
556 | }; | |
557 | ||
558 | /* Bit 0 of the base reserved bits is used for firing state */ | |
559 | /* Bit 1 of the base reserved bits is used for repeats state */ | |
560 | ||
561 | CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) { | |
bd5b749c | 562 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0); |
9ce05555 A |
563 | } |
564 | ||
565 | CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) { | |
bd5b749c | 566 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1); |
9ce05555 A |
567 | } |
568 | ||
569 | CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) { | |
bd5b749c | 570 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0); |
9ce05555 A |
571 | } |
572 | ||
573 | CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) { | |
bd5b749c | 574 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1); |
9ce05555 A |
575 | } |
576 | ||
577 | CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) { | |
bd5b749c | 578 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1); |
9ce05555 A |
579 | } |
580 | ||
581 | CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) { | |
bd5b749c | 582 | __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0); |
9ce05555 A |
583 | } |
584 | ||
585 | CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) { | |
586 | __CFSpinLock(&(rlo->_lock)); | |
587 | } | |
588 | ||
589 | CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) { | |
590 | __CFSpinUnlock(&(rlo->_lock)); | |
591 | } | |
592 | ||
593 | static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
594 | __CFRunLoopObserverLock(rlo); | |
595 | if (0 == rlo->_rlCount) { | |
596 | rlo->_runLoop = rl; | |
597 | } | |
598 | rlo->_rlCount++; | |
599 | __CFRunLoopObserverUnlock(rlo); | |
600 | } | |
601 | ||
602 | static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
603 | __CFRunLoopObserverLock(rlo); | |
604 | rlo->_rlCount--; | |
605 | if (0 == rlo->_rlCount) { | |
606 | rlo->_runLoop = NULL; | |
607 | } | |
608 | __CFRunLoopObserverUnlock(rlo); | |
609 | } | |
610 | ||
611 | struct __CFRunLoopTimer { | |
612 | CFRuntimeBase _base; | |
613 | CFSpinLock_t _lock; | |
614 | CFRunLoopRef _runLoop; | |
615 | CFIndex _rlCount; | |
bd5b749c | 616 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
617 | mach_port_name_t _port; |
618 | #endif | |
619 | CFIndex _order; /* immutable */ | |
620 | int64_t _fireTSR; /* TSR units */ | |
621 | int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */ | |
622 | CFRunLoopTimerCallBack _callout; /* immutable */ | |
623 | CFRunLoopTimerContext _context; /* immutable, except invalidation */ | |
624 | }; | |
625 | ||
626 | /* Bit 0 of the base reserved bits is used for firing state */ | |
d8925383 | 627 | /* Bit 1 of the base reserved bits is used for fired-during-callout state */ |
9ce05555 A |
628 | |
629 | CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) { | |
bd5b749c | 630 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0); |
9ce05555 A |
631 | } |
632 | ||
633 | CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) { | |
bd5b749c | 634 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 1); |
9ce05555 A |
635 | } |
636 | ||
637 | CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) { | |
bd5b749c | 638 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 0); |
9ce05555 A |
639 | } |
640 | ||
d8925383 | 641 | CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) { |
bd5b749c | 642 | return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1); |
d8925383 A |
643 | } |
644 | ||
645 | CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) { | |
bd5b749c | 646 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 1); |
d8925383 A |
647 | } |
648 | ||
649 | CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) { | |
bd5b749c | 650 | __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 0); |
d8925383 A |
651 | } |
652 | ||
9ce05555 A |
653 | CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) { |
654 | __CFSpinLock(&(rlt->_lock)); | |
655 | } | |
656 | ||
657 | CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) { | |
658 | __CFSpinUnlock(&(rlt->_lock)); | |
659 | } | |
660 | ||
bd5b749c | 661 | static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit; |
9ce05555 A |
662 | |
663 | CF_INLINE void __CFRunLoopTimerFireTSRLock(void) { | |
664 | __CFSpinLock(&__CFRLTFireTSRLock); | |
665 | } | |
666 | ||
667 | CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) { | |
668 | __CFSpinUnlock(&__CFRLTFireTSRLock); | |
669 | } | |
670 | ||
bd5b749c | 671 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 | 672 | static CFMutableDictionaryRef __CFRLTPortMap = NULL; |
bd5b749c | 673 | static CFSpinLock_t __CFRLTPortMapLock = CFSpinLockInit; |
9ce05555 A |
674 | |
675 | CF_INLINE void __CFRunLoopTimerPortMapLock(void) { | |
676 | __CFSpinLock(&__CFRLTPortMapLock); | |
677 | } | |
678 | ||
679 | CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) { | |
680 | __CFSpinUnlock(&__CFRLTPortMapLock); | |
681 | } | |
d8925383 | 682 | #endif |
9ce05555 A |
683 | |
684 | static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
bd5b749c | 685 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
686 | __CFRunLoopTimerLock(rlt); |
687 | if (0 == rlt->_rlCount) { | |
688 | rlt->_runLoop = rl; | |
689 | if (MACH_PORT_NULL == rlt->_port) { | |
690 | rlt->_port = mk_timer_create(); | |
691 | } | |
692 | __CFRunLoopTimerPortMapLock(); | |
693 | if (NULL == __CFRLTPortMap) { | |
694 | __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); | |
695 | } | |
bd5b749c | 696 | CFDictionarySetValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port, rlt); |
9ce05555 A |
697 | __CFRunLoopTimerPortMapUnlock(); |
698 | } | |
699 | rlt->_rlCount++; | |
700 | mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet); | |
701 | mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR)); | |
702 | __CFRunLoopTimerUnlock(rlt); | |
703 | #endif | |
704 | } | |
705 | ||
706 | static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { | |
bd5b749c | 707 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 | 708 | __CFRunLoopTimerLock(rlt); |
d8925383 | 709 | __CFPortSetRemove(rlt->_port, rlm->_portSet); |
9ce05555 A |
710 | rlt->_rlCount--; |
711 | if (0 == rlt->_rlCount) { | |
712 | __CFRunLoopTimerPortMapLock(); | |
713 | if (NULL != __CFRLTPortMap) { | |
bd5b749c | 714 | CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); |
9ce05555 A |
715 | } |
716 | __CFRunLoopTimerPortMapUnlock(); | |
717 | rlt->_runLoop = NULL; | |
718 | mk_timer_cancel(rlt->_port, NULL); | |
719 | } | |
720 | __CFRunLoopTimerUnlock(rlt); | |
721 | #endif | |
722 | } | |
723 | ||
d8925383 | 724 | // Caller must hold the Timer lock for safety |
9ce05555 | 725 | static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt, CFRunLoopRef rl) { |
bd5b749c | 726 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
727 | mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR)); |
728 | #endif | |
729 | } | |
730 | ||
9ce05555 A |
731 | /* CFRunLoop */ |
732 | ||
733 | CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode") | |
734 | CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes") | |
735 | ||
9ce05555 | 736 | struct _findsource { |
d8925383 | 737 | __CFPort port; |
9ce05555 A |
738 | CFRunLoopSourceRef result; |
739 | }; | |
740 | ||
741 | static void __CFRunLoopFindSource(const void *value, void *ctx) { | |
742 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value; | |
743 | struct _findsource *context = (struct _findsource *)ctx; | |
d8925383 | 744 | __CFPort port; |
9ce05555 A |
745 | if (NULL != context->result) return; |
746 | if (1 != rls->_context.version0.version) return; | |
747 | __CFRunLoopSourceLock(rls); | |
748 | port = rls->_context.version1.getPort(rls->_context.version1.info); | |
749 | if (port == context->port) { | |
750 | context->result = rls; | |
751 | } | |
752 | __CFRunLoopSourceUnlock(rls); | |
753 | } | |
754 | ||
755 | // call with rl and rlm locked | |
d8925383 | 756 | static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) { /* DOES CALLOUT */ |
bd5b749c | 757 | CHECK_FOR_FORK(); |
9ce05555 A |
758 | struct _findsource context = {port, NULL}; |
759 | if (NULL != rlm->_sources) { | |
760 | CFSetApplyFunction(rlm->_sources, (__CFRunLoopFindSource), &context); | |
761 | } | |
762 | if (NULL == context.result && NULL != rlm->_submodes) { | |
763 | CFIndex idx, cnt; | |
764 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
765 | CFRunLoopSourceRef source = NULL; | |
766 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
767 | CFRunLoopModeRef subrlm; | |
768 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
769 | if (NULL != subrlm) { | |
770 | source = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port); | |
771 | __CFRunLoopModeUnlock(subrlm); | |
772 | } | |
773 | if (NULL != source) { | |
774 | context.result = source; | |
775 | break; | |
776 | } | |
777 | } | |
778 | } | |
779 | return context.result; | |
780 | } | |
781 | ||
bd5b749c | 782 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 | 783 | // call with rl and rlm locked |
d8925383 | 784 | static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, __CFPort port) { |
bd5b749c | 785 | CHECK_FOR_FORK(); |
9ce05555 A |
786 | CFRunLoopTimerRef result = NULL; |
787 | __CFRunLoopTimerPortMapLock(); | |
788 | if (NULL != __CFRLTPortMap) { | |
bd5b749c | 789 | result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)(uintptr_t)port); |
9ce05555 A |
790 | } |
791 | __CFRunLoopTimerPortMapUnlock(); | |
792 | return result; | |
793 | } | |
794 | #endif | |
795 | ||
5645d61f A |
796 | // Remove backreferences the mode's sources have to the rl (context); |
797 | // the primary purpose of rls->_runLoops is so that Invalidation can remove | |
798 | // the source from the run loops it is in, but during deallocation of a | |
799 | // run loop, we already know that the sources are going to be punted | |
800 | // from it, so invalidation of sources does not need to remove from a | |
801 | // deallocating run loop. | |
802 | static void __CFRunLoopCleanseSources(const void *value, void *context) { | |
803 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
804 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
805 | CFIndex idx, cnt; | |
806 | const void **list, *buffer[256]; | |
807 | if (NULL == rlm->_sources) return; | |
808 | cnt = CFSetGetCount(rlm->_sources); | |
809 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
810 | CFSetGetValues(rlm->_sources, list); | |
811 | for (idx = 0; idx < cnt; idx++) { | |
812 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; | |
813 | __CFRunLoopSourceLock(rls); | |
814 | if (NULL != rls->_runLoops) { | |
815 | CFBagRemoveValue(rls->_runLoops, rl); | |
816 | } | |
817 | __CFRunLoopSourceUnlock(rls); | |
818 | } | |
819 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
820 | } | |
821 | ||
9ce05555 A |
822 | static void __CFRunLoopDeallocateSources(const void *value, void *context) { |
823 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
824 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
825 | CFIndex idx, cnt; | |
826 | const void **list, *buffer[256]; | |
827 | if (NULL == rlm->_sources) return; | |
828 | cnt = CFSetGetCount(rlm->_sources); | |
829 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
830 | CFSetGetValues(rlm->_sources, list); | |
831 | for (idx = 0; idx < cnt; idx++) { | |
832 | CFRetain(list[idx]); | |
833 | } | |
834 | CFSetRemoveAllValues(rlm->_sources); | |
835 | for (idx = 0; idx < cnt; idx++) { | |
836 | __CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm); | |
837 | CFRelease(list[idx]); | |
838 | } | |
839 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
840 | } | |
841 | ||
842 | static void __CFRunLoopDeallocateObservers(const void *value, void *context) { | |
843 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
844 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
845 | CFIndex idx, cnt; | |
846 | const void **list, *buffer[256]; | |
847 | if (NULL == rlm->_observers) return; | |
848 | cnt = CFSetGetCount(rlm->_observers); | |
849 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
850 | CFSetGetValues(rlm->_observers, list); | |
851 | for (idx = 0; idx < cnt; idx++) { | |
852 | CFRetain(list[idx]); | |
853 | } | |
854 | CFSetRemoveAllValues(rlm->_observers); | |
855 | for (idx = 0; idx < cnt; idx++) { | |
856 | __CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm); | |
857 | CFRelease(list[idx]); | |
858 | } | |
859 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
860 | } | |
861 | ||
862 | static void __CFRunLoopDeallocateTimers(const void *value, void *context) { | |
863 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
864 | CFRunLoopRef rl = (CFRunLoopRef)context; | |
865 | CFIndex idx, cnt; | |
866 | const void **list, *buffer[256]; | |
867 | if (NULL == rlm->_timers) return; | |
868 | cnt = CFSetGetCount(rlm->_timers); | |
869 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
870 | CFSetGetValues(rlm->_timers, list); | |
871 | for (idx = 0; idx < cnt; idx++) { | |
872 | CFRetain(list[idx]); | |
873 | } | |
874 | CFSetRemoveAllValues(rlm->_timers); | |
875 | for (idx = 0; idx < cnt; idx++) { | |
876 | __CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm); | |
877 | CFRelease(list[idx]); | |
878 | } | |
879 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
880 | } | |
881 | ||
882 | static void __CFRunLoopDeallocate(CFTypeRef cf) { | |
883 | CFRunLoopRef rl = (CFRunLoopRef)cf; | |
884 | /* We try to keep the run loop in a valid state as long as possible, | |
885 | since sources may have non-retained references to the run loop. | |
886 | Another reason is that we don't want to lock the run loop for | |
887 | callback reasons, if we can get away without that. We start by | |
888 | eliminating the sources, since they are the most likely to call | |
889 | back into the run loop during their "cancellation". Common mode | |
890 | items will be removed from the mode indirectly by the following | |
891 | three lines. */ | |
892 | __CFRunLoopSetDeallocating(rl); | |
893 | if (NULL != rl->_modes) { | |
5645d61f | 894 | CFSetApplyFunction(rl->_modes, (__CFRunLoopCleanseSources), rl); // remove references to rl |
9ce05555 A |
895 | CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateSources), rl); |
896 | CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateObservers), rl); | |
897 | CFSetApplyFunction(rl->_modes, (__CFRunLoopDeallocateTimers), rl); | |
898 | } | |
899 | __CFRunLoopLock(rl); | |
900 | if (NULL != rl->_commonModeItems) { | |
901 | CFRelease(rl->_commonModeItems); | |
902 | } | |
903 | if (NULL != rl->_commonModes) { | |
904 | CFRelease(rl->_commonModes); | |
905 | } | |
906 | if (NULL != rl->_modes) { | |
907 | CFRelease(rl->_modes); | |
908 | } | |
d8925383 A |
909 | __CFPortFree(rl->_wakeUpPort); |
910 | rl->_wakeUpPort = CFPORT_NULL; | |
9ce05555 A |
911 | __CFRunLoopUnlock(rl); |
912 | } | |
913 | ||
914 | static const CFRuntimeClass __CFRunLoopModeClass = { | |
915 | 0, | |
916 | "CFRunLoopMode", | |
917 | NULL, // init | |
918 | NULL, // copy | |
919 | __CFRunLoopModeDeallocate, | |
920 | __CFRunLoopModeEqual, | |
921 | __CFRunLoopModeHash, | |
922 | NULL, // | |
923 | __CFRunLoopModeCopyDescription | |
924 | }; | |
925 | ||
926 | static const CFRuntimeClass __CFRunLoopClass = { | |
927 | 0, | |
928 | "CFRunLoop", | |
929 | NULL, // init | |
930 | NULL, // copy | |
931 | __CFRunLoopDeallocate, | |
932 | NULL, | |
933 | NULL, | |
934 | NULL, // | |
935 | __CFRunLoopCopyDescription | |
936 | }; | |
937 | ||
938 | __private_extern__ void __CFRunLoopInitialize(void) { | |
939 | __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass); | |
940 | __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass); | |
941 | } | |
942 | ||
943 | CFTypeID CFRunLoopGetTypeID(void) { | |
944 | return __kCFRunLoopTypeID; | |
945 | } | |
946 | ||
947 | static CFRunLoopRef __CFRunLoopCreate(void) { | |
948 | CFRunLoopRef loop = NULL; | |
949 | CFRunLoopModeRef rlm; | |
950 | uint32_t size = sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase); | |
951 | loop = (CFRunLoopRef)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, __kCFRunLoopTypeID, size, NULL); | |
952 | if (NULL == loop) { | |
953 | return NULL; | |
954 | } | |
955 | loop->_stopped = NULL; | |
bd5b749c | 956 | CF_SPINLOCK_INIT_FOR_STRUCTS(loop->_lock); |
d8925383 A |
957 | loop->_wakeUpPort = __CFPortAllocate(); |
958 | if (CFPORT_NULL == loop->_wakeUpPort) HALT; | |
9ce05555 A |
959 | loop->_commonModes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks); |
960 | CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode); | |
961 | loop->_commonModeItems = NULL; | |
962 | loop->_currentMode = NULL; | |
963 | loop->_modes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks); | |
964 | _CFSetSetCapacity(loop->_modes, 10); | |
bd5b749c | 965 | loop->_counterpart = NULL; |
9ce05555 A |
966 | rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true); |
967 | if (NULL != rlm) __CFRunLoopModeUnlock(rlm); | |
968 | return loop; | |
969 | } | |
970 | ||
5645d61f A |
971 | static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName); |
972 | ||
973 | static CFMutableDictionaryRef __CFRunLoops = NULL; | |
bd5b749c A |
974 | static char setMainLoop = 0; |
975 | static CFSpinLock_t loopsLock = CFSpinLockInit; | |
d8925383 | 976 | |
bd5b749c A |
977 | // If this is called on a non-main thread, and the main thread pthread_t is passed in, |
978 | // and this has not yet beed called on the main thread (since the last fork(), this will | |
979 | // produce a different run loop that will probably be tossed away eventually, than the | |
980 | // main thread run loop. There's nothing much we can do about that, without a call to | |
981 | // fetch the main thread's pthread_t from the pthreads subsystem. | |
9ce05555 | 982 | |
bd5b749c | 983 | // t==0 is a synonym for "main thread" that always works |
5645d61f A |
984 | static CFRunLoopRef _CFRunLoop0(pthread_t t) { |
985 | CFRunLoopRef loop; | |
bd5b749c | 986 | __CFSpinLock(&loopsLock); |
5645d61f | 987 | if (!__CFRunLoops) { |
bd5b749c | 988 | __CFSpinUnlock(&loopsLock); |
5645d61f | 989 | CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); |
bd5b749c | 990 | CFRunLoopRef mainLoop = __CFRunLoopCreate(); |
5645d61f A |
991 | CFDictionarySetValue(dict, pthreadPointer(kNilPthreadT), mainLoop); |
992 | if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) { | |
bd5b749c | 993 | CFRelease(dict); |
bd5b749c | 994 | } |
5645d61f | 995 | CFRelease(mainLoop); |
bd5b749c A |
996 | __CFSpinLock(&loopsLock); |
997 | } | |
998 | if (pthread_main_np() && pthread_equal(t, pthread_self())) { | |
999 | t = kNilPthreadT; | |
1000 | } | |
5645d61f | 1001 | loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); |
bd5b749c A |
1002 | if (!loop) { |
1003 | __CFSpinUnlock(&loopsLock); | |
1004 | CFRunLoopRef newLoop = __CFRunLoopCreate(); | |
bd5b749c | 1005 | __CFSpinLock(&loopsLock); |
5645d61f A |
1006 | loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t)); |
1007 | if (!loop) { | |
1008 | CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop); | |
bd5b749c A |
1009 | loop = newLoop; |
1010 | } | |
5645d61f | 1011 | CFRelease(newLoop); |
9ce05555 | 1012 | } |
bd5b749c A |
1013 | if (!setMainLoop && pthread_main_np()) { |
1014 | if (pthread_equal(t, kNilPthreadT)) { | |
5645d61f | 1015 | CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), loop); |
bd5b749c | 1016 | } else { |
5645d61f A |
1017 | CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(kNilPthreadT)); |
1018 | CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), mainLoop); | |
bd5b749c A |
1019 | } |
1020 | setMainLoop = 1; | |
9ce05555 | 1021 | } |
bd5b749c A |
1022 | __CFSpinUnlock(&loopsLock); |
1023 | return loop; | |
9ce05555 A |
1024 | } |
1025 | ||
5645d61f A |
1026 | // Called for each thread as it exits |
1027 | static void __CFFinalizeRunLoop(void *arg) { | |
1028 | CFRunLoopRef rl = NULL; | |
bd5b749c | 1029 | __CFSpinLock(&loopsLock); |
5645d61f A |
1030 | if (__CFRunLoops) { |
1031 | rl = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(pthread_self())); | |
1032 | if (rl) CFRetain(rl); | |
1033 | CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self())); | |
bd5b749c | 1034 | } |
5645d61f A |
1035 | __CFSpinUnlock(&loopsLock); |
1036 | if (rl && CFRunLoopGetMain() != rl) { | |
1037 | // purge all sources before deallocation | |
1038 | CFArrayRef array = CFRunLoopCopyAllModes(rl); | |
1039 | for (CFIndex idx = CFArrayGetCount(array); idx--;) { | |
1040 | CFStringRef modeName = CFArrayGetValueAtIndex(array, idx); | |
1041 | __CFRunLoopRemoveAllSources(rl, modeName); | |
1042 | } | |
1043 | __CFRunLoopRemoveAllSources(rl, kCFRunLoopCommonModes); | |
1044 | CFRelease(array); | |
1045 | } | |
1046 | if (rl) { | |
1047 | CFRelease(rl); | |
1048 | } | |
1049 | } | |
1050 | ||
1051 | __private_extern__ void _CFRunLoop1(void) { __CFFinalizeRunLoop(0); } | |
1052 | ||
1053 | void _CFRunLoopSetCurrent(CFRunLoopRef rl) { | |
1054 | CFRunLoopRef currentLoop = CFRunLoopGetCurrent(); | |
1055 | if (rl != currentLoop) { | |
1056 | __CFSpinLock(&loopsLock); | |
1057 | if (rl) { | |
1058 | CFDictionarySetValue(__CFRunLoops, pthreadPointer(pthread_self()), rl); | |
1059 | } else { | |
1060 | CFDictionaryRemoveValue(__CFRunLoops, pthreadPointer(pthread_self())); | |
9ce05555 | 1061 | } |
bd5b749c | 1062 | __CFSpinUnlock(&loopsLock); |
5645d61f | 1063 | } |
bd5b749c A |
1064 | } |
1065 | ||
1066 | CFRunLoopRef CFRunLoopGetMain(void) { | |
1067 | CHECK_FOR_FORK(); | |
1068 | return _CFRunLoop0(kNilPthreadT); | |
9ce05555 A |
1069 | } |
1070 | ||
1071 | CFRunLoopRef CFRunLoopGetCurrent(void) { | |
bd5b749c A |
1072 | CHECK_FOR_FORK(); |
1073 | return _CFRunLoop0(pthread_self()); | |
9ce05555 A |
1074 | } |
1075 | ||
9ce05555 | 1076 | CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) { |
bd5b749c | 1077 | CHECK_FOR_FORK(); |
9ce05555 A |
1078 | CFStringRef result = NULL; |
1079 | __CFRunLoopLock(rl); | |
1080 | if (NULL != rl->_currentMode) { | |
1081 | result = CFRetain(rl->_currentMode->_name); | |
1082 | } | |
1083 | __CFRunLoopUnlock(rl); | |
1084 | return result; | |
1085 | } | |
1086 | ||
1087 | static void __CFRunLoopGetModeName(const void *value, void *context) { | |
1088 | CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; | |
1089 | CFMutableArrayRef array = (CFMutableArrayRef)context; | |
1090 | CFArrayAppendValue(array, rlm->_name); | |
1091 | } | |
1092 | ||
1093 | CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) { | |
bd5b749c | 1094 | CHECK_FOR_FORK(); |
9ce05555 A |
1095 | CFMutableArrayRef array; |
1096 | __CFRunLoopLock(rl); | |
bd5b749c | 1097 | array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks); |
9ce05555 A |
1098 | CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array); |
1099 | __CFRunLoopUnlock(rl); | |
1100 | return array; | |
1101 | } | |
1102 | ||
1103 | static void __CFRunLoopAddItemsToCommonMode(const void *value, void *ctx) { | |
1104 | CFTypeRef item = (CFTypeRef)value; | |
1105 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
1106 | CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]); | |
1107 | if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) { | |
1108 | CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName); | |
1109 | } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) { | |
1110 | CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName); | |
1111 | } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) { | |
1112 | CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName); | |
1113 | } | |
1114 | } | |
1115 | ||
1116 | static void __CFRunLoopAddItemToCommonModes(const void *value, void *ctx) { | |
1117 | CFStringRef modeName = (CFStringRef)value; | |
1118 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
1119 | CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]); | |
1120 | if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) { | |
1121 | CFRunLoopAddSource(rl, (CFRunLoopSourceRef)item, modeName); | |
1122 | } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) { | |
1123 | CFRunLoopAddObserver(rl, (CFRunLoopObserverRef)item, modeName); | |
1124 | } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) { | |
1125 | CFRunLoopAddTimer(rl, (CFRunLoopTimerRef)item, modeName); | |
1126 | } | |
1127 | } | |
1128 | ||
1129 | static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) { | |
1130 | CFStringRef modeName = (CFStringRef)value; | |
1131 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
1132 | CFTypeRef item = (CFTypeRef)(((CFTypeRef *)ctx)[1]); | |
1133 | if (CFGetTypeID(item) == __kCFRunLoopSourceTypeID) { | |
1134 | CFRunLoopRemoveSource(rl, (CFRunLoopSourceRef)item, modeName); | |
1135 | } else if (CFGetTypeID(item) == __kCFRunLoopObserverTypeID) { | |
1136 | CFRunLoopRemoveObserver(rl, (CFRunLoopObserverRef)item, modeName); | |
1137 | } else if (CFGetTypeID(item) == __kCFRunLoopTimerTypeID) { | |
1138 | CFRunLoopRemoveTimer(rl, (CFRunLoopTimerRef)item, modeName); | |
1139 | } | |
1140 | } | |
1141 | ||
bd5b749c A |
1142 | Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) { |
1143 | __CFRunLoopLock(rl); | |
1144 | Boolean present = CFSetContainsValue(rl->_commonModes, modeName); | |
1145 | __CFRunLoopUnlock(rl); | |
1146 | return present; | |
1147 | } | |
1148 | ||
1149 | void *_CFRunLoop02(CFRunLoopRef rl) { | |
1150 | return rl->_counterpart; | |
1151 | } | |
1152 | ||
1153 | void _CFRunLoop03(CFRunLoopRef rl, void *ns) { | |
1154 | rl->_counterpart = ns; | |
1155 | } | |
1156 | ||
9ce05555 | 1157 | void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) { |
bd5b749c | 1158 | CHECK_FOR_FORK(); |
9ce05555 A |
1159 | if (__CFRunLoopIsDeallocating(rl)) return; |
1160 | __CFRunLoopLock(rl); | |
1161 | if (!CFSetContainsValue(rl->_commonModes, modeName)) { | |
1162 | CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL; | |
1163 | CFSetAddValue(rl->_commonModes, modeName); | |
1164 | __CFRunLoopUnlock(rl); | |
1165 | if (NULL != set) { | |
1166 | CFTypeRef context[2] = {rl, modeName}; | |
1167 | /* add all common-modes items to new mode */ | |
1168 | CFSetApplyFunction(set, (__CFRunLoopAddItemsToCommonMode), (void *)context); | |
1169 | CFRelease(set); | |
1170 | } | |
1171 | } else { | |
1172 | __CFRunLoopUnlock(rl); | |
1173 | } | |
1174 | } | |
1175 | ||
bd5b749c A |
1176 | static CFComparisonResult __CFRunLoopObserverQSortComparator(const void *val1, const void *val2, void *context) { |
1177 | CFRunLoopObserverRef o1 = *((CFRunLoopObserverRef *)val1); | |
1178 | CFRunLoopObserverRef o2 = *((CFRunLoopObserverRef *)val2); | |
1179 | if (!o1) { | |
1180 | return (!o2) ? kCFCompareEqualTo : kCFCompareLessThan; | |
1181 | } | |
1182 | if (!o2) { | |
1183 | return kCFCompareGreaterThan; | |
1184 | } | |
9ce05555 A |
1185 | if (o1->_order < o2->_order) return kCFCompareLessThan; |
1186 | if (o2->_order < o1->_order) return kCFCompareGreaterThan; | |
1187 | return kCFCompareEqualTo; | |
1188 | } | |
1189 | ||
9ce05555 A |
1190 | |
1191 | /* rl is unlocked, rlm is locked on entrance and exit */ | |
1192 | /* ALERT: this should collect all the candidate observers from the top level | |
1193 | * and all submodes, recursively, THEN start calling them, in order to obey | |
1194 | * the ordering parameter. */ | |
1195 | static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */ | |
bd5b749c | 1196 | CHECK_FOR_FORK(); |
9ce05555 | 1197 | CFIndex idx, cnt; |
9ce05555 | 1198 | CFArrayRef submodes; |
9ce05555 A |
1199 | |
1200 | /* Fire the observers */ | |
1201 | submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; | |
1202 | if (NULL != rlm->_observers) { | |
bd5b749c | 1203 | cnt = CFSetGetCount(rlm->_observers); |
9ce05555 | 1204 | if (0 < cnt) { |
bd5b749c A |
1205 | CFRunLoopObserverRef buffer[(cnt <= 1024) ? cnt : 1]; |
1206 | CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFRunLoopObserverRef), 0); | |
1207 | CFSetGetValues(rlm->_observers, (const void **)collectedObservers); | |
9ce05555 | 1208 | for (idx = 0; idx < cnt; idx++) { |
bd5b749c A |
1209 | CFRunLoopObserverRef rlo = collectedObservers[idx]; |
1210 | if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { | |
1211 | CFRetain(rlo); | |
9ce05555 | 1212 | } else { |
bd5b749c A |
1213 | /* We're not interested in this one - set it to NULL so we don't process it later */ |
1214 | collectedObservers[idx] = NULL; | |
9ce05555 A |
1215 | } |
1216 | } | |
bd5b749c A |
1217 | __CFRunLoopModeUnlock(rlm); |
1218 | CFQSortArray(collectedObservers, cnt, sizeof(CFRunLoopObserverRef), __CFRunLoopObserverQSortComparator, NULL); | |
1219 | for (idx = 0; idx < cnt; idx++) { | |
1220 | CFRunLoopObserverRef rlo = collectedObservers[idx]; | |
1221 | if (rlo) { | |
1222 | __CFRunLoopObserverLock(rlo); | |
1223 | if (__CFIsValid(rlo)) { | |
1224 | __CFRunLoopObserverUnlock(rlo); | |
1225 | __CFRunLoopObserverSetFiring(rlo); | |
1226 | rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */ | |
1227 | __CFRunLoopObserverUnsetFiring(rlo); | |
1228 | if (!__CFRunLoopObserverRepeats(rlo)) { | |
1229 | CFRunLoopObserverInvalidate(rlo); | |
1230 | } | |
1231 | } else { | |
1232 | __CFRunLoopObserverUnlock(rlo); | |
1233 | } | |
1234 | CFRelease(rlo); | |
1235 | } | |
1236 | } | |
9ce05555 | 1237 | __CFRunLoopModeLock(rlm); |
bd5b749c | 1238 | if (collectedObservers != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, collectedObservers); |
9ce05555 | 1239 | } |
9ce05555 A |
1240 | } |
1241 | if (NULL != submodes) { | |
1242 | __CFRunLoopModeUnlock(rlm); | |
1243 | for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) { | |
1244 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx); | |
1245 | CFRunLoopModeRef subrlm; | |
1246 | __CFRunLoopLock(rl); | |
1247 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1248 | __CFRunLoopUnlock(rl); | |
1249 | if (NULL != subrlm) { | |
1250 | __CFRunLoopDoObservers(rl, subrlm, activity); | |
1251 | __CFRunLoopModeUnlock(subrlm); | |
1252 | } | |
1253 | } | |
1254 | CFRelease(submodes); | |
1255 | __CFRunLoopModeLock(rlm); | |
1256 | } | |
1257 | } | |
1258 | ||
1259 | static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) { | |
1260 | CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1; | |
1261 | CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2; | |
1262 | if (o1->_order < o2->_order) return kCFCompareLessThan; | |
1263 | if (o2->_order < o1->_order) return kCFCompareGreaterThan; | |
1264 | return kCFCompareEqualTo; | |
1265 | } | |
1266 | ||
1267 | static void __CFRunLoopCollectSources0(const void *value, void *context) { | |
1268 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value; | |
1269 | CFTypeRef *sources = (CFTypeRef *)context; | |
1270 | if (0 == rls->_context.version0.version && __CFIsValid(rls) && __CFRunLoopSourceIsSignaled(rls)) { | |
1271 | if (NULL == *sources) { | |
1272 | *sources = CFRetain(rls); | |
1273 | } else if (CFGetTypeID(*sources) == __kCFRunLoopSourceTypeID) { | |
1274 | CFTypeRef oldrls = *sources; | |
1275 | *sources = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); | |
1276 | CFArrayAppendValue((CFMutableArrayRef)*sources, oldrls); | |
1277 | CFArrayAppendValue((CFMutableArrayRef)*sources, rls); | |
1278 | CFRelease(oldrls); | |
1279 | } else { | |
1280 | CFArrayAppendValue((CFMutableArrayRef)*sources, rls); | |
1281 | } | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | /* rl is unlocked, rlm is locked on entrance and exit */ | |
1286 | static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */ | |
bd5b749c | 1287 | CHECK_FOR_FORK(); |
9ce05555 A |
1288 | CFTypeRef sources = NULL; |
1289 | Boolean sourceHandled = false; | |
1290 | CFIndex idx, cnt; | |
1291 | ||
1292 | __CFRunLoopModeUnlock(rlm); // locks have to be taken in order | |
1293 | __CFRunLoopLock(rl); | |
1294 | __CFRunLoopModeLock(rlm); | |
1295 | /* Fire the version 0 sources */ | |
1296 | if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) { | |
1297 | CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources); | |
1298 | } | |
1299 | for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) { | |
1300 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
1301 | CFRunLoopModeRef subrlm; | |
1302 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1303 | if (NULL != subrlm) { | |
1304 | if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) { | |
1305 | CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources); | |
1306 | } | |
1307 | __CFRunLoopModeUnlock(subrlm); | |
1308 | } | |
1309 | } | |
1310 | __CFRunLoopUnlock(rl); | |
1311 | if (NULL != sources) { | |
1312 | // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef | |
1313 | __CFRunLoopModeUnlock(rlm); | |
1314 | if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) { | |
1315 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources; | |
1316 | __CFRunLoopSourceLock(rls); | |
1317 | __CFRunLoopSourceUnsetSignaled(rls); | |
1318 | if (__CFIsValid(rls)) { | |
1319 | __CFRunLoopSourceUnlock(rls); | |
1320 | if (NULL != rls->_context.version0.perform) { | |
1321 | rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ | |
bd5b749c | 1322 | CHECK_FOR_FORK(); |
9ce05555 A |
1323 | } |
1324 | sourceHandled = true; | |
1325 | } else { | |
1326 | __CFRunLoopSourceUnlock(rls); | |
1327 | } | |
1328 | } else { | |
1329 | cnt = CFArrayGetCount(sources); | |
1330 | CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL); | |
1331 | for (idx = 0; idx < cnt; idx++) { | |
1332 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, idx); | |
1333 | __CFRunLoopSourceLock(rls); | |
1334 | __CFRunLoopSourceUnsetSignaled(rls); | |
1335 | if (__CFIsValid(rls)) { | |
1336 | __CFRunLoopSourceUnlock(rls); | |
1337 | if (NULL != rls->_context.version0.perform) { | |
1338 | rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ | |
bd5b749c | 1339 | CHECK_FOR_FORK(); |
9ce05555 A |
1340 | } |
1341 | sourceHandled = true; | |
1342 | } else { | |
1343 | __CFRunLoopSourceUnlock(rls); | |
1344 | } | |
1345 | if (stopAfterHandle && sourceHandled) { | |
1346 | break; | |
1347 | } | |
1348 | } | |
1349 | } | |
1350 | CFRelease(sources); | |
1351 | __CFRunLoopModeLock(rlm); | |
1352 | } | |
1353 | return sourceHandled; | |
1354 | } | |
1355 | ||
d8925383 A |
1356 | // msg, size and reply are unused on Windows |
1357 | static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls | |
bd5b749c | 1358 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
1359 | , mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply |
1360 | #endif | |
1361 | ) { /* DOES CALLOUT */ | |
bd5b749c | 1362 | CHECK_FOR_FORK(); |
9ce05555 A |
1363 | Boolean sourceHandled = false; |
1364 | ||
1365 | /* Fire a version 1 source */ | |
1366 | CFRetain(rls); | |
1367 | __CFRunLoopModeUnlock(rlm); | |
1368 | __CFRunLoopSourceLock(rls); | |
1369 | if (__CFIsValid(rls)) { | |
1370 | __CFRunLoopSourceUnsetSignaled(rls); | |
1371 | __CFRunLoopSourceUnlock(rls); | |
1372 | if (NULL != rls->_context.version1.perform) { | |
bd5b749c | 1373 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 | 1374 | *reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info); /* CALLOUT */ |
bd5b749c | 1375 | CHECK_FOR_FORK(); |
d8925383 | 1376 | #else |
bd5b749c | 1377 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } |
d8925383 | 1378 | rls->_context.version1.perform(rls->_context.version1.info); /* CALLOUT */ |
bd5b749c | 1379 | CHECK_FOR_FORK(); |
d8925383 | 1380 | #endif |
bd5b749c A |
1381 | } else { |
1382 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); } | |
1383 | } | |
9ce05555 A |
1384 | sourceHandled = true; |
1385 | } else { | |
bd5b749c | 1386 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } |
9ce05555 A |
1387 | __CFRunLoopSourceUnlock(rls); |
1388 | } | |
1389 | CFRelease(rls); | |
1390 | __CFRunLoopModeLock(rlm); | |
1391 | return sourceHandled; | |
1392 | } | |
9ce05555 A |
1393 | |
1394 | static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ | |
1395 | Boolean timerHandled = false; | |
1396 | int64_t oldFireTSR = 0; | |
1397 | ||
1398 | /* Fire a timer */ | |
1399 | CFRetain(rlt); | |
1400 | __CFRunLoopModeUnlock(rlm); | |
1401 | __CFRunLoopTimerLock(rlt); | |
1402 | if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) { | |
d8925383 | 1403 | __CFRunLoopTimerUnsetDidFire(rlt); |
9ce05555 A |
1404 | __CFRunLoopTimerSetFiring(rlt); |
1405 | __CFRunLoopTimerUnlock(rlt); | |
1406 | __CFRunLoopTimerFireTSRLock(); | |
1407 | oldFireTSR = rlt->_fireTSR; | |
1408 | __CFRunLoopTimerFireTSRUnlock(); | |
1409 | rlt->_callout(rlt, rlt->_context.info); /* CALLOUT */ | |
bd5b749c | 1410 | CHECK_FOR_FORK(); |
9ce05555 A |
1411 | __CFRunLoopTimerUnsetFiring(rlt); |
1412 | timerHandled = true; | |
1413 | } else { | |
d8925383 A |
1414 | // If the timer fires while it is firing in a higher activiation, |
1415 | // it is not allowed to fire, but we have to remember that fact. | |
1416 | // Later, if the timer's fire date is being handled manually, we | |
1417 | // need to re-arm the kernel timer, since it has possibly already | |
1418 | // fired (this firing which is being skipped, say) and the timer | |
1419 | // will permanently stop if we completely drop this firing. | |
1420 | if (__CFRunLoopTimerIsFiring(rlt)) __CFRunLoopTimerSetDidFire(rlt); | |
9ce05555 A |
1421 | __CFRunLoopTimerUnlock(rlt); |
1422 | } | |
1423 | if (__CFIsValid(rlt) && timerHandled) { | |
1424 | if (0 == rlt->_intervalTSR) { | |
1425 | CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ | |
1426 | } else { | |
1427 | /* This is just a little bit tricky: we want to support calling | |
1428 | * CFRunLoopTimerSetNextFireDate() from within the callout and | |
1429 | * honor that new time here if it is a later date, otherwise | |
1430 | * it is completely ignored. */ | |
1431 | int64_t currentFireTSR; | |
1432 | __CFRunLoopTimerFireTSRLock(); | |
1433 | currentFireTSR = rlt->_fireTSR; | |
1434 | if (oldFireTSR < currentFireTSR) { | |
1435 | /* Next fire TSR was set, and set to a date after the previous | |
1436 | * fire date, so we honor it. */ | |
d8925383 A |
1437 | if (__CFRunLoopTimerDidFire(rlt)) { |
1438 | __CFRunLoopTimerRescheduleWithAllModes(rlt, rl); | |
1439 | __CFRunLoopTimerUnsetDidFire(rlt); | |
1440 | } | |
9ce05555 A |
1441 | } else { |
1442 | if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) { | |
1443 | currentFireTSR = LLONG_MAX; | |
1444 | } else { | |
1445 | int64_t currentTSR = (int64_t)__CFReadTSR(); | |
1446 | currentFireTSR = oldFireTSR; | |
1447 | while (currentFireTSR <= currentTSR) { | |
1448 | currentFireTSR += rlt->_intervalTSR; | |
1449 | } | |
1450 | } | |
d8925383 A |
1451 | rlt->_fireTSR = currentFireTSR; |
1452 | __CFRunLoopTimerRescheduleWithAllModes(rlt, rl); | |
9ce05555 | 1453 | } |
9ce05555 | 1454 | __CFRunLoopTimerFireTSRUnlock(); |
9ce05555 A |
1455 | } |
1456 | } | |
1457 | CFRelease(rlt); | |
1458 | __CFRunLoopModeLock(rlm); | |
1459 | return timerHandled; | |
1460 | } | |
1461 | ||
1462 | CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) { | |
bd5b749c | 1463 | CHECK_FOR_FORK(); |
9ce05555 A |
1464 | CFRunLoopModeRef rlm; |
1465 | Boolean result = false; | |
1466 | __CFRunLoopLock(rl); | |
1467 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
1468 | if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm)) { | |
1469 | result = true; | |
1470 | } | |
1471 | __CFRunLoopUnlock(rl); | |
1472 | if (rlm) __CFRunLoopModeUnlock(rlm); | |
1473 | return result; | |
1474 | } | |
1475 | ||
1476 | // rl is locked, rlm is locked on entry and exit | |
d8925383 | 1477 | static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPortSet portSet) { |
9ce05555 A |
1478 | CFIndex idx, cnt; |
1479 | const void **list, *buffer[256]; | |
1480 | ||
1481 | // Timers and version 1 sources go into the portSet currently | |
1482 | if (NULL != rlm->_sources) { | |
1483 | cnt = CFSetGetCount(rlm->_sources); | |
1484 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
1485 | CFSetGetValues(rlm->_sources, list); | |
1486 | for (idx = 0; idx < cnt; idx++) { | |
1487 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; | |
d8925383 A |
1488 | if (1 == rls->_context.version0.version) { |
1489 | __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ | |
1490 | if (CFPORT_NULL != port) { | |
1491 | __CFPortSetInsert(port, portSet); | |
1492 | } | |
9ce05555 A |
1493 | } |
1494 | } | |
1495 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1496 | } | |
bd5b749c | 1497 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
1498 | if (NULL != rlm->_timers) { |
1499 | cnt = CFSetGetCount(rlm->_timers); | |
1500 | list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); | |
1501 | CFSetGetValues(rlm->_timers, list); | |
1502 | for (idx = 0; idx < cnt; idx++) { | |
1503 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx]; | |
1504 | if (MACH_PORT_NULL != rlt->_port) { | |
1505 | mach_port_insert_member(mach_task_self(), rlt->_port, portSet); | |
1506 | } | |
1507 | } | |
1508 | if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); | |
1509 | } | |
d8925383 | 1510 | #endif |
9ce05555 A |
1511 | // iterate over submodes |
1512 | for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) { | |
1513 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
1514 | CFRunLoopModeRef subrlm; | |
1515 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1516 | if (NULL != subrlm) { | |
1517 | __CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet); | |
1518 | __CFRunLoopModeUnlock(subrlm); | |
1519 | } | |
1520 | } | |
1521 | } | |
d8925383 | 1522 | |
bd5b749c | 1523 | static __CFPortSet _LastMainWaitSet = 0; |
d8925383 A |
1524 | |
1525 | // return NO if we're the main runloop and there are no messages waiting on the port set | |
1526 | int _CFRunLoopInputsReady(void) { | |
bd5b749c | 1527 | CHECK_FOR_FORK(); |
d8925383 A |
1528 | // XXX_PCB: the following 2 lines aren't safe to call during GC, because another |
1529 | // thread may have entered CFRunLoopGetMain(), which grabs a spink lock, and then | |
1530 | // is suspended by the GC. We can check for the main thread more directly | |
1531 | // by calling pthread_main_np(). | |
1532 | // CFRunLoopRef current = CFRunLoopGetMain() | |
1533 | // if (current != CFRunLoopGetMain()) return true; | |
bd5b749c | 1534 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 | 1535 | if (!pthread_main_np()) return true; |
9ce05555 | 1536 | |
d8925383 A |
1537 | // XXX_PCB: can't be any messages waiting if the wait set is NULL. |
1538 | if (_LastMainWaitSet == MACH_PORT_NULL) return false; | |
1539 | ||
1540 | // prepare a message header with no space for any data, nor a trailer | |
1541 | mach_msg_header_t msg; | |
1542 | msg.msgh_size = sizeof(msg); // just the header, ma'am | |
1543 | // need the waitset, actually XXX | |
1544 | msg.msgh_local_port = _LastMainWaitSet; | |
1545 | msg.msgh_remote_port = MACH_PORT_NULL; | |
1546 | msg.msgh_id = 0; | |
1547 | ||
1548 | 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); | |
1549 | ||
1550 | return (MACH_RCV_TOO_LARGE == ret); | |
bd5b749c A |
1551 | #endif |
1552 | return true; | |
1553 | } | |
1554 | ||
1555 | #if 0 | |
1556 | static void print_msg_scan_header(void) { | |
1557 | printf("======== ======== ======== ========\n"); | |
1558 | printf("description\tport\tport type\t\treferences\n"); | |
1559 | } | |
1560 | ||
1561 | static void print_one_port_info(const char *desc, mach_port_t port, mach_msg_type_name_t type) { | |
1562 | mach_port_urefs_t refs; | |
1563 | kern_return_t ret = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs); | |
1564 | if (ret != KERN_SUCCESS) refs = 0; | |
1565 | const char *type_name = "???"; | |
1566 | switch (type) { | |
1567 | case MACH_MSG_TYPE_MOVE_SEND: type_name = "MACH_MSG_TYPE_MOVE_SEND"; break; | |
1568 | case MACH_MSG_TYPE_MOVE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break; | |
1569 | case MACH_MSG_TYPE_MOVE_RECEIVE: type_name = "MACH_MSG_TYPE_MOVE_RECEIVE"; break; | |
1570 | case MACH_MSG_TYPE_MAKE_SEND: type_name = "MACH_MSG_TYPE_MAKE_SEND"; break; | |
1571 | case MACH_MSG_TYPE_MAKE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break; | |
1572 | } | |
1573 | printf("%s\t%p\t%-20s\t%u\n", desc, port, type_name, refs); | |
1574 | } | |
1575 | ||
1576 | static void mach_msg_scan(mach_msg_header_t *msg, int clean) { | |
1577 | Boolean printed_header = false; | |
1578 | /* | |
1579 | * The msgh_local_port field doesn't hold a port right. | |
1580 | * The receive operation consumes the destination port right. | |
1581 | */ | |
1582 | if (MACH_PORT_NULL != msg->msgh_remote_port) { | |
1583 | if (! printed_header) print_msg_scan_header(); | |
1584 | printed_header = true; | |
1585 | print_one_port_info("msg->msgh_remote_port", msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(msg->msgh_bits)); | |
1586 | } | |
1587 | if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) { | |
1588 | mach_msg_body_t *body = (mach_msg_body_t *) (msg + 1); | |
1589 | mach_msg_descriptor_t *saddr = (mach_msg_descriptor_t *) ((mach_msg_base_t *) msg + 1); | |
1590 | mach_msg_descriptor_t *eaddr = saddr + body->msgh_descriptor_count; | |
1591 | for ( ; saddr < eaddr; saddr++) { | |
1592 | switch (saddr->type.type) { | |
1593 | case MACH_MSG_PORT_DESCRIPTOR:; | |
1594 | mach_msg_port_descriptor_t *dsc = &saddr->port; | |
1595 | if (! printed_header) print_msg_scan_header(); | |
1596 | printed_header = true; | |
1597 | print_one_port_info("port in body", dsc->name, dsc->disposition); | |
1598 | // if (clean) mach_port_deallocate(mach_task_self(), dsc->name); | |
1599 | break; | |
1600 | case MACH_MSG_OOL_PORTS_DESCRIPTOR:; | |
1601 | mach_msg_ool_ports_descriptor_t *dsc2 = &saddr->ool_ports; | |
1602 | mach_port_t *ports = (mach_port_t *) dsc2->address; | |
1603 | for (mach_msg_type_number_t j = 0; j < dsc2->count; j++, ports++) { | |
1604 | if (! printed_header) print_msg_scan_header(); | |
1605 | printed_header = true; | |
1606 | print_one_port_info("port in OOL ports", *ports, dsc2->disposition); | |
1607 | } | |
1608 | break; | |
1609 | } | |
1610 | } | |
1611 | } | |
d8925383 | 1612 | } |
bd5b749c | 1613 | #endif |
d8925383 | 1614 | |
9ce05555 A |
1615 | /* rl is unlocked, rlm locked on entrance and exit */ |
1616 | static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, Boolean waitIfEmpty) { /* DOES CALLOUT */ | |
1617 | int64_t termTSR; | |
bd5b749c | 1618 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
1619 | mach_port_name_t timeoutPort = MACH_PORT_NULL; |
1620 | Boolean timeoutPortAdded = false; | |
9ce05555 A |
1621 | #endif |
1622 | Boolean poll = false; | |
d8925383 | 1623 | Boolean firstPass = true; |
9ce05555 A |
1624 | |
1625 | if (__CFRunLoopIsStopped(rl)) { | |
1626 | return kCFRunLoopRunStopped; | |
1627 | } else if (rlm->_stopped) { | |
1628 | rlm->_stopped = false; | |
1629 | return kCFRunLoopRunStopped; | |
1630 | } | |
9ce05555 A |
1631 | if (seconds <= 0.0) { |
1632 | termTSR = 0; | |
bd5b749c | 1633 | } else if (3.1556952e+9 < seconds) { |
9ce05555 A |
1634 | termTSR = LLONG_MAX; |
1635 | } else { | |
1636 | termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds); | |
bd5b749c | 1637 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
1638 | timeoutPort = mk_timer_create(); |
1639 | mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR)); | |
9ce05555 | 1640 | #endif |
d8925383 | 1641 | } |
9ce05555 A |
1642 | if (seconds <= 0.0) { |
1643 | poll = true; | |
1644 | } | |
5645d61f | 1645 | if (rl == CFRunLoopGetMain()) _LastMainWaitSet = CFPORT_NULL; |
9ce05555 | 1646 | for (;;) { |
d8925383 A |
1647 | __CFPortSet waitSet = CFPORT_NULL; |
1648 | waitSet = CFPORT_NULL; | |
1649 | Boolean destroyWaitSet = false; | |
1650 | CFRunLoopSourceRef rls; | |
bd5b749c | 1651 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
1652 | mach_msg_header_t *msg; |
1653 | kern_return_t ret; | |
bd5b749c | 1654 | uint8_t buffer[1024 + 80] = {0}; // large enough for 1k of inline payload; must be zeroed for GC |
d8925383 A |
1655 | #else |
1656 | CFArrayRef timersToCall = NULL; | |
9ce05555 | 1657 | #endif |
9ce05555 A |
1658 | int32_t returnValue = 0; |
1659 | Boolean sourceHandledThisLoop = false; | |
9ce05555 A |
1660 | |
1661 | __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); | |
1662 | __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); | |
1663 | ||
1664 | sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle); | |
1665 | ||
1666 | if (sourceHandledThisLoop) { | |
1667 | poll = true; | |
1668 | } | |
1669 | ||
1670 | if (!poll) { | |
1671 | __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); | |
1672 | __CFRunLoopSetSleeping(rl); | |
1673 | } | |
9ce05555 A |
1674 | if (NULL != rlm->_submodes) { |
1675 | // !!! what do we do if this doesn't succeed? | |
d8925383 A |
1676 | waitSet = __CFPortSetAllocate(); |
1677 | if (CFPORT_NULL == waitSet) HALT; | |
9ce05555 A |
1678 | __CFRunLoopModeUnlock(rlm); |
1679 | __CFRunLoopLock(rl); | |
1680 | __CFRunLoopModeLock(rlm); | |
1681 | __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet); | |
1682 | __CFRunLoopUnlock(rl); | |
bd5b749c | 1683 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
1684 | if (CFPORT_NULL != timeoutPort) { |
1685 | __CFPortSetInsert(timeoutPort, waitSet); | |
9ce05555 | 1686 | } |
d8925383 A |
1687 | #endif |
1688 | destroyWaitSet = true; | |
9ce05555 A |
1689 | } else { |
1690 | waitSet = rlm->_portSet; | |
bd5b749c | 1691 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
1692 | if (!timeoutPortAdded && CFPORT_NULL != timeoutPort) { |
1693 | __CFPortSetInsert(timeoutPort, waitSet); | |
9ce05555 A |
1694 | timeoutPortAdded = true; |
1695 | } | |
d8925383 | 1696 | #endif |
9ce05555 | 1697 | } |
5645d61f | 1698 | if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet; |
9ce05555 A |
1699 | __CFRunLoopModeUnlock(rlm); |
1700 | ||
bd5b749c | 1701 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 | 1702 | msg = (mach_msg_header_t *)buffer; |
9ce05555 A |
1703 | msg->msgh_size = sizeof(buffer); |
1704 | ||
1705 | /* In that sleep of death what nightmares may come ... */ | |
1706 | try_receive: | |
1707 | msg->msgh_bits = 0; | |
1708 | msg->msgh_local_port = waitSet; | |
1709 | msg->msgh_remote_port = MACH_PORT_NULL; | |
1710 | msg->msgh_id = 0; | |
9ce05555 | 1711 | ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|(poll ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL); |
9ce05555 | 1712 | if (MACH_RCV_TOO_LARGE == ret) { |
9ce05555 | 1713 | uint32_t newSize = round_msg(msg->msgh_size) + sizeof(mach_msg_audit_trailer_t); |
9ce05555 A |
1714 | if (msg == (mach_msg_header_t *)buffer) msg = NULL; |
1715 | msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0); | |
1716 | msg->msgh_size = newSize; | |
1717 | goto try_receive; | |
1718 | } else if (MACH_RCV_TIMED_OUT == ret) { | |
1719 | // timeout, for poll | |
1720 | if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); | |
1721 | msg = NULL; | |
1722 | } else if (MACH_MSG_SUCCESS != ret) { | |
1723 | HALT; | |
1724 | } | |
d8925383 | 1725 | #elif defined(__WIN32__) |
d8925383 A |
1726 | DWORD waitResult = WAIT_TIMEOUT; |
1727 | HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; | |
1728 | HANDLE *handles; | |
1729 | uint32_t handleCount; | |
1730 | Boolean freeHandles; | |
1731 | if (destroyWaitSet) { | |
1732 | // wait set is a local, no one else could modify it, no need to copy handles | |
1733 | handles = waitSet->handles; | |
1734 | handleCount = waitSet->used; | |
1735 | freeHandles = FALSE; | |
1736 | } else { | |
1737 | // copy out the handles to be safe from other threads at work | |
1738 | handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount); | |
1739 | freeHandles = (handles != handleBuf); | |
1740 | } | |
1741 | // should msgQMask be an OR'ing of this and all submodes' masks? | |
9ce05555 | 1742 | if (0 == GetQueueStatus(rlm->_msgQMask)) { |
d8925383 A |
1743 | DWORD timeout; |
1744 | if (poll) | |
1745 | timeout = 0; | |
1746 | else { | |
bd5b749c | 1747 | __CFRunLoopModeLock(rlm); |
d8925383 A |
1748 | int64_t nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm); |
1749 | if (nextStop <= 0) | |
1750 | nextStop = termTSR; | |
1751 | else if (nextStop > termTSR) | |
1752 | nextStop = termTSR; | |
1753 | // else the next stop is dictated by the next timer | |
1754 | int64_t timeoutTSR = nextStop - __CFReadTSR(); | |
1755 | if (timeoutTSR < 0) | |
1756 | timeout = 0; | |
1757 | else { | |
1758 | CFTimeInterval timeoutCF = __CFTSRToTimeInterval(timeoutTSR) * 1000; | |
1759 | if (timeoutCF > MAXDWORD) | |
1760 | timeout = INFINITE; | |
1761 | else | |
1762 | timeout = timeoutCF; | |
1763 | } | |
1764 | } | |
bd5b749c A |
1765 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- about to wait for %d objects, wakeupport is %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), handleCount, rl->_wakeUpPort); } |
1766 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("All RLM sources = %@"), rlm->_sources); } | |
1767 | waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout, rlm->_msgQMask); | |
1768 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- waitResult was %d"), CFRunLoopGetCurrent(), *_CFGetProgname(), waitResult); } | |
d8925383 A |
1769 | } |
1770 | ResetEvent(rl->_wakeUpPort); | |
9ce05555 | 1771 | #endif |
9ce05555 | 1772 | if (destroyWaitSet) { |
d8925383 | 1773 | __CFPortSetFree(waitSet); |
5645d61f | 1774 | if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0; |
9ce05555 | 1775 | } |
9ce05555 A |
1776 | __CFRunLoopLock(rl); |
1777 | __CFRunLoopModeLock(rlm); | |
1778 | __CFRunLoopUnlock(rl); | |
1779 | if (!poll) { | |
1780 | __CFRunLoopUnsetSleeping(rl); | |
1781 | __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); | |
1782 | } | |
1783 | poll = false; | |
1784 | __CFRunLoopModeUnlock(rlm); | |
1785 | __CFRunLoopLock(rl); | |
1786 | __CFRunLoopModeLock(rlm); | |
1787 | ||
d8925383 | 1788 | __CFPort livePort = CFPORT_NULL; |
bd5b749c | 1789 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 | 1790 | if (NULL != msg) { |
d8925383 A |
1791 | livePort = msg->msgh_local_port; |
1792 | } | |
1793 | #elif defined(__WIN32__) | |
1794 | CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError()); | |
1795 | if (waitResult == WAIT_TIMEOUT) { | |
1796 | // do nothing, just return to caller | |
1797 | } else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) { | |
bd5b749c | 1798 | // a handle was signalled |
d8925383 | 1799 | livePort = handles[waitResult-WAIT_OBJECT_0]; |
bd5b749c | 1800 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- Resetting event %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), livePort); } |
d8925383 A |
1801 | } else if (waitResult == WAIT_OBJECT_0+handleCount) { |
1802 | // windows message received - the CFWindowsMessageQueue will pick this up when | |
1803 | // the v0 RunLoopSources get their chance | |
1804 | } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) { | |
1805 | // an "abandoned mutex object" | |
1806 | livePort = handles[waitResult-WAIT_ABANDONED_0]; | |
1807 | } else { | |
1808 | CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult); | |
1809 | } | |
1810 | if (freeHandles) | |
1811 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles); | |
1812 | timersToCall = __CFRunLoopTimersToFire(rl, rlm); | |
1813 | #endif | |
1814 | ||
1815 | if (CFPORT_NULL == livePort) { | |
1816 | __CFRunLoopUnlock(rl); | |
d8925383 A |
1817 | } else if (livePort == rl->_wakeUpPort) { |
1818 | // wakeup | |
bd5b749c | 1819 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("wakeupPort was signalled")); } |
d8925383 A |
1820 | __CFRunLoopUnlock(rl); |
1821 | } | |
bd5b749c | 1822 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
1823 | else if (livePort == timeoutPort) { |
1824 | returnValue = kCFRunLoopRunTimedOut; | |
1825 | __CFRunLoopUnlock(rl); | |
1826 | } else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) { | |
1827 | mach_msg_header_t *reply = NULL; | |
1828 | __CFRunLoopUnlock(rl); | |
bd5b749c | 1829 | // mach_msg_scan(msg, 0); |
d8925383 A |
1830 | if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) { |
1831 | sourceHandledThisLoop = true; | |
1832 | } | |
bd5b749c | 1833 | // mach_msg_scan(msg, 1); |
d8925383 A |
1834 | if (NULL != reply) { |
1835 | ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); | |
9ce05555 | 1836 | //#warning CF: what should be done with the return value? |
d8925383 | 1837 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); |
9ce05555 | 1838 | } |
9ce05555 | 1839 | } else { |
d8925383 A |
1840 | CFRunLoopTimerRef rlt; |
1841 | rlt = __CFRunLoopModeFindTimerForMachPort(rlm, livePort); | |
1842 | __CFRunLoopUnlock(rl); | |
1843 | if (NULL != rlt) { | |
1844 | __CFRunLoopDoTimer(rl, rlm, rlt); | |
1845 | } | |
1846 | } | |
1847 | if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); | |
1848 | #else | |
1849 | else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) { | |
9ce05555 | 1850 | __CFRunLoopUnlock(rl); |
bd5b749c | 1851 | if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("Source %@ was signalled"), rls); } |
d8925383 A |
1852 | if (__CFRunLoopDoSource1(rl, rlm, rls)) { |
1853 | sourceHandledThisLoop = true; | |
1854 | } | |
1855 | } | |
1856 | #endif | |
1857 | ||
9ce05555 A |
1858 | __CFRunLoopModeUnlock(rlm); // locks must be taken in order |
1859 | __CFRunLoopLock(rl); | |
1860 | __CFRunLoopModeLock(rlm); | |
1861 | if (sourceHandledThisLoop && stopAfterHandle) { | |
1862 | returnValue = kCFRunLoopRunHandledSource; | |
d8925383 A |
1863 | // If we're about to timeout, but we just did a zero-timeout poll that only found our own |
1864 | // internal wakeup signal on the first look at the portset, we'll go around the loop one | |
1865 | // more time, so as not to starve a v1 source that was just added along with a runloop wakeup. | |
1866 | } else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) { | |
9ce05555 A |
1867 | returnValue = kCFRunLoopRunTimedOut; |
1868 | } else if (__CFRunLoopIsStopped(rl)) { | |
1869 | returnValue = kCFRunLoopRunStopped; | |
1870 | } else if (rlm->_stopped) { | |
1871 | rlm->_stopped = false; | |
1872 | returnValue = kCFRunLoopRunStopped; | |
1873 | } else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm)) { | |
1874 | returnValue = kCFRunLoopRunFinished; | |
1875 | } | |
1876 | __CFRunLoopUnlock(rl); | |
1877 | if (0 != returnValue) { | |
bd5b749c | 1878 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 | 1879 | if (MACH_PORT_NULL != timeoutPort) { |
d8925383 | 1880 | if (!destroyWaitSet) __CFPortSetRemove(timeoutPort, waitSet); |
9ce05555 A |
1881 | mk_timer_destroy(timeoutPort); |
1882 | } | |
1883 | #endif | |
1884 | return returnValue; | |
1885 | } | |
d8925383 | 1886 | firstPass = false; |
9ce05555 A |
1887 | } |
1888 | } | |
1889 | ||
9ce05555 | 1890 | SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ |
bd5b749c | 1891 | CHECK_FOR_FORK(); |
9ce05555 A |
1892 | if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished; |
1893 | __CFRunLoopLock(rl); | |
bd5b749c | 1894 | CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false); |
9ce05555 A |
1895 | if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode)) { |
1896 | if (currentMode) __CFRunLoopModeUnlock(currentMode); | |
1897 | __CFRunLoopUnlock(rl); | |
1898 | return kCFRunLoopRunFinished; | |
1899 | } | |
bd5b749c A |
1900 | uint32_t *previousStopped = (uint32_t *)rl->_stopped; |
1901 | rl->_stopped = CFAllocatorAllocate(kCFAllocatorSystemDefault, 4 * sizeof(uint32_t), 0); | |
9ce05555 A |
1902 | rl->_stopped[0] = 0x4346524C; |
1903 | rl->_stopped[1] = 0x4346524C; // 'CFRL' | |
1904 | rl->_stopped[2] = 0x00000000; // here the value is stored | |
1905 | rl->_stopped[3] = 0x4346524C; | |
bd5b749c | 1906 | CFRunLoopModeRef previousMode = rl->_currentMode; |
9ce05555 A |
1907 | rl->_currentMode = currentMode; |
1908 | __CFRunLoopUnlock(rl); | |
bd5b749c | 1909 | int32_t result; |
9ce05555 A |
1910 | __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); |
1911 | result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, false); | |
1912 | __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); | |
1913 | __CFRunLoopModeUnlock(currentMode); | |
1914 | __CFRunLoopLock(rl); | |
bd5b749c | 1915 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, (uint32_t *)rl->_stopped); |
9ce05555 A |
1916 | rl->_stopped = previousStopped; |
1917 | rl->_currentMode = previousMode; | |
1918 | __CFRunLoopUnlock(rl); | |
1919 | return result; | |
1920 | } | |
1921 | ||
d8925383 A |
1922 | void CFRunLoopRun(void) { /* DOES CALLOUT */ |
1923 | int32_t result; | |
1924 | do { | |
1925 | result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false); | |
bd5b749c | 1926 | CHECK_FOR_FORK(); |
d8925383 A |
1927 | } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); |
1928 | } | |
1929 | ||
9ce05555 | 1930 | SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ |
bd5b749c | 1931 | CHECK_FOR_FORK(); |
9ce05555 A |
1932 | return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled); |
1933 | } | |
1934 | ||
1935 | static void __CFRunLoopFindMinTimer(const void *value, void *ctx) { | |
1936 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value; | |
d8925383 A |
1937 | if (__CFIsValid(rlt)) { |
1938 | CFRunLoopTimerRef *result = ctx; | |
1939 | if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) { | |
1940 | *result = rlt; | |
1941 | } | |
9ce05555 A |
1942 | } |
1943 | } | |
1944 | ||
d8925383 | 1945 | static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm) { |
9ce05555 A |
1946 | CFRunLoopTimerRef result = NULL; |
1947 | int64_t fireTime = 0; | |
9ce05555 A |
1948 | if (rlm) { |
1949 | if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { | |
1950 | __CFRunLoopTimerFireTSRLock(); | |
1951 | CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result); | |
d8925383 A |
1952 | if (result) |
1953 | fireTime = result->_fireTSR; | |
9ce05555 A |
1954 | __CFRunLoopTimerFireTSRUnlock(); |
1955 | } | |
d8925383 A |
1956 | if (NULL != rlm->_submodes) { |
1957 | CFIndex idx, cnt; | |
1958 | for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { | |
1959 | CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); | |
1960 | CFRunLoopModeRef subrlm; | |
1961 | subrlm = __CFRunLoopFindMode(rl, modeName, false); | |
1962 | if (NULL != subrlm) { | |
1963 | int64_t newFireTime = __CFRunLoopGetNextTimerFireTSR(rl, subrlm); | |
1964 | __CFRunLoopModeUnlock(subrlm); | |
1965 | if (fireTime == 0 || (newFireTime != 0 && newFireTime < fireTime)) | |
1966 | fireTime = newFireTime; | |
1967 | } | |
1968 | } | |
1969 | } | |
1970 | __CFRunLoopModeUnlock(rlm); | |
bd5b749c | 1971 | } |
d8925383 A |
1972 | return fireTime; |
1973 | } | |
1974 | ||
1975 | CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) { | |
bd5b749c | 1976 | CHECK_FOR_FORK(); |
d8925383 A |
1977 | CFRunLoopModeRef rlm; |
1978 | int64_t fireTSR; | |
1979 | __CFRunLoopLock(rl); | |
1980 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
1981 | __CFRunLoopUnlock(rl); | |
1982 | fireTSR = __CFRunLoopGetNextTimerFireTSR(rl, rlm); | |
1983 | int64_t now2 = (int64_t)mach_absolute_time(); | |
1984 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
1985 | return (0 == fireTSR) ? 0.0 : (now1 + __CFTSRToTimeInterval(fireTSR - now2)); | |
9ce05555 A |
1986 | } |
1987 | ||
1988 | Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) { | |
bd5b749c | 1989 | CHECK_FOR_FORK(); |
9ce05555 A |
1990 | return __CFRunLoopIsSleeping(rl); |
1991 | } | |
1992 | ||
1993 | void CFRunLoopWakeUp(CFRunLoopRef rl) { | |
bd5b749c A |
1994 | CHECK_FOR_FORK(); |
1995 | #if DEPLOYMENT_TARGET_MACOSX | |
9ce05555 A |
1996 | kern_return_t ret; |
1997 | /* We unconditionally try to send the message, since we don't want | |
1998 | * to lose a wakeup, but the send may fail if there is already a | |
1999 | * wakeup pending, since the queue length is 1. */ | |
d8925383 | 2000 | ret = __CFSendTrivialMachMessage(rl->_wakeUpPort, 0, MACH_SEND_TIMEOUT, 0); |
9ce05555 A |
2001 | if (ret != MACH_MSG_SUCCESS && ret != MACH_SEND_TIMED_OUT) { |
2002 | HALT; | |
2003 | } | |
2004 | #else | |
d8925383 | 2005 | SetEvent(rl->_wakeUpPort); |
9ce05555 A |
2006 | #endif |
2007 | } | |
2008 | ||
2009 | void CFRunLoopStop(CFRunLoopRef rl) { | |
bd5b749c | 2010 | CHECK_FOR_FORK(); |
9ce05555 A |
2011 | __CFRunLoopLock(rl); |
2012 | __CFRunLoopSetStopped(rl); | |
2013 | __CFRunLoopUnlock(rl); | |
2014 | CFRunLoopWakeUp(rl); | |
2015 | } | |
2016 | ||
2017 | CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) { | |
bd5b749c | 2018 | CHECK_FOR_FORK(); |
9ce05555 A |
2019 | CFRunLoopModeRef rlm; |
2020 | __CFRunLoopLock(rl); | |
2021 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2022 | __CFRunLoopUnlock(rl); | |
2023 | if (NULL != rlm) { | |
2024 | rlm->_stopped = true; | |
2025 | __CFRunLoopModeUnlock(rlm); | |
2026 | } | |
2027 | CFRunLoopWakeUp(rl); | |
2028 | } | |
2029 | ||
2030 | CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) { | |
bd5b749c | 2031 | CHECK_FOR_FORK(); |
9ce05555 A |
2032 | CFRunLoopModeRef rlm; |
2033 | if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) { | |
2034 | return false; | |
2035 | } else if (CFEqual(modeName, candidateContainedName)) { | |
2036 | return true; | |
2037 | } | |
2038 | __CFRunLoopLock(rl); | |
2039 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2040 | __CFRunLoopUnlock(rl); | |
2041 | if (NULL != rlm) { | |
2042 | CFArrayRef submodes; | |
2043 | if (NULL == rlm->_submodes) { | |
2044 | __CFRunLoopModeUnlock(rlm); | |
2045 | return false; | |
2046 | } | |
2047 | if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) { | |
2048 | __CFRunLoopModeUnlock(rlm); | |
2049 | return true; | |
2050 | } | |
2051 | submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; | |
2052 | __CFRunLoopModeUnlock(rlm); | |
2053 | if (NULL != submodes) { | |
2054 | CFIndex idx, cnt; | |
2055 | for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) { | |
2056 | CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx); | |
2057 | if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) { | |
2058 | CFRelease(submodes); | |
2059 | return true; | |
2060 | } | |
2061 | } | |
2062 | CFRelease(submodes); | |
2063 | } | |
2064 | } | |
2065 | return false; | |
2066 | } | |
2067 | ||
2068 | CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) { | |
bd5b749c | 2069 | CHECK_FOR_FORK(); |
9ce05555 A |
2070 | CFRunLoopModeRef rlm; |
2071 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2072 | // should really do a recursive check here, to make sure that a cycle isn't | |
2073 | // introduced; of course, if that happens, you aren't going to get very far. | |
2074 | if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) { | |
2075 | return; | |
2076 | } else { | |
2077 | __CFRunLoopLock(rl); | |
2078 | rlm = __CFRunLoopFindMode(rl, toModeName, true); | |
2079 | __CFRunLoopUnlock(rl); | |
2080 | if (NULL != rlm) { | |
2081 | if (NULL == rlm->_submodes) { | |
2082 | rlm->_submodes = CFArrayCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeArrayCallBacks); | |
2083 | } | |
2084 | if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) { | |
2085 | CFArrayAppendValue(rlm->_submodes, modeName); | |
2086 | } | |
2087 | __CFRunLoopModeUnlock(rlm); | |
2088 | } | |
2089 | } | |
2090 | } | |
2091 | ||
2092 | CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) { | |
bd5b749c | 2093 | CHECK_FOR_FORK(); |
9ce05555 A |
2094 | CFRunLoopModeRef rlm; |
2095 | // should really do a recursive check here, to make sure that a cycle isn't | |
2096 | // introduced; of course, if that happens, you aren't going to get very far. | |
2097 | if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) { | |
2098 | return; | |
2099 | } else { | |
2100 | __CFRunLoopLock(rl); | |
2101 | rlm = __CFRunLoopFindMode(rl, fromModeName, true); | |
2102 | __CFRunLoopUnlock(rl); | |
2103 | if (NULL != rlm) { | |
2104 | if (NULL != rlm->_submodes) { | |
2105 | CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes); | |
2106 | idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName); | |
2107 | if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx); | |
2108 | } | |
2109 | __CFRunLoopModeUnlock(rlm); | |
2110 | } | |
2111 | } | |
2112 | } | |
2113 | ||
2114 | Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { | |
bd5b749c | 2115 | CHECK_FOR_FORK(); |
9ce05555 A |
2116 | CFRunLoopModeRef rlm; |
2117 | Boolean hasValue = false; | |
2118 | __CFRunLoopLock(rl); | |
2119 | if (modeName == kCFRunLoopCommonModes) { | |
2120 | if (NULL != rl->_commonModeItems) { | |
2121 | hasValue = CFSetContainsValue(rl->_commonModeItems, rls); | |
2122 | } | |
2123 | __CFRunLoopUnlock(rl); | |
2124 | } else { | |
2125 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2126 | __CFRunLoopUnlock(rl); | |
2127 | if (NULL != rlm && NULL != rlm->_sources) { | |
2128 | hasValue = CFSetContainsValue(rlm->_sources, rls); | |
2129 | __CFRunLoopModeUnlock(rlm); | |
2130 | } else if (NULL != rlm) { | |
2131 | __CFRunLoopModeUnlock(rlm); | |
2132 | } | |
2133 | } | |
2134 | return hasValue; | |
2135 | } | |
2136 | ||
2137 | void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ | |
bd5b749c | 2138 | CHECK_FOR_FORK(); |
9ce05555 A |
2139 | CFRunLoopModeRef rlm; |
2140 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2141 | if (!__CFIsValid(rls)) return; | |
2142 | __CFRunLoopLock(rl); | |
2143 | if (modeName == kCFRunLoopCommonModes) { | |
2144 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2145 | if (NULL == rl->_commonModeItems) { | |
2146 | rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks); | |
2147 | _CFSetSetCapacity(rl->_commonModeItems, 20); | |
2148 | } | |
2149 | CFSetAddValue(rl->_commonModeItems, rls); | |
2150 | __CFRunLoopUnlock(rl); | |
2151 | if (NULL != set) { | |
2152 | CFTypeRef context[2] = {rl, rls}; | |
2153 | /* add new item to all common-modes */ | |
2154 | CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); | |
2155 | CFRelease(set); | |
2156 | } | |
2157 | } else { | |
2158 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2159 | __CFRunLoopUnlock(rl); | |
2160 | if (NULL != rlm && NULL == rlm->_sources) { | |
2161 | rlm->_sources = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks); | |
2162 | _CFSetSetCapacity(rlm->_sources, 10); | |
2163 | } | |
2164 | if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) { | |
2165 | CFSetAddValue(rlm->_sources, rls); | |
2166 | __CFRunLoopModeUnlock(rlm); | |
2167 | __CFRunLoopSourceSchedule(rls, rl, rlm); /* DOES CALLOUT */ | |
2168 | } else if (NULL != rlm) { | |
2169 | __CFRunLoopModeUnlock(rlm); | |
2170 | } | |
2171 | } | |
2172 | } | |
2173 | ||
2174 | void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ | |
bd5b749c | 2175 | CHECK_FOR_FORK(); |
9ce05555 A |
2176 | CFRunLoopModeRef rlm; |
2177 | __CFRunLoopLock(rl); | |
2178 | if (modeName == kCFRunLoopCommonModes) { | |
2179 | if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) { | |
2180 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2181 | CFSetRemoveValue(rl->_commonModeItems, rls); | |
2182 | __CFRunLoopUnlock(rl); | |
2183 | if (NULL != set) { | |
2184 | CFTypeRef context[2] = {rl, rls}; | |
2185 | /* remove new item from all common-modes */ | |
2186 | CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context); | |
2187 | CFRelease(set); | |
2188 | } | |
2189 | } else { | |
2190 | __CFRunLoopUnlock(rl); | |
2191 | } | |
2192 | } else { | |
2193 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2194 | __CFRunLoopUnlock(rl); | |
2195 | if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) { | |
2196 | CFRetain(rls); | |
2197 | CFSetRemoveValue(rlm->_sources, rls); | |
2198 | __CFRunLoopModeUnlock(rlm); | |
2199 | __CFRunLoopSourceCancel(rls, rl, rlm); /* DOES CALLOUT */ | |
2200 | CFRelease(rls); | |
2201 | } else if (NULL != rlm) { | |
2202 | __CFRunLoopModeUnlock(rlm); | |
2203 | } | |
2204 | } | |
2205 | } | |
2206 | ||
5645d61f A |
2207 | static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) { |
2208 | CFStringRef modeName = (CFStringRef)value; | |
2209 | CFRunLoopRef rl = (CFRunLoopRef)ctx; | |
2210 | __CFRunLoopRemoveAllSources(rl, modeName); | |
2211 | } | |
2212 | ||
2213 | static void __CFRunLoopRemoveSourceFromMode(const void *value, void *ctx) { | |
2214 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)value; | |
2215 | CFRunLoopRef rl = (CFRunLoopRef)(((CFTypeRef *)ctx)[0]); | |
2216 | CFStringRef modeName = (CFStringRef)(((CFTypeRef *)ctx)[1]); | |
2217 | CFRunLoopRemoveSource(rl, rls, modeName); | |
2218 | } | |
2219 | ||
2220 | static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) { | |
2221 | CHECK_FOR_FORK(); | |
2222 | CFRunLoopModeRef rlm; | |
2223 | __CFRunLoopLock(rl); | |
2224 | if (modeName == kCFRunLoopCommonModes) { | |
2225 | if (NULL != rl->_commonModeItems) { | |
2226 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2227 | __CFRunLoopUnlock(rl); | |
2228 | if (NULL != set) { | |
2229 | CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl); | |
2230 | CFRelease(set); | |
2231 | } | |
2232 | } else { | |
2233 | __CFRunLoopUnlock(rl); | |
2234 | } | |
2235 | } else { | |
2236 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2237 | __CFRunLoopUnlock(rl); | |
2238 | if (NULL != rlm && NULL != rlm->_sources) { | |
2239 | CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources); | |
2240 | __CFRunLoopModeUnlock(rlm); | |
2241 | CFTypeRef context[2] = {rl, modeName}; | |
2242 | CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context); | |
2243 | CFRelease(set); | |
2244 | } else if (NULL != rlm) { | |
2245 | __CFRunLoopModeUnlock(rlm); | |
2246 | } | |
2247 | } | |
2248 | } | |
2249 | ||
9ce05555 | 2250 | Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { |
bd5b749c | 2251 | CHECK_FOR_FORK(); |
9ce05555 A |
2252 | CFRunLoopModeRef rlm; |
2253 | Boolean hasValue = false; | |
2254 | __CFRunLoopLock(rl); | |
2255 | if (modeName == kCFRunLoopCommonModes) { | |
2256 | if (NULL != rl->_commonModeItems) { | |
2257 | hasValue = CFSetContainsValue(rl->_commonModeItems, rlo); | |
2258 | } | |
2259 | __CFRunLoopUnlock(rl); | |
2260 | } else { | |
2261 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2262 | __CFRunLoopUnlock(rl); | |
2263 | if (NULL != rlm && NULL != rlm->_observers) { | |
2264 | hasValue = CFSetContainsValue(rlm->_observers, rlo); | |
2265 | __CFRunLoopModeUnlock(rlm); | |
2266 | } else if (NULL != rlm) { | |
2267 | __CFRunLoopModeUnlock(rlm); | |
2268 | } | |
2269 | } | |
2270 | return hasValue; | |
2271 | } | |
2272 | ||
2273 | void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { | |
bd5b749c | 2274 | CHECK_FOR_FORK(); |
9ce05555 A |
2275 | CFRunLoopModeRef rlm; |
2276 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2277 | if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return; | |
2278 | __CFRunLoopLock(rl); | |
2279 | if (modeName == kCFRunLoopCommonModes) { | |
2280 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2281 | if (NULL == rl->_commonModeItems) { | |
2282 | rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks); | |
2283 | } | |
2284 | CFSetAddValue(rl->_commonModeItems, rlo); | |
2285 | __CFRunLoopUnlock(rl); | |
2286 | if (NULL != set) { | |
2287 | CFTypeRef context[2] = {rl, rlo}; | |
2288 | /* add new item to all common-modes */ | |
2289 | CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); | |
2290 | CFRelease(set); | |
2291 | } | |
2292 | } else { | |
2293 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2294 | __CFRunLoopUnlock(rl); | |
2295 | if (NULL != rlm && NULL == rlm->_observers) { | |
2296 | rlm->_observers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks); | |
2297 | } | |
2298 | if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) { | |
2299 | CFSetAddValue(rlm->_observers, rlo); | |
2300 | __CFRunLoopModeUnlock(rlm); | |
2301 | __CFRunLoopObserverSchedule(rlo, rl, rlm); | |
2302 | } else if (NULL != rlm) { | |
2303 | __CFRunLoopModeUnlock(rlm); | |
2304 | } | |
2305 | } | |
2306 | } | |
2307 | ||
2308 | void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { | |
bd5b749c | 2309 | CHECK_FOR_FORK(); |
9ce05555 A |
2310 | CFRunLoopModeRef rlm; |
2311 | __CFRunLoopLock(rl); | |
2312 | if (modeName == kCFRunLoopCommonModes) { | |
2313 | if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) { | |
2314 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2315 | CFSetRemoveValue(rl->_commonModeItems, rlo); | |
2316 | __CFRunLoopUnlock(rl); | |
2317 | if (NULL != set) { | |
2318 | CFTypeRef context[2] = {rl, rlo}; | |
2319 | /* remove new item from all common-modes */ | |
2320 | CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context); | |
2321 | CFRelease(set); | |
2322 | } | |
2323 | } else { | |
2324 | __CFRunLoopUnlock(rl); | |
2325 | } | |
2326 | } else { | |
2327 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2328 | __CFRunLoopUnlock(rl); | |
2329 | if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) { | |
2330 | CFRetain(rlo); | |
2331 | CFSetRemoveValue(rlm->_observers, rlo); | |
2332 | __CFRunLoopModeUnlock(rlm); | |
2333 | __CFRunLoopObserverCancel(rlo, rl, rlm); | |
2334 | CFRelease(rlo); | |
2335 | } else if (NULL != rlm) { | |
2336 | __CFRunLoopModeUnlock(rlm); | |
2337 | } | |
2338 | } | |
2339 | } | |
2340 | ||
2341 | Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { | |
bd5b749c | 2342 | CHECK_FOR_FORK(); |
9ce05555 A |
2343 | CFRunLoopModeRef rlm; |
2344 | Boolean hasValue = false; | |
2345 | __CFRunLoopLock(rl); | |
2346 | if (modeName == kCFRunLoopCommonModes) { | |
2347 | if (NULL != rl->_commonModeItems) { | |
2348 | hasValue = CFSetContainsValue(rl->_commonModeItems, rlt); | |
2349 | } | |
2350 | __CFRunLoopUnlock(rl); | |
2351 | } else { | |
2352 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2353 | __CFRunLoopUnlock(rl); | |
2354 | if (NULL != rlm && NULL != rlm->_timers) { | |
2355 | hasValue = CFSetContainsValue(rlm->_timers, rlt); | |
2356 | __CFRunLoopModeUnlock(rlm); | |
2357 | } else if (NULL != rlm) { | |
2358 | __CFRunLoopModeUnlock(rlm); | |
2359 | } | |
2360 | } | |
2361 | return hasValue; | |
2362 | } | |
2363 | ||
2364 | void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { | |
bd5b749c | 2365 | CHECK_FOR_FORK(); |
9ce05555 A |
2366 | CFRunLoopModeRef rlm; |
2367 | if (__CFRunLoopIsDeallocating(rl)) return; | |
2368 | if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return; | |
2369 | __CFRunLoopLock(rl); | |
2370 | if (modeName == kCFRunLoopCommonModes) { | |
2371 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2372 | if (NULL == rl->_commonModeItems) { | |
2373 | rl->_commonModeItems = CFSetCreateMutable(CFGetAllocator(rl), 0, &kCFTypeSetCallBacks); | |
2374 | } | |
2375 | CFSetAddValue(rl->_commonModeItems, rlt); | |
2376 | __CFRunLoopUnlock(rl); | |
2377 | if (NULL != set) { | |
2378 | CFTypeRef context[2] = {rl, rlt}; | |
2379 | /* add new item to all common-modes */ | |
2380 | CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context); | |
2381 | CFRelease(set); | |
2382 | } | |
2383 | } else { | |
2384 | rlm = __CFRunLoopFindMode(rl, modeName, true); | |
2385 | __CFRunLoopUnlock(rl); | |
2386 | if (NULL != rlm && NULL == rlm->_timers) { | |
2387 | rlm->_timers = CFSetCreateMutable(CFGetAllocator(rlm), 0, &kCFTypeSetCallBacks); | |
2388 | } | |
2389 | if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) { | |
2390 | CFSetAddValue(rlm->_timers, rlt); | |
2391 | __CFRunLoopModeUnlock(rlm); | |
2392 | __CFRunLoopTimerSchedule(rlt, rl, rlm); | |
2393 | } else if (NULL != rlm) { | |
2394 | __CFRunLoopModeUnlock(rlm); | |
2395 | } | |
2396 | } | |
2397 | } | |
2398 | ||
2399 | void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { | |
bd5b749c | 2400 | CHECK_FOR_FORK(); |
9ce05555 A |
2401 | CFRunLoopModeRef rlm; |
2402 | __CFRunLoopLock(rl); | |
2403 | if (modeName == kCFRunLoopCommonModes) { | |
2404 | if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) { | |
2405 | CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; | |
2406 | CFSetRemoveValue(rl->_commonModeItems, rlt); | |
2407 | __CFRunLoopUnlock(rl); | |
2408 | if (NULL != set) { | |
2409 | CFTypeRef context[2] = {rl, rlt}; | |
2410 | /* remove new item from all common-modes */ | |
2411 | CFSetApplyFunction(set, (__CFRunLoopRemoveItemFromCommonModes), (void *)context); | |
2412 | CFRelease(set); | |
2413 | } | |
2414 | } else { | |
2415 | __CFRunLoopUnlock(rl); | |
2416 | } | |
2417 | } else { | |
2418 | rlm = __CFRunLoopFindMode(rl, modeName, false); | |
2419 | __CFRunLoopUnlock(rl); | |
2420 | if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) { | |
2421 | CFRetain(rlt); | |
2422 | CFSetRemoveValue(rlm->_timers, rlt); | |
2423 | __CFRunLoopModeUnlock(rlm); | |
2424 | __CFRunLoopTimerCancel(rlt, rl, rlm); | |
2425 | CFRelease(rlt); | |
2426 | } else if (NULL != rlm) { | |
2427 | __CFRunLoopModeUnlock(rlm); | |
2428 | } | |
2429 | } | |
2430 | } | |
2431 | ||
2432 | ||
2433 | /* CFRunLoopSource */ | |
2434 | ||
2435 | static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CALLOUT */ | |
2436 | CFRunLoopSourceRef rls1 = (CFRunLoopSourceRef)cf1; | |
2437 | CFRunLoopSourceRef rls2 = (CFRunLoopSourceRef)cf2; | |
2438 | if (rls1 == rls2) return true; | |
2439 | if (rls1->_order != rls2->_order) return false; | |
2440 | if (rls1->_context.version0.version != rls2->_context.version0.version) return false; | |
2441 | if (rls1->_context.version0.hash != rls2->_context.version0.hash) return false; | |
2442 | if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false; | |
2443 | if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false; | |
2444 | if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false; | |
2445 | if (rls1->_context.version0.equal) | |
2446 | return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info); | |
2447 | return (rls1->_context.version0.info == rls2->_context.version0.info); | |
2448 | } | |
2449 | ||
2450 | static CFHashCode __CFRunLoopSourceHash(CFTypeRef cf) { /* DOES CALLOUT */ | |
2451 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf; | |
2452 | if (rls->_context.version0.hash) | |
2453 | return rls->_context.version0.hash(rls->_context.version0.info); | |
2454 | return (CFHashCode)rls->_context.version0.info; | |
2455 | } | |
2456 | ||
2457 | static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ | |
2458 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf; | |
2459 | CFStringRef result; | |
2460 | CFStringRef contextDesc = NULL; | |
2461 | if (NULL != rls->_context.version0.copyDescription) { | |
2462 | contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info); | |
2463 | } | |
2464 | if (NULL == contextDesc) { | |
bd5b749c A |
2465 | void *addr = rls->_context.version0.version == 0 ? (void *)rls->_context.version0.perform : (rls->_context.version0.version == 1 ? (void *)rls->_context.version1.perform : NULL); |
2466 | #if DEPLOYMENT_TARGET_MACOSX | |
2467 | Dl_info info; | |
2468 | const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; | |
2469 | contextDesc = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource context>{version = %ld, info = %p, callout = %s (%p)}"), rls->_context.version0.version, rls->_context.version0.info, name, addr); | |
2470 | #else | |
2471 | #error Unknown or unspecified DEPLOYMENT_TARGET | |
2472 | #endif | |
9ce05555 | 2473 | } |
bd5b749c | 2474 | result = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("<CFRunLoopSource %p [%p]>{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), lockCount(rls->_lock) ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); |
9ce05555 A |
2475 | CFRelease(contextDesc); |
2476 | return result; | |
2477 | } | |
2478 | ||
2479 | static void __CFRunLoopSourceDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ | |
2480 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)cf; | |
2481 | CFRunLoopSourceInvalidate(rls); | |
2482 | if (rls->_context.version0.release) { | |
2483 | rls->_context.version0.release(rls->_context.version0.info); | |
2484 | } | |
2485 | } | |
2486 | ||
2487 | static const CFRuntimeClass __CFRunLoopSourceClass = { | |
d8925383 | 2488 | _kCFRuntimeScannedObject, |
9ce05555 A |
2489 | "CFRunLoopSource", |
2490 | NULL, // init | |
2491 | NULL, // copy | |
2492 | __CFRunLoopSourceDeallocate, | |
2493 | __CFRunLoopSourceEqual, | |
2494 | __CFRunLoopSourceHash, | |
2495 | NULL, // | |
2496 | __CFRunLoopSourceCopyDescription | |
2497 | }; | |
2498 | ||
2499 | __private_extern__ void __CFRunLoopSourceInitialize(void) { | |
2500 | __kCFRunLoopSourceTypeID = _CFRuntimeRegisterClass(&__CFRunLoopSourceClass); | |
2501 | } | |
2502 | ||
2503 | CFTypeID CFRunLoopSourceGetTypeID(void) { | |
2504 | return __kCFRunLoopSourceTypeID; | |
2505 | } | |
2506 | ||
2507 | CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) { | |
bd5b749c | 2508 | CHECK_FOR_FORK(); |
9ce05555 A |
2509 | CFRunLoopSourceRef memory; |
2510 | uint32_t size; | |
2511 | if (NULL == context) HALT; | |
2512 | size = sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase); | |
2513 | memory = (CFRunLoopSourceRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopSourceTypeID, size, NULL); | |
2514 | if (NULL == memory) { | |
2515 | return NULL; | |
2516 | } | |
2517 | __CFSetValid(memory); | |
2518 | __CFRunLoopSourceUnsetSignaled(memory); | |
bd5b749c | 2519 | CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); |
9ce05555 A |
2520 | memory->_bits = 0; |
2521 | memory->_order = order; | |
2522 | memory->_runLoops = NULL; | |
d8925383 A |
2523 | size = 0; |
2524 | switch (context->version) { | |
2525 | case 0: | |
2526 | size = sizeof(CFRunLoopSourceContext); | |
2527 | break; | |
2528 | case 1: | |
2529 | size = sizeof(CFRunLoopSourceContext1); | |
2530 | break; | |
bd5b749c | 2531 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
2532 | case 2: |
2533 | size = sizeof(CFRunLoopSourceContext2); | |
2534 | break; | |
bd5b749c | 2535 | #endif |
d8925383 A |
2536 | } |
2537 | CF_WRITE_BARRIER_MEMMOVE(&memory->_context, context, size); | |
9ce05555 A |
2538 | if (context->retain) { |
2539 | memory->_context.version0.info = (void *)context->retain(context->info); | |
2540 | } | |
2541 | return memory; | |
2542 | } | |
2543 | ||
2544 | CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) { | |
bd5b749c | 2545 | CHECK_FOR_FORK(); |
9ce05555 A |
2546 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
2547 | return rls->_order; | |
2548 | } | |
2549 | ||
2550 | static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) { | |
2551 | CFRunLoopRef rl = (CFRunLoopRef)value; | |
2552 | CFTypeRef *params = context; | |
2553 | CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0]; | |
2554 | CFArrayRef array; | |
2555 | CFIndex idx; | |
2556 | if (rl == params[1]) return; | |
2557 | array = CFRunLoopCopyAllModes(rl); | |
2558 | for (idx = CFArrayGetCount(array); idx--;) { | |
2559 | CFStringRef modeName = CFArrayGetValueAtIndex(array, idx); | |
2560 | CFRunLoopRemoveSource(rl, rls, modeName); | |
2561 | } | |
2562 | CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes); | |
2563 | CFRelease(array); | |
2564 | params[1] = rl; | |
2565 | } | |
2566 | ||
2567 | void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) { | |
bd5b749c | 2568 | CHECK_FOR_FORK(); |
9ce05555 A |
2569 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
2570 | CFRetain(rls); | |
2571 | __CFRunLoopSourceLock(rls); | |
2572 | if (__CFIsValid(rls)) { | |
2573 | __CFUnsetValid(rls); | |
bd5b749c | 2574 | __CFRunLoopSourceUnsetSignaled(rls); |
9ce05555 A |
2575 | if (NULL != rls->_runLoops) { |
2576 | CFTypeRef params[2] = {rls, NULL}; | |
2577 | CFBagRef bag = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops); | |
2578 | CFRelease(rls->_runLoops); | |
2579 | rls->_runLoops = NULL; | |
2580 | __CFRunLoopSourceUnlock(rls); | |
2581 | CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params); | |
2582 | CFRelease(bag); | |
2583 | } else { | |
2584 | __CFRunLoopSourceUnlock(rls); | |
2585 | } | |
2586 | /* for hashing- and equality-use purposes, can't actually release the context here */ | |
2587 | } else { | |
2588 | __CFRunLoopSourceUnlock(rls); | |
2589 | } | |
2590 | CFRelease(rls); | |
2591 | } | |
2592 | ||
2593 | Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) { | |
bd5b749c | 2594 | CHECK_FOR_FORK(); |
9ce05555 A |
2595 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
2596 | return __CFIsValid(rls); | |
2597 | } | |
2598 | ||
2599 | void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) { | |
bd5b749c | 2600 | CHECK_FOR_FORK(); |
9ce05555 | 2601 | __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); |
bd5b749c | 2602 | CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__); |
d8925383 A |
2603 | CFIndex size = 0; |
2604 | switch (context->version) { | |
2605 | case 0: | |
2606 | size = sizeof(CFRunLoopSourceContext); | |
2607 | break; | |
2608 | case 1: | |
2609 | size = sizeof(CFRunLoopSourceContext1); | |
2610 | break; | |
bd5b749c | 2611 | #if DEPLOYMENT_TARGET_MACOSX |
d8925383 A |
2612 | case 2: |
2613 | size = sizeof(CFRunLoopSourceContext2); | |
2614 | break; | |
bd5b749c | 2615 | #endif |
d8925383 A |
2616 | } |
2617 | memmove(context, &rls->_context, size); | |
9ce05555 A |
2618 | } |
2619 | ||
2620 | void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) { | |
bd5b749c | 2621 | CHECK_FOR_FORK(); |
9ce05555 A |
2622 | __CFRunLoopSourceLock(rls); |
2623 | if (__CFIsValid(rls)) { | |
2624 | __CFRunLoopSourceSetSignaled(rls); | |
2625 | } | |
2626 | __CFRunLoopSourceUnlock(rls); | |
2627 | } | |
2628 | ||
bd5b749c A |
2629 | Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) { |
2630 | CHECK_FOR_FORK(); | |
2631 | __CFRunLoopSourceLock(rls); | |
2632 | Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false; | |
2633 | __CFRunLoopSourceUnlock(rls); | |
2634 | return ret; | |
2635 | } | |
9ce05555 A |
2636 | |
2637 | /* CFRunLoopObserver */ | |
2638 | ||
2639 | static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ | |
2640 | CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf; | |
2641 | CFStringRef result; | |
2642 | CFStringRef contextDesc = NULL; | |
9ce05555 A |
2643 | if (NULL != rlo->_context.copyDescription) { |
2644 | contextDesc = rlo->_context.copyDescription(rlo->_context.info); | |
2645 | } | |
2646 | if (!contextDesc) { | |
2647 | contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver context %p>"), rlo->_context.info); | |
2648 | } | |
bd5b749c A |
2649 | #if DEPLOYMENT_TARGET_MACOSX |
2650 | void *addr = rlo->_callout; | |
2651 | Dl_info info; | |
2652 | const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; | |
2653 | result = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("<CFRunLoopObserver %p [%p]>{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlo), lockCount(rlo->_lock) ? "Yes" : "No", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, name, addr, contextDesc); | |
2654 | #else | |
2655 | #error Unknown or unspecified DEPLOYMENT_TARGET | |
2656 | #endif | |
9ce05555 A |
2657 | CFRelease(contextDesc); |
2658 | return result; | |
2659 | } | |
2660 | ||
2661 | static void __CFRunLoopObserverDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ | |
2662 | CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf; | |
2663 | CFRunLoopObserverInvalidate(rlo); | |
2664 | } | |
2665 | ||
2666 | static const CFRuntimeClass __CFRunLoopObserverClass = { | |
2667 | 0, | |
2668 | "CFRunLoopObserver", | |
2669 | NULL, // init | |
2670 | NULL, // copy | |
2671 | __CFRunLoopObserverDeallocate, | |
2672 | NULL, | |
2673 | NULL, | |
2674 | NULL, // | |
2675 | __CFRunLoopObserverCopyDescription | |
2676 | }; | |
2677 | ||
2678 | __private_extern__ void __CFRunLoopObserverInitialize(void) { | |
2679 | __kCFRunLoopObserverTypeID = _CFRuntimeRegisterClass(&__CFRunLoopObserverClass); | |
2680 | } | |
2681 | ||
2682 | CFTypeID CFRunLoopObserverGetTypeID(void) { | |
2683 | return __kCFRunLoopObserverTypeID; | |
2684 | } | |
2685 | ||
2686 | CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) { | |
bd5b749c | 2687 | CHECK_FOR_FORK(); |
9ce05555 A |
2688 | CFRunLoopObserverRef memory; |
2689 | UInt32 size; | |
2690 | size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase); | |
2691 | memory = (CFRunLoopObserverRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopObserverTypeID, size, NULL); | |
2692 | if (NULL == memory) { | |
2693 | return NULL; | |
2694 | } | |
2695 | __CFSetValid(memory); | |
2696 | __CFRunLoopObserverUnsetFiring(memory); | |
2697 | if (repeats) { | |
2698 | __CFRunLoopObserverSetRepeats(memory); | |
2699 | } else { | |
2700 | __CFRunLoopObserverUnsetRepeats(memory); | |
2701 | } | |
bd5b749c | 2702 | CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); |
9ce05555 A |
2703 | memory->_runLoop = NULL; |
2704 | memory->_rlCount = 0; | |
2705 | memory->_activities = activities; | |
2706 | memory->_order = order; | |
2707 | memory->_callout = callout; | |
2708 | if (context) { | |
2709 | if (context->retain) { | |
2710 | memory->_context.info = (void *)context->retain(context->info); | |
2711 | } else { | |
2712 | memory->_context.info = context->info; | |
2713 | } | |
2714 | memory->_context.retain = context->retain; | |
2715 | memory->_context.release = context->release; | |
2716 | memory->_context.copyDescription = context->copyDescription; | |
2717 | } else { | |
2718 | memory->_context.info = 0; | |
2719 | memory->_context.retain = 0; | |
2720 | memory->_context.release = 0; | |
2721 | memory->_context.copyDescription = 0; | |
2722 | } | |
2723 | return memory; | |
2724 | } | |
2725 | ||
2726 | CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) { | |
bd5b749c | 2727 | CHECK_FOR_FORK(); |
9ce05555 A |
2728 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
2729 | return rlo->_activities; | |
2730 | } | |
2731 | ||
2732 | CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) { | |
bd5b749c | 2733 | CHECK_FOR_FORK(); |
9ce05555 A |
2734 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
2735 | return rlo->_order; | |
2736 | } | |
2737 | ||
2738 | Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) { | |
bd5b749c | 2739 | CHECK_FOR_FORK(); |
9ce05555 A |
2740 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
2741 | return __CFRunLoopObserverRepeats(rlo); | |
2742 | } | |
2743 | ||
2744 | void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */ | |
bd5b749c | 2745 | CHECK_FOR_FORK(); |
9ce05555 A |
2746 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
2747 | CFRetain(rlo); | |
2748 | __CFRunLoopObserverLock(rlo); | |
2749 | if (__CFIsValid(rlo)) { | |
2750 | CFRunLoopRef rl = rlo->_runLoop; | |
2751 | __CFUnsetValid(rlo); | |
2752 | __CFRunLoopObserverUnlock(rlo); | |
2753 | if (NULL != rl) { | |
2754 | CFArrayRef array; | |
2755 | CFIndex idx; | |
2756 | array = CFRunLoopCopyAllModes(rl); | |
2757 | for (idx = CFArrayGetCount(array); idx--;) { | |
2758 | CFStringRef modeName = CFArrayGetValueAtIndex(array, idx); | |
2759 | CFRunLoopRemoveObserver(rl, rlo, modeName); | |
2760 | } | |
2761 | CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes); | |
2762 | CFRelease(array); | |
2763 | } | |
2764 | if (rlo->_context.release) | |
2765 | rlo->_context.release(rlo->_context.info); /* CALLOUT */ | |
2766 | rlo->_context.info = NULL; | |
2767 | } else { | |
2768 | __CFRunLoopObserverUnlock(rlo); | |
2769 | } | |
2770 | CFRelease(rlo); | |
2771 | } | |
2772 | ||
2773 | Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) { | |
bd5b749c | 2774 | CHECK_FOR_FORK(); |
9ce05555 A |
2775 | return __CFIsValid(rlo); |
2776 | } | |
2777 | ||
2778 | void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) { | |
bd5b749c | 2779 | CHECK_FOR_FORK(); |
9ce05555 A |
2780 | __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); |
2781 | CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); | |
2782 | *context = rlo->_context; | |
2783 | } | |
2784 | ||
2785 | /* CFRunLoopTimer */ | |
2786 | ||
2787 | static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ | |
2788 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf; | |
2789 | CFStringRef result; | |
2790 | CFStringRef contextDesc = NULL; | |
2791 | int64_t fireTime; | |
2792 | __CFRunLoopTimerFireTSRLock(); | |
2793 | fireTime = rlt->_fireTSR; | |
2794 | __CFRunLoopTimerFireTSRUnlock(); | |
9ce05555 A |
2795 | if (NULL != rlt->_context.copyDescription) { |
2796 | contextDesc = rlt->_context.copyDescription(rlt->_context.info); | |
2797 | } | |
2798 | if (NULL == contextDesc) { | |
2799 | contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer context %p>"), rlt->_context.info); | |
2800 | } | |
d8925383 A |
2801 | int64_t now2 = (int64_t)mach_absolute_time(); |
2802 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
bd5b749c A |
2803 | #if DEPLOYMENT_TARGET_MACOSX |
2804 | void *addr = rlt->_callout; | |
2805 | Dl_info info; | |
2806 | const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; | |
2807 | result = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("<CFRunLoopTimer %p [%p]>{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlt), lockCount(rlt->_lock) ? "Yes" : "No", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, name, addr, contextDesc); | |
2808 | #else | |
2809 | #error Unknown or unspecified DEPLOYMENT_TARGET | |
2810 | #endif | |
9ce05555 A |
2811 | CFRelease(contextDesc); |
2812 | return result; | |
2813 | } | |
2814 | ||
2815 | static void __CFRunLoopTimerDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ | |
2816 | CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf; | |
2817 | CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ | |
2818 | } | |
2819 | ||
2820 | static const CFRuntimeClass __CFRunLoopTimerClass = { | |
2821 | 0, | |
2822 | "CFRunLoopTimer", | |
2823 | NULL, // init | |
2824 | NULL, // copy | |
2825 | __CFRunLoopTimerDeallocate, | |
2826 | NULL, // equal | |
2827 | NULL, | |
2828 | NULL, // | |
2829 | __CFRunLoopTimerCopyDescription | |
2830 | }; | |
2831 | ||
2832 | __private_extern__ void __CFRunLoopTimerInitialize(void) { | |
2833 | __kCFRunLoopTimerTypeID = _CFRuntimeRegisterClass(&__CFRunLoopTimerClass); | |
2834 | } | |
2835 | ||
2836 | CFTypeID CFRunLoopTimerGetTypeID(void) { | |
2837 | return __kCFRunLoopTimerTypeID; | |
2838 | } | |
2839 | ||
2840 | CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) { | |
bd5b749c | 2841 | CHECK_FOR_FORK(); |
9ce05555 A |
2842 | CFRunLoopTimerRef memory; |
2843 | UInt32 size; | |
2844 | size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase); | |
2845 | memory = (CFRunLoopTimerRef)_CFRuntimeCreateInstance(allocator, __kCFRunLoopTimerTypeID, size, NULL); | |
2846 | if (NULL == memory) { | |
2847 | return NULL; | |
2848 | } | |
2849 | __CFSetValid(memory); | |
2850 | __CFRunLoopTimerUnsetFiring(memory); | |
d8925383 | 2851 | __CFRunLoopTimerUnsetDidFire(memory); |
bd5b749c | 2852 | CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); |
9ce05555 A |
2853 | memory->_runLoop = NULL; |
2854 | memory->_rlCount = 0; | |
bd5b749c | 2855 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
2856 | memory->_port = MACH_PORT_NULL; |
2857 | #endif | |
2858 | memory->_order = order; | |
d8925383 A |
2859 | int64_t now2 = (int64_t)mach_absolute_time(); |
2860 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
bd5b749c | 2861 | if (3.1556952e+9 < fireDate) fireDate = 3.1556952e+9; |
d8925383 A |
2862 | if (fireDate < now1) { |
2863 | memory->_fireTSR = now2; | |
2864 | } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { | |
9ce05555 A |
2865 | memory->_fireTSR = LLONG_MAX; |
2866 | } else { | |
d8925383 | 2867 | memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); |
9ce05555 | 2868 | } |
bd5b749c | 2869 | if (3.1556952e+9 < interval) interval = 3.1556952e+9; |
9ce05555 A |
2870 | if (interval <= 0.0) { |
2871 | memory->_intervalTSR = 0; | |
2872 | } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) { | |
2873 | memory->_intervalTSR = LLONG_MAX; | |
2874 | } else { | |
2875 | memory->_intervalTSR = __CFTimeIntervalToTSR(interval); | |
2876 | } | |
2877 | memory->_callout = callout; | |
2878 | if (NULL != context) { | |
2879 | if (context->retain) { | |
2880 | memory->_context.info = (void *)context->retain(context->info); | |
2881 | } else { | |
2882 | memory->_context.info = context->info; | |
2883 | } | |
2884 | memory->_context.retain = context->retain; | |
2885 | memory->_context.release = context->release; | |
2886 | memory->_context.copyDescription = context->copyDescription; | |
2887 | } else { | |
2888 | memory->_context.info = 0; | |
2889 | memory->_context.retain = 0; | |
2890 | memory->_context.release = 0; | |
2891 | memory->_context.copyDescription = 0; | |
2892 | } | |
2893 | return memory; | |
2894 | } | |
2895 | ||
2896 | CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) { | |
bd5b749c | 2897 | CHECK_FOR_FORK(); |
9ce05555 A |
2898 | int64_t fireTime, result = 0; |
2899 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime"); | |
2900 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
2901 | __CFRunLoopTimerFireTSRLock(); | |
2902 | fireTime = rlt->_fireTSR; | |
2903 | __CFRunLoopTimerFireTSRUnlock(); | |
2904 | __CFRunLoopTimerLock(rlt); | |
2905 | if (__CFIsValid(rlt)) { | |
2906 | result = fireTime; | |
2907 | } | |
2908 | __CFRunLoopTimerUnlock(rlt); | |
d8925383 A |
2909 | int64_t now2 = (int64_t)mach_absolute_time(); |
2910 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
2911 | return (0 == result) ? 0.0 : now1 + __CFTSRToTimeInterval(result - now2); | |
9ce05555 A |
2912 | } |
2913 | ||
2914 | void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) { | |
bd5b749c | 2915 | CHECK_FOR_FORK(); |
9ce05555 | 2916 | __CFRunLoopTimerFireTSRLock(); |
d8925383 A |
2917 | int64_t now2 = (int64_t)mach_absolute_time(); |
2918 | CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); | |
bd5b749c | 2919 | if (3.1556952e+9 < fireDate) fireDate = 3.1556952e+9; |
d8925383 A |
2920 | if (fireDate < now1) { |
2921 | rlt->_fireTSR = now2; | |
2922 | } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { | |
9ce05555 A |
2923 | rlt->_fireTSR = LLONG_MAX; |
2924 | } else { | |
d8925383 A |
2925 | rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); |
2926 | } | |
9ce05555 A |
2927 | if (rlt->_runLoop != NULL) { |
2928 | __CFRunLoopTimerRescheduleWithAllModes(rlt, rlt->_runLoop); | |
2929 | } | |
d8925383 | 2930 | __CFRunLoopTimerFireTSRUnlock(); |
9ce05555 A |
2931 | } |
2932 | ||
2933 | CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) { | |
bd5b749c | 2934 | CHECK_FOR_FORK(); |
9ce05555 A |
2935 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval"); |
2936 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
2937 | return __CFTSRToTimeInterval(rlt->_intervalTSR); | |
2938 | } | |
2939 | ||
2940 | Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) { | |
bd5b749c | 2941 | CHECK_FOR_FORK(); |
9ce05555 A |
2942 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); |
2943 | return (0 != rlt->_intervalTSR); | |
2944 | } | |
2945 | ||
2946 | CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) { | |
bd5b749c | 2947 | CHECK_FOR_FORK(); |
9ce05555 A |
2948 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order"); |
2949 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
2950 | return rlt->_order; | |
2951 | } | |
2952 | ||
2953 | void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ | |
bd5b749c | 2954 | CHECK_FOR_FORK(); |
9ce05555 A |
2955 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate"); |
2956 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
2957 | CFRetain(rlt); | |
2958 | __CFRunLoopTimerLock(rlt); | |
2959 | if (__CFIsValid(rlt)) { | |
2960 | CFRunLoopRef rl = rlt->_runLoop; | |
2961 | void *info = rlt->_context.info; | |
2962 | __CFUnsetValid(rlt); | |
bd5b749c | 2963 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
2964 | __CFRunLoopTimerPortMapLock(); |
2965 | if (NULL != __CFRLTPortMap) { | |
bd5b749c | 2966 | CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); |
9ce05555 A |
2967 | } |
2968 | __CFRunLoopTimerPortMapUnlock(); | |
2969 | mk_timer_destroy(rlt->_port); | |
2970 | rlt->_port = MACH_PORT_NULL; | |
2971 | #endif | |
2972 | rlt->_context.info = NULL; | |
2973 | __CFRunLoopTimerUnlock(rlt); | |
2974 | if (NULL != rl) { | |
2975 | CFArrayRef array; | |
2976 | CFIndex idx; | |
2977 | array = CFRunLoopCopyAllModes(rl); | |
2978 | for (idx = CFArrayGetCount(array); idx--;) { | |
2979 | CFStringRef modeName = CFArrayGetValueAtIndex(array, idx); | |
2980 | CFRunLoopRemoveTimer(rl, rlt, modeName); | |
2981 | } | |
2982 | CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes); | |
2983 | CFRelease(array); | |
2984 | } | |
2985 | if (NULL != rlt->_context.release) { | |
2986 | rlt->_context.release(info); /* CALLOUT */ | |
2987 | } | |
2988 | } else { | |
2989 | __CFRunLoopTimerUnlock(rlt); | |
2990 | } | |
2991 | CFRelease(rlt); | |
2992 | } | |
2993 | ||
2994 | Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) { | |
bd5b749c | 2995 | CHECK_FOR_FORK(); |
9ce05555 A |
2996 | CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid"); |
2997 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); | |
2998 | return __CFIsValid(rlt); | |
2999 | } | |
3000 | ||
3001 | void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) { | |
bd5b749c | 3002 | CHECK_FOR_FORK(); |
9ce05555 A |
3003 | __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); |
3004 | CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); | |
3005 | *context = rlt->_context; | |
3006 | } | |
3007 | ||
bd5b749c | 3008 | #endif |
9ce05555 | 3009 |