]> git.saurik.com Git - apple/cf.git/blob - CFUtilities.c
CF-550.13.tar.gz
[apple/cf.git] / CFUtilities.c
1 /*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
24 /* CFUtilities.c
25 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #include <CoreFoundation/CFPriv.h>
30 #include "CFInternal.h"
31 #include "CFLocaleInternal.h"
32 #include <CoreFoundation/CFPriv.h>
33 #include <CoreFoundation/CFBundle.h>
34 #include <CoreFoundation/CFURLAccess.h>
35 #include <CoreFoundation/CFPropertyList.h>
36 #include <CoreFoundation/CFTimeZone.h>
37 #include <CoreFoundation/CFCalendar.h>
38 #include <math.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <asl.h>
43 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
44 #include <unistd.h>
45 #include <sys/uio.h>
46 #include <mach/mach.h>
47 #include <pthread.h>
48 #include <mach-o/loader.h>
49 #include <mach-o/dyld.h>
50 #include <crt_externs.h>
51 #include <dlfcn.h>
52 #include <vproc.h>
53 #include <vproc_priv.h>
54 #include <sys/sysctl.h>
55 #include <sys/stat.h>
56 #include <mach/mach.h>
57 #include <mach/mach_vm.h>
58 #include <sys/mman.h>
59 #include <stdio.h>
60 #include <sys/errno.h>
61 #include <mach/mach_time.h>
62 #include <libkern/OSAtomic.h>
63 #include <Block.h>
64 #endif
65 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
66 #include <string.h>
67 #include <pthread.h>
68 #endif
69
70 /* Comparator is passed the address of the values. */
71 /* Binary searches a sorted-increasing array of some type.
72 Return value is either 1) the index of the element desired,
73 if the target value exists in the list, 2) greater than or
74 equal to count, if the element is greater than all the values
75 in the list, or 3) the index of the element greater than the
76 target value.
77
78 For example, a search in the list of integers:
79 2 3 5 7 11 13 17
80
81 For... Will Return...
82 2 0
83 5 2
84 23 7
85 1 0
86 9 4
87
88 For instance, if you just care about found/not found:
89 index = CFBSearch(list, count, elem);
90 if (count <= index || list[index] != elem) {
91 * Not found *
92 } else {
93 * Found *
94 }
95
96 */
97 __private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
98 const char *ptr = (const char *)list;
99 while (0 < count) {
100 CFIndex half = count / 2;
101 const char *probe = ptr + elementSize * half;
102 CFComparisonResult cr = comparator(element, probe, context);
103 if (0 == cr) return (probe - (const char *)list) / elementSize;
104 ptr = (cr < 0) ? ptr : probe + elementSize;
105 count = (cr < 0) ? half : (half + (count & 1) - 1);
106 }
107 return (ptr - (const char *)list) / elementSize;
108 }
109
110
111 #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
112
113 CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
114 /* The ELF hash algorithm, used in the ELF object file format */
115 UInt32 H = 0, T1, T2;
116 SInt32 rem = length;
117 while (3 < rem) {
118 ELF_STEP(bytes[length - rem]);
119 ELF_STEP(bytes[length - rem + 1]);
120 ELF_STEP(bytes[length - rem + 2]);
121 ELF_STEP(bytes[length - rem + 3]);
122 rem -= 4;
123 }
124 switch (rem) {
125 case 3: ELF_STEP(bytes[length - 3]);
126 case 2: ELF_STEP(bytes[length - 2]);
127 case 1: ELF_STEP(bytes[length - 1]);
128 case 0: ;
129 }
130 return H;
131 }
132
133 #undef ELF_STEP
134
135
136 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
137 __private_extern__ uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) {
138 vm_map_t task = mach_task_self();
139 mach_vm_address_t address = start;
140 for (;;) {
141 mach_vm_size_t size = 0;
142 vm_region_basic_info_data_64_t info;
143 mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
144 mach_port_t object_name;
145 kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name);
146 if (KERN_SUCCESS != ret) break;
147 boolean_t scan = (info.protection & VM_PROT_WRITE) ? 1 : 0;
148 if (scan) {
149 uintptr_t *addr = (uintptr_t *)((uintptr_t)address);
150 uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size);
151 while (addr < end) {
152 if ((uintptr_t *)start <= addr && *addr == ptr) {
153 return (uintptr_t)addr;
154 }
155 addr++;
156 }
157 }
158 address += size;
159 }
160 return 0;
161 }
162 #endif
163
164 #if DEPLOYMENT_TARGET_WINDOWS
165 struct _args {
166 void *func;
167 void *arg;
168 HANDLE handle;
169 };
170 static unsigned __stdcall __CFWinThreadFunc(void *arg) {
171 struct _args *args = (struct _args*)arg;
172 ((void (*)(void *))args->func)(args->arg);
173 CloseHandle(args->handle);
174 CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg);
175 _endthreadex(0);
176 return 0;
177 }
178 #endif
179
180 __private_extern__ void *__CFStartSimpleThread(void *func, void *arg) {
181 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
182 pthread_attr_t attr;
183 pthread_t tid = 0;
184 pthread_attr_init(&attr);
185 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
186 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
187 pthread_attr_setstacksize(&attr, 60 * 1024); // 60K stack for our internal threads is sufficient
188 OSMemoryBarrier(); // ensure arg is fully initialized and set in memory
189 pthread_create(&tid, &attr, func, arg);
190 pthread_attr_destroy(&attr);
191 //warning CF: we dont actually know that a pthread_t is the same size as void *
192 return (void *)tid;
193 #elif DEPLOYMENT_TARGET_WINDOWS
194 unsigned tid;
195 struct _args *args = (struct _args*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0);
196 if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)");
197 HANDLE handle;
198 args->func = func;
199 args->arg = arg;
200 /* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */
201 args->handle = (HANDLE)_beginthreadex(NULL, 0, __CFWinThreadFunc, args, CREATE_SUSPENDED, &tid);
202 handle = args->handle;
203 ResumeThread(handle);
204 return handle;
205 #endif
206 }
207
208
209 // Looks for localized version of "nonLocalized" in the SystemVersion bundle
210 // If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
211 // If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
212 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
213 static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
214 CFStringRef localized = NULL;
215 CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
216 if (!locBundle) {
217 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
218 if (url) {
219 locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url);
220 CFRelease(url);
221 }
222 }
223 if (locBundle) {
224 localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
225 if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
226 }
227 return localized ? localized : (CFStringRef)CFRetain(nonLocalized);
228 }
229 #endif
230
231 static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
232 CFPropertyListRef plist = NULL;
233 CFDataRef data;
234 CFURLRef url;
235
236 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
237 if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) {
238 plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL);
239 CFRelease(data);
240 }
241 if (url) CFRelease(url);
242
243 if (plist) {
244 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
245 CFBundleRef locBundle = NULL;
246 CFStringRef fullVersion, vers, versExtra, build;
247 CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
248 CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
249 CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
250 if (locBundle) CFRelease(locBundle);
251
252 // Now build the full version string
253 if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
254 CFRelease(fullVersionString);
255 fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
256 }
257 vers = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionKey);
258 versExtra = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionExtraKey);
259 if (vers && versExtra) vers = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %@"), vers, versExtra);
260 build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey);
261 fullVersion = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
262 if (vers && versExtra) CFRelease(vers);
263
264 CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
265 CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
266 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
267 CFRelease(versionString);
268 CFRelease(buildString);
269 CFRelease(fullVersionString);
270 CFRelease(fullVersion);
271 #endif
272 }
273 return (CFDictionaryRef)plist;
274 }
275
276 CFStringRef CFCopySystemVersionString(void) {
277 CFStringRef versionString;
278 CFDictionaryRef dict = _CFCopyServerVersionDictionary();
279 if (!dict) dict = _CFCopySystemVersionDictionary();
280 if (!dict) return NULL;
281 versionString = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("FullVersionString"));
282 if (versionString) CFRetain(versionString);
283 CFRelease(dict);
284 return versionString;
285 }
286
287 // Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired
288 // In fact, they do not cache any more, because the file can change after
289 // apps are running in some situations, and apps need the new info.
290 // Proper caching and testing to see if the file has changed, without race
291 // conditions, would require semi-convoluted use of fstat().
292
293 CFDictionaryRef _CFCopySystemVersionDictionary(void) {
294 CFPropertyListRef plist = NULL;
295 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
296 return (CFDictionaryRef)plist;
297 }
298
299 CFDictionaryRef _CFCopyServerVersionDictionary(void) {
300 CFPropertyListRef plist = NULL;
301 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
302 return (CFDictionaryRef)plist;
303 }
304
305 CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
306 CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
307 CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
308 CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
309 CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
310 CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
311 CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
312 CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
313
314 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || TARGET_IPHONE_SIMULATOR
315
316 typedef struct {
317 uint16_t primaryVersion;
318 uint8_t secondaryVersion;
319 uint8_t tertiaryVersion;
320 } CFLibraryVersion;
321
322 CFLibraryVersion CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName) {
323 CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
324 char library[CFMaxPathSize]; // search specs larger than this are pointless
325 if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
326 int32_t version = NSVersionOfLinkTimeLibrary(library);
327 if (-1 != version) {
328 ret.primaryVersion = version >> 16;
329 ret.secondaryVersion = (version >> 8) & 0xff;
330 ret.tertiaryVersion = version & 0xff;
331 }
332 return ret;
333 }
334
335 CFLibraryVersion CFGetExecutingLibraryVersion(CFStringRef libraryName) {
336 CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
337 char library[CFMaxPathSize]; // search specs larger than this are pointless
338 if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
339 int32_t version = NSVersionOfRunTimeLibrary(library);
340 if (-1 != version) {
341 ret.primaryVersion = version >> 16;
342 ret.secondaryVersion = (version >> 8) & 0xff;
343 ret.tertiaryVersion = version & 0xff;
344 }
345 return ret;
346 }
347
348 static inline Boolean _CFLibraryVersionLessThan(CFLibraryVersion vers1, CFLibraryVersion vers2) {
349 if (vers1.primaryVersion < vers2.primaryVersion) {
350 return true;
351 } else if (vers1.primaryVersion == vers2.primaryVersion) {
352 if (vers1.secondaryVersion < vers2.secondaryVersion) {
353 return true;
354 } else if (vers1.secondaryVersion == vers2.secondaryVersion) {
355 return vers1.tertiaryVersion < vers2.tertiaryVersion;
356 }
357 }
358 return false;
359 }
360
361 /*
362 If
363 (vers != 0xFFFF): We know the version number of the library this app was linked against
364 and (versionInfo[version].VERSIONFIELD != 0xFFFF): And we know what version number started the specified release
365 and ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD)): And it's distinct from the prev release
366 Then
367 If the version the app is linked against is less than the version recorded for the specified release
368 Then stop checking and return false
369 Else stop checking and return YES
370 Else
371 Continue checking (the next library)
372 */
373
374 #define resultIndex(VERSION) (VERSION)
375
376 #define checkLibrary(LIBNAME, VERSIONFIELD) { \
377 uint16_t vers = (NSVersionOfLinkTimeLibrary(LIBNAME) >> 16); \
378 if ((vers != 0xFFFF) && (versionInfo[version].VERSIONFIELD != 0xFFFF) && \
379 ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD))) \
380 return (results[resultIndex(version)] = ((vers < versionInfo[version].VERSIONFIELD) ? false : true)); \
381 }
382
383
384 CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
385 // The numbers in the below tables should be the numbers for any version of the framework in the release.
386 // When adding new entries to these tables for a new build train, it's simplest to use the versions of the
387 // first new versions of projects submitted to the new train. These can later be updated. One thing to watch for is that software updates
388 // for the previous release do not increase numbers beyond the number used for the next release!
389 // For a given train, don't ever use the last versions submitted to the previous train! (This to assure room for software updates.)
390 // If versions are the same as previous release, use 0xFFFF; this will assure the answer is a conservative NO.
391 // NOTE: Also update the CFM check below, perhaps to the previous release... (???)
392 static const struct {
393 uint16_t libSystemVersion;
394 uint16_t cocoaVersion;
395 uint16_t appkitVersion;
396 uint16_t fouVersion;
397 uint16_t cfVersion;
398 uint16_t carbonVersion;
399 uint16_t applicationServicesVersion;
400 uint16_t coreServicesVersion;
401 uint16_t iokitVersion;
402 } versionInfo[] = {
403 {50, 5, 577, 397, 196, 113, 16, 9, 52}, /* CFSystemVersionCheetah (used the last versions) */
404 {55, 7, 620, 425, 226, 122, 16, 10, 67}, /* CFSystemVersionPuma (used the last versions) */
405 {56, 8, 631, 431, 232, 122, 17, 11, 73}, /* CFSystemVersionJaguar */
406 {67, 9, 704, 481, 281, 126, 19, 16, 159}, /* CFSystemVersionPanther */
407 {73, 10, 750, 505, 305, 128, 22, 18, 271}, /* CFSystemVersionTiger */
408 {89, 12, 840, 575, 375, 136, 34, 32, 0xFFFF}, /* CFSystemVersionLeopard */
409 {112, 13, 960, 680, 480, 0xFFFF, 0xFFFF, 33, 0xFFFF}, /* CFSystemVersionSnowLeopard */
410 };
411
412
413 // !!! When a new release is added to the array, don't forget to bump the size of this array!
414 static char results[CFSystemVersionMax] = {-2, -2, -2, -2, -2, -2}; /* We cache the results per-release; there are only a few of these... */
415 if (version >= CFSystemVersionMax) return false; /* Actually, we don't know the answer, and something scary is going on */
416
417 int versionIndex = resultIndex(version);
418 if (results[versionIndex] != -2) return results[versionIndex];
419
420 #if DEPLOYMENT_TARGET_MACOSX
421 if (_CFIsCFM()) {
422 results[versionIndex] = (version <= CFSystemVersionJaguar) ? true : false;
423 return results[versionIndex];
424 }
425 #endif
426
427 // Do a sanity check, since sometimes System framework is screwed up, which confuses everything.
428 // If the currently executing System framework has a version less than that of Leopard, warn.
429 static Boolean called = false;
430 if (!called) { // We do a check here in case CFLog() recursively calls this function.
431 called = true;
432 int32_t vers = NSVersionOfRunTimeLibrary("System");
433 if ((vers != -1) && (((unsigned int)vers) >> 16) < 89) { // 89 is the version of libSystem for first version of Leopard
434 CFLog(__kCFLogAssertion, CFSTR("System.framework version (%x) is wrong, this will break CF and up"), vers);
435 }
436 if (results[versionIndex] != -2) return results[versionIndex]; // If there was a recursive call that figured this out, return
437 }
438
439 #if DEPLOYMENT_TARGET_MACOSX
440 if (version < CFSystemVersionMax) {
441 // Compare the linked library versions of a Mac OS X app to framework versions found on Mac OS X.
442 checkLibrary("System", libSystemVersion); // Pretty much everyone links with this
443 checkLibrary("Cocoa", cocoaVersion);
444 checkLibrary("AppKit", appkitVersion);
445 checkLibrary("Foundation", fouVersion);
446 checkLibrary("CoreFoundation", cfVersion);
447 checkLibrary("Carbon", carbonVersion);
448 checkLibrary("ApplicationServices", applicationServicesVersion);
449 checkLibrary("CoreServices", coreServicesVersion);
450 checkLibrary("IOKit", iokitVersion);
451 } else {
452 }
453 #else
454 #endif
455
456 /* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */
457 return false;
458 }
459 #else
460 CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
461 return true;
462 }
463 #endif
464
465
466 #if DEPLOYMENT_TARGET_MACOSX
467 __private_extern__ void *__CFLookupCarbonCoreFunction(const char *name) {
468 static void *image = NULL;
469 if (NULL == image) {
470 image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL);
471 }
472 void *dyfunc = NULL;
473 if (image) {
474 dyfunc = dlsym(image, name);
475 }
476 return dyfunc;
477 }
478 #endif
479
480 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
481 __private_extern__ void *__CFLookupCFNetworkFunction(const char *name) {
482 static void *image = NULL;
483 if (NULL == image) {
484 const char *path = NULL;
485 if (!issetugid()) {
486 path = __CFgetenv("CFNETWORK_LIBRARY_PATH");
487 }
488 if (!path) {
489 #if DEPLOYMENT_TARGET_MACOSX
490 path = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork";
491 #else
492 path = "/System/Library/Frameworks/CFNetwork.framework/CFNetwork";
493 #endif
494 }
495 image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
496 }
497 void *dyfunc = NULL;
498 if (image) {
499 dyfunc = dlsym(image, name);
500 }
501 return dyfunc;
502 }
503 #endif
504
505
506 #ifndef __CFGetSessionID_defined
507
508 __private_extern__ uint32_t __CFGetSessionID(void) {
509 return 0;
510 }
511
512 #endif
513
514 __private_extern__ CFIndex __CFActiveProcessorCount() {
515 int32_t pcnt;
516 #if DEPLOYMENT_TARGET_WINDOWS
517 SYSTEM_INFO sysInfo;
518 GetSystemInfo(&sysInfo);
519 DWORD_PTR activeProcessorMask = sysInfo.dwActiveProcessorMask;
520 // assumes sizeof(DWORD_PTR) is 64 bits or less
521 uint64_t v = activeProcessorMask;
522 v = v - ((v >> 1) & 0x5555555555555555ULL);
523 v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
524 v = (v + (v >> 4)) & 0xf0f0f0f0f0f0f0fULL;
525 pcnt = (v * 0x0101010101010101ULL) >> ((sizeof(v) - 1) * 8);
526 #else
527 int32_t mib[] = {CTL_HW, HW_AVAILCPU};
528 size_t len = sizeof(pcnt);
529 int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &pcnt, &len, NULL, 0);
530 if (result != 0) {
531 pcnt = 0;
532 }
533 #endif
534 return pcnt;
535 }
536
537 const char *_CFPrintForDebugger(const void *obj) {
538 static char *result = NULL;
539 CFStringRef str;
540 CFIndex cnt = 0;
541
542 free(result); // Let go of result from previous call.
543 result = NULL;
544 if (obj) {
545 if (CFGetTypeID(obj) == CFStringGetTypeID()) {
546 // Makes Ali marginally happier
547 str = __CFCopyFormattingDescription(obj, NULL);
548 if (!str) str = CFCopyDescription(obj);
549 } else {
550 str = CFCopyDescription(obj);
551 }
552 } else {
553 str = (CFStringRef)CFRetain(CFSTR("(null)"));
554 }
555
556 if (str != NULL) {
557 CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt);
558 }
559 result = (char *) malloc(cnt + 2); // 1 for '\0', 1 for an optional '\n'
560 if (str != NULL) {
561 CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt);
562 }
563 result[cnt] = '\0';
564
565 if (str) CFRelease(str);
566 return result;
567 }
568
569 static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
570 CFStringRef str;
571 CFIndex idx, cnt;
572 CFStringInlineBuffer buffer;
573 bool lastNL = false;
574
575 if (obj) {
576 if (CFGetTypeID(obj) == CFStringGetTypeID()) {
577 // Makes Ali marginally happier
578 str = __CFCopyFormattingDescription(obj, NULL);
579 if (!str) str = CFCopyDescription(obj);
580 } else {
581 str = CFCopyDescription(obj);
582 }
583 } else {
584 str = (CFStringRef)CFRetain(CFSTR("(null)"));
585 }
586 cnt = CFStringGetLength(str);
587
588 // iTunes used OutputDebugStringW(theString);
589
590 CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
591 #if DEPLOYMENT_TARGET_WINDOWS
592 wchar_t *accumulatedBuffer = (wchar_t *)malloc((cnt+1) * sizeof(wchar_t));
593 #endif
594 for (idx = 0; idx < cnt; idx++) {
595 UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
596 #if DEPLOYMENT_TARGET_WINDOWS
597 if (file == stderr || file == stdout) {
598 accumulatedBuffer[idx] = ch;
599 lastNL = (ch == L'\n');
600 if (idx == (cnt - 1)) {
601 accumulatedBuffer[idx+1] = L'\0';
602 OutputDebugStringW(accumulatedBuffer);
603 free(accumulatedBuffer);
604 }
605 } else {
606 #endif
607
608 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
609 if (ch < 128) {
610 fprintf_l(file, NULL, "%c", ch);
611 lastNL = (ch == '\n');
612 } else {
613 fprintf_l(file, NULL, "\\u%04x", ch);
614 }
615 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
616 if (ch < 128) {
617 _fprintf_l(file, "%c", NULL, ch);
618 lastNL = (ch == '\n');
619 } else {
620 _fprintf_l(file, "\\u%04x", NULL, ch);
621 }
622 #endif
623 }
624 #if DEPLOYMENT_TARGET_WINDOWS
625 }
626 #endif
627 if (!lastNL) {
628 #if DEPLOYMENT_TARGET_WINDOWS
629 if (file == stderr || file == stdout) {
630 char outStr[2];
631 outStr[0] = '\n';
632 outStr[1] = '\0';
633 OutputDebugStringA(outStr);
634 } else {
635 _fprintf_l(file, "\n", NULL);
636 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
637 fprintf_l(file, NULL, "\n");
638 #endif
639 #if DEPLOYMENT_TARGET_WINDOWS
640 }
641 #endif
642 if (flush) fflush(file);
643 }
644
645 if (str) CFRelease(str);
646 }
647
648 void CFShow(const void *obj) {
649 _CFShowToFile(stderr, true, obj);
650 }
651
652
653 // message must be a UTF8-encoded, null-terminated, byte buffer with at least length bytes
654 typedef void (*CFLogFunc)(int32_t lev, const char *message, size_t length, char withBanner);
655
656 static Boolean also_do_stderr() {
657 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
658 if (!issetugid() && __CFgetenv("CFLOG_FORCE_STDERR")) {
659 return true;
660 }
661 struct stat sb;
662 int ret = fstat(STDERR_FILENO, &sb);
663 if (ret < 0) return false;
664 mode_t m = sb.st_mode & S_IFMT;
665 if (S_IFREG == m || S_IFSOCK == m) return true;
666 if (!(S_IFIFO == m || S_IFCHR == m)) return false; // disallow any whacky stuff
667 // if it could be a pipe back to launchd, fail
668 int64_t val = 0;
669 // assumes val is not written to on error
670 vproc_swap_integer(NULL, VPROC_GSK_IS_MANAGED, NULL, &val);
671 if (val) return false;
672 #endif
673 return true;
674 }
675
676 static void __CFLogCString(int32_t lev, const char *message, size_t length, char withBanner) {
677 char *banner = NULL;
678 char *time = NULL;
679 char *thread = NULL;
680 char *uid = NULL;
681 #if !(DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
682 int bannerLen = 0;
683 #endif
684 if (withBanner) {
685 CFAbsoluteTime at = CFAbsoluteTimeGetCurrent();
686 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, kCFCalendarIdentifierGregorian);
687 if (!calendar) goto after_banner;
688 CFTimeZoneRef tz = CFTimeZoneCopySystem();
689 if (!tz) {
690 CFRelease(calendar);
691 goto after_banner;
692 }
693 CFCalendarSetTimeZone(calendar, tz);
694 CFRelease(tz);
695 int32_t year, month, day, hour, minute, second;
696 Boolean dec = CFCalendarDecomposeAbsoluteTime(calendar, at, "yMdHms", &year, &month, &day, &hour, &minute, &second);
697 CFRelease(calendar);
698 if (!dec) goto after_banner;
699 double atf;
700 int32_t ms = (int32_t)floor(1000.0 * modf(at, &atf));
701 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
702 asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), pthread_mach_thread_np(pthread_self()));
703 asprintf(&thread, "%x", pthread_mach_thread_np(pthread_self()));
704 #else
705 bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), GetCurrentThreadId());
706 asprintf(&thread, "%x", GetCurrentThreadId());
707 #endif
708 asprintf(&time, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, ms);
709
710 }
711 after_banner:;
712 asprintf(&uid, "%d", geteuid());
713 aslclient asl = asl_open(NULL, "com.apple.console", ASL_OPT_NO_DELAY);
714 aslmsg msg = asl_new(ASL_TYPE_MSG);
715 asl_set(msg, "CFLog Local Time", time); // not to be documented, not public API
716 asl_set(msg, "CFLog Thread", thread); // not to be documented, not public API
717 asl_set(msg, "ReadUID", uid);
718 static const char *levstr[] = {"0", "1", "2", "3", "4", "5", "6", "7"};
719 asl_set(msg, ASL_KEY_LEVEL, levstr[lev]);
720 asl_set(msg, ASL_KEY_MSG, message);
721 asl_send(asl, msg);
722 asl_free(msg);
723 asl_close(asl);
724
725 if (also_do_stderr()) {
726 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
727 struct iovec v[3];
728 v[0].iov_base = banner;
729 v[0].iov_len = banner ? strlen(banner) : 0;
730 v[1].iov_base = (char *)message;
731 v[1].iov_len = length;
732 v[2].iov_base = "\n";
733 v[2].iov_len = (message[length - 1] != '\n') ? 1 : 0;
734 int nv = (v[0].iov_base ? 1 : 0) + 1 + (v[2].iov_len ? 1 : 0);
735 static CFSpinLock_t lock = CFSpinLockInit;
736 __CFSpinLock(&lock);
737 writev(STDERR_FILENO, v[0].iov_base ? v : v + 1, nv);
738 __CFSpinUnlock(&lock);
739 #else
740 size_t bufLen = bannerLen + length + 1;
741 char *buf = (char *)malloc(sizeof(char) * bufLen);
742 if (banner) {
743 // Copy the banner into the debug string
744 memmove_s(buf, bufLen, banner, bannerLen);
745
746 // Copy the message into the debug string
747 strcpy_s(buf + bannerLen, bufLen - bannerLen, message);
748 } else {
749 strcpy_s(buf, bufLen, message);
750 }
751 buf[bufLen - 1] = '\0';
752 fprintf_s(stderr, "%s\n", buf);
753 // This Win32 API call only prints when a debugger is active
754 // OutputDebugStringA(buf);
755 free(buf);
756 #endif
757 }
758
759 if (thread) free(thread);
760 if (time) free(time);
761 if (banner) free(banner);
762 if (uid) free(uid);
763 }
764
765 CF_EXPORT void _CFLogvEx(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) {
766 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
767 if (pthread_getspecific(__CFTSDKeyIsInCFLog)) return;
768 pthread_setspecific(__CFTSDKeyIsInCFLog, (void *)1);
769 #endif
770 CFStringRef str = format ? _CFStringCreateWithFormatAndArgumentsAux(kCFAllocatorSystemDefault, copyDescFunc, formatOptions, (CFStringRef)format, args) : 0;
771 CFIndex blen = str ? CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1 : 0;
772 char *buf = str ? (char *)malloc(blen) : 0;
773 if (str && buf) {
774 Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8);
775 size_t len = strlen(buf);
776 // silently ignore 0-length or really large messages, and levels outside the valid range
777 if (converted && !(len <= 0 || (1 << 24) < len) && !(lev < ASL_LEVEL_EMERG || ASL_LEVEL_DEBUG < lev)) {
778 (logit ? logit : __CFLogCString)(lev, buf, len, 1);
779 }
780 }
781 if (buf) free(buf);
782 if (str) CFRelease(str);
783 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
784 pthread_setspecific(__CFTSDKeyIsInCFLog, 0);
785 #endif
786 }
787
788 void CFLog(int32_t lev, CFStringRef format, ...) {
789 va_list args;
790 va_start(args, format);
791 _CFLogvEx(NULL, NULL, NULL, lev, format, args);
792 va_end(args);
793 }
794
795
796
797 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
798
799 kern_return_t _CFDiscorporateMemoryAllocate(CFDiscorporateMemory *hm, size_t size, bool purgeable) {
800 kern_return_t ret = KERN_SUCCESS;
801 size = round_page(size);
802 if (0 == size) size = vm_page_size;
803 memset(hm, 0, sizeof(CFDiscorporateMemory));
804 void *addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, VM_MAKE_TAG(0) | (purgeable ? VM_FLAGS_PURGABLE : 0), 0);
805 if ((uintptr_t)addr == -1) {
806 ret = KERN_NO_SPACE;
807 }
808 if (KERN_SUCCESS == ret) {
809 hm->address = (mach_vm_address_t)(uintptr_t)addr;
810 hm->size = (mach_vm_size_t)size;
811 hm->port = MACH_PORT_NULL;
812 hm->corporeal = true;
813 hm->purgeable = purgeable;
814 }
815 if (KERN_SUCCESS == ret) ret = mach_make_memory_entry_64(mach_task_self(), &hm->size, hm->address, VM_PROT_DEFAULT, &hm->port, MACH_PORT_NULL);
816 if (KERN_SUCCESS == ret) hm->corporeal = true;
817 return ret;
818 }
819
820 kern_return_t _CFDiscorporateMemoryDeallocate(CFDiscorporateMemory *hm) {
821 kern_return_t ret1 = KERN_SUCCESS, ret2 = KERN_SUCCESS;
822 if (hm->corporeal) ret1 = mach_vm_deallocate(mach_task_self(), hm->address, hm->size);
823 hm->address = MACH_VM_MIN_ADDRESS;
824 hm->corporeal = false;
825 ret2 = mach_port_deallocate(mach_task_self(), hm->port);
826 hm->port = MACH_PORT_NULL;
827 return ret1 != KERN_SUCCESS ? ret1 : ret2;
828 }
829
830 kern_return_t _CFDiscorporateMemoryDematerialize(CFDiscorporateMemory *hm) {
831 kern_return_t ret = KERN_SUCCESS;
832 if (!hm->corporeal) ret = KERN_INVALID_MEMORY_CONTROL;
833 int state = VM_PURGABLE_VOLATILE;
834 if (KERN_SUCCESS == ret) vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
835 if (KERN_SUCCESS == ret) ret = mach_vm_deallocate(mach_task_self(), hm->address, hm->size);
836 if (KERN_SUCCESS == ret) hm->address = MACH_VM_MIN_ADDRESS;
837 if (KERN_SUCCESS == ret) hm->corporeal = false;
838 return ret;
839 }
840
841 kern_return_t _CFDiscorporateMemoryMaterialize(CFDiscorporateMemory *hm) {
842 kern_return_t ret = KERN_SUCCESS;
843 if (hm->corporeal) ret = KERN_INVALID_MEMORY_CONTROL;
844 if (KERN_SUCCESS == ret) ret = mach_vm_map(mach_task_self(), &hm->address, hm->size, 0, VM_FLAGS_ANYWHERE, hm->port, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
845 if (KERN_SUCCESS == ret) hm->corporeal = true;
846 int state = VM_PURGABLE_NONVOLATILE;
847 if (KERN_SUCCESS == ret) ret = vm_purgable_control(mach_task_self(), (vm_address_t)hm->address, VM_PURGABLE_SET_STATE, &state);
848 if (KERN_SUCCESS == ret) if (VM_PURGABLE_EMPTY == state) ret = KERN_PROTECTION_FAILURE; // same as VM_PURGABLE_EMPTY
849 return ret;
850 }
851
852 #endif
853
854 #if DEPLOYMENT_TARGET_MACOSX
855
856 #define SUDDEN_TERMINATION_ENABLE_VPROC 1
857
858 #if SUDDEN_TERMINATION_ENABLE_VPROC
859
860 static CFSpinLock_t __CFProcessKillingLock = CFSpinLockInit;
861 static CFIndex __CFProcessKillingDisablingCount = 1;
862 static Boolean __CFProcessKillingWasTurnedOn = false;
863
864 void _CFSuddenTerminationDisable(void) {
865 __CFSpinLock(&__CFProcessKillingLock);
866 __CFProcessKillingDisablingCount++;
867 _vproc_transaction_begin();
868 __CFSpinUnlock(&__CFProcessKillingLock);
869 }
870
871 void _CFSuddenTerminationEnable(void) {
872 // In our model the first call of _CFSuddenTerminationEnable() that does not balance a previous call of _CFSuddenTerminationDisable() actually enables sudden termination so we have to keep a count that's almost redundant with vproc's.
873 __CFSpinLock(&__CFProcessKillingLock);
874 __CFProcessKillingDisablingCount--;
875 if (__CFProcessKillingDisablingCount==0 && !__CFProcessKillingWasTurnedOn) {
876 int64_t transactionsAreToBeEnabled = 1;
877 int64_t transactionsWereAlreadyEnabled = 0;
878 vproc_err_t verr = vproc_swap_integer(NULL, VPROC_GSK_TRANSACTIONS_ENABLED, &transactionsAreToBeEnabled, &transactionsWereAlreadyEnabled);
879 if (!verr) {
880 if (!transactionsWereAlreadyEnabled) {
881 // We set __CFProcessKillingWasTurnedOn below regardless of success because there's no point in retrying.
882 } // else this process was launched by launchd with transactions already enabled because EnableTransactions was set to true in the launchd .plist file.
883 } // else this process was not launched by launchd and the fix for 6416724 is not in the build yet.
884 __CFProcessKillingWasTurnedOn = true;
885 } else {
886 // Mail seems to have sudden termination disabling/enabling imbalance bugs that make _vproc_transaction_end() kill the app but we don't want that to prevent our submission of the fix 6382488.
887 if (__CFProcessKillingDisablingCount>=0) {
888 _vproc_transaction_end();
889 } else {
890 CFLog(kCFLogLevelError, CFSTR("-[NSProcessInfo enableSuddenTermination] has been invoked more times than necessary to balance invocations of -[NSProcessInfo disableSuddenTermination]. Ignoring."));
891 }
892 }
893 __CFSpinUnlock(&__CFProcessKillingLock);
894 }
895
896 void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
897 // This is for when the caller wants to try to exit quickly if possible but not automatically exit the process when it next becomes clean, because quitting might still be cancelled by the user.
898 __CFSpinLock(&__CFProcessKillingLock);
899 // Check _vproc_transaction_count() because other code in the process might go straight to the vproc APIs but also check __CFProcessKillingWasTurnedOn because _vproc_transaction_count() can return 0 when transactions didn't even get enabled.
900 if (_vproc_transaction_count()==0 && __CFProcessKillingWasTurnedOn) {
901 _exit(exitStatus);
902 }
903 __CFSpinUnlock(&__CFProcessKillingLock);
904 }
905
906 void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
907 // The user has had their final opportunity to cancel quitting. Exit as soon as the process is clean. Same carefulness as in _CFSuddenTerminationExitIfTerminationEnabled().
908 __CFSpinLock(&__CFProcessKillingLock);
909 if (__CFProcessKillingWasTurnedOn) {
910 _vproc_transaction_try_exit(exitStatus);
911 }
912 __CFSpinUnlock(&__CFProcessKillingLock);
913 }
914
915 size_t _CFSuddenTerminationDisablingCount(void) {
916 // Until sudden termination has been really enabled vproc's notion of the count is off by one but we can't just return __CFProcessKillingDisablingCount() because that doesn't take into account stuff that calls the vproc_transaction functions behind our back.
917 return _vproc_transaction_count() + (__CFProcessKillingWasTurnedOn ? 0 : 1);
918 }
919
920 #else
921
922 #warning Building with vproc sudden termination API disabled.
923
924 static CFSpinLock_t __CFProcessKillingLock = CFSpinLockInit;
925 static size_t __CFProcessKillingDisablingCount = 1;
926 static Boolean __CFProcessExitNextTimeKillingIsEnabled = false;
927 static int32_t __CFProcessExitStatus = 0;
928 static int __CFProcessIsKillableNotifyToken;
929 static Boolean __CFProcessIsKillableNotifyTokenIsFigured = false;
930
931 __private_extern__ void _CFSetSuddenTerminationEnabled(Boolean isEnabled) {
932 if (!__CFProcessIsKillableNotifyTokenIsFigured) {
933 char *notificationName = NULL;
934 asprintf(&notificationName, "com.apple.isKillable.%i", getpid());
935 uint32_t notifyResult = notify_register_check(notificationName, &__CFProcessIsKillableNotifyToken);
936 if (notifyResult != NOTIFY_STATUS_OK) {
937 CFLog(kCFLogLevelError, CFSTR("%s: notify_register_check() returned %i."), __PRETTY_FUNCTION__, notifyResult);
938 }
939 free(notificationName);
940 __CFProcessIsKillableNotifyTokenIsFigured = true;
941 }
942 uint32_t notifyResult = notify_set_state(__CFProcessIsKillableNotifyToken, isEnabled);
943 if (notifyResult != NOTIFY_STATUS_OK) {
944 CFLog(kCFLogLevelError, CFSTR("%s: notify_set_state() returned %i"), __PRETTY_FUNCTION__, notifyResult);
945 }
946 }
947
948 void _CFSuddenTerminationDisable(void) {
949 __CFSpinLock(&__CFProcessKillingLock);
950 if (__CFProcessKillingDisablingCount == 0) {
951 _CFSetSuddenTerminationEnabled(false);
952 }
953 __CFProcessKillingDisablingCount++;
954 __CFSpinUnlock(&__CFProcessKillingLock);
955 }
956
957 void _CFSuddenTerminationEnable(void) {
958 __CFSpinLock(&__CFProcessKillingLock);
959 __CFProcessKillingDisablingCount--;
960 if (__CFProcessKillingDisablingCount == 0) {
961 if (__CFProcessExitNextTimeKillingIsEnabled) {
962 _exit(__CFProcessExitStatus);
963 } else {
964 _CFSetSuddenTerminationEnabled(true);
965 }
966 }
967 __CFSpinUnlock(&__CFProcessKillingLock);
968 }
969
970 void _CFSuddenTerminationExitIfTerminationEnabled(int exitStatus) {
971 __CFSpinLock(&__CFProcessKillingLock);
972 if (__CFProcessKillingDisablingCount == 0) {
973 _exit(exitStatus);
974 }
975 __CFSpinUnlock(&__CFProcessKillingLock);
976 }
977
978 void _CFSuddenTerminationExitWhenTerminationEnabled(int exitStatus) {
979 __CFSpinLock(&__CFProcessKillingLock);
980 if (__CFProcessKillingDisablingCount == 0) {
981 _exit(exitStatus);
982 } else {
983 __CFProcessExitNextTimeKillingIsEnabled = YES;
984 __CFProcessExitStatus = exitStatus;
985 }
986 __CFSpinUnlock(&__CFProcessKillingLock);
987 }
988
989 size_t _CFSuddenTerminationDisablingCount(void) {
990 return __CFProcessKillingDisablingCount;
991 }
992
993 #endif
994
995 #endif
996
997 #if 0
998 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
999
1000 typedef void (^ThrottleTypeA)(void); // allows calls per nanoseconds
1001 typedef void (^ThrottleTypeB)(uint64_t amt); // allows amount per nanoseconds
1002
1003 __private_extern__ ThrottleTypeA __CFCreateThrottleTypeA(uint16_t calls, uint64_t nanoseconds) {
1004 struct mach_timebase_info info;
1005 mach_timebase_info(&info);
1006 uint64_t period = nanoseconds / info.numer * info.denom;
1007
1008 if (0 == calls || 0 == period) return NULL;
1009
1010 __block OSSpinLock b_lock = OS_SPINLOCK_INIT;
1011 __block uint64_t b_values[calls];
1012 __block uint64_t *b_oldest = b_values;
1013 memset(b_values, 0, sizeof(b_values));
1014
1015 return Block_copy(^{
1016 uint64_t curr_time = mach_absolute_time();
1017 OSSpinLockLock(&b_lock);
1018 uint64_t next_time = *b_oldest + period;
1019 *b_oldest = (curr_time < next_time) ? next_time : curr_time;
1020 b_oldest++;
1021 if (b_values + calls <= b_oldest) b_oldest = b_values;
1022 OSSpinLockUnlock(&b_lock);
1023 if (curr_time < next_time) {
1024 mach_wait_until(next_time);
1025 }
1026 });
1027 }
1028
1029 __private_extern__ ThrottleTypeB __CFCreateThrottleTypeB(uint64_t amount, uint64_t nanoseconds) {
1030 struct mach_timebase_info info;
1031 mach_timebase_info(&info);
1032 uint64_t period = nanoseconds / info.numer * info.denom;
1033
1034 if (0 == amount || 0 == period) return NULL;
1035
1036 __block OSSpinLock b_lock = OS_SPINLOCK_INIT;
1037 __block uint64_t b_sum = 0ULL;
1038 __block uint16_t b_num_values = 8;
1039 __block uint64_t *b_values = calloc(b_num_values, 2 * sizeof(uint64_t));
1040 __block uint64_t *b_oldest = b_values;
1041
1042 return Block_copy(^(uint64_t amt){
1043 OSSpinLockLock(&b_lock);
1044 // unimplemented
1045 OSSpinLockUnlock(&b_lock);
1046 });
1047 }
1048
1049 #endif
1050 #endif
1051