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