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