]> git.saurik.com Git - apple/cf.git/blame - CFPlatform.c
CF-1151.16.tar.gz
[apple/cf.git] / CFPlatform.c
CommitLineData
9ce05555 1/*
d8b101a4 2 * Copyright (c) 2014 Apple Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
d7384798 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.
d7384798 12 *
9ce05555
A
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.
d7384798 20 *
9ce05555
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
f64f9b69 23
9ce05555 24/* CFPlatform.c
d7384798 25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
8ca704e1 26 Responsibility: Tony Parker
9ce05555
A
27*/
28
29#include "CFInternal.h"
cf7d2af9 30#include <CoreFoundation/CFPriv.h>
856091c5 31#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
cf7d2af9
A
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <pwd.h>
38 #include <crt_externs.h>
39 #include <mach-o/dyld.h>
a48904a4 40 #include <pthread/tsd_private.h>
cf7d2af9 41#endif
bd5b749c 42
cf7d2af9
A
43#if DEPLOYMENT_TARGET_WINDOWS
44#include <shellapi.h>
45#include <shlobj.h>
8ca704e1 46#include <WinIoCtl.h>
cf7d2af9
A
47
48#define getcwd _NS_getcwd
49
50#endif
51
856091c5 52#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
9ce05555
A
53#define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8
54#else
55#define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding()
56#endif
57
856091c5 58extern void __CFGetUGIDs(uid_t *euid, gid_t *egid);
9ce05555 59
856091c5 60#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
bd5b749c
A
61// CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these
62char **_CFArgv(void) { return *_NSGetArgv(); }
63int _CFArgc(void) { return *_NSGetArgc(); }
d8925383 64#endif
9ce05555
A
65
66
a48904a4 67CF_PRIVATE Boolean _CFGetCurrentDirectory(char *path, int maxlen) {
9ce05555 68 return getcwd(path, maxlen) != NULL;
9ce05555
A
69}
70
cf7d2af9
A
71#if DEPLOYMENT_TARGET_WINDOWS
72// Returns the path to the CF DLL, which we can then use to find resources like char sets
73bool bDllPathCached = false;
a48904a4 74CF_PRIVATE const wchar_t *_CFDLLPath(void) {
cf7d2af9
A
75 static wchar_t cachedPath[MAX_PATH+1];
76
77 if (!bDllPathCached) {
78#ifdef _DEBUG
79 // might be nice to get this from the project file at some point
80 wchar_t *DLLFileName = L"CoreFoundation_debug.dll";
81#else
82 wchar_t *DLLFileName = L"CoreFoundation.dll";
83#endif
84 HMODULE ourModule = GetModuleHandleW(DLLFileName);
85
86 CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed");
87
88 DWORD wResult = GetModuleFileNameW(ourModule, cachedPath, MAX_PATH+1);
89 CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError());
90 CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", cachedPath);
91
92 // strip off last component, the DLL name
93 CFIndex idx;
94 for (idx = wResult - 1; idx; idx--) {
95 if ('\\' == cachedPath[idx]) {
96 cachedPath[idx] = '\0';
97 break;
9ce05555 98 }
9ce05555 99 }
cf7d2af9 100 bDllPathCached = true;
9ce05555 101 }
cf7d2af9 102 return cachedPath;
9ce05555 103}
d8925383 104#endif
9ce05555 105
9ce05555 106static const char *__CFProcessPath = NULL;
d8925383 107static const char *__CFprogname = NULL;
9ce05555 108
d8925383
A
109const char **_CFGetProgname(void) {
110 if (!__CFprogname)
111 _CFProcessPath(); // sets up __CFprogname as a side-effect
9ce05555
A
112 return &__CFprogname;
113}
114
d8925383
A
115const char **_CFGetProcessPath(void) {
116 if (!__CFProcessPath)
117 _CFProcessPath(); // sets up __CFProcessPath as a side-effect
118 return &__CFProcessPath;
119}
120
cf7d2af9 121#if DEPLOYMENT_TARGET_WINDOWS
9ce05555 122const char *_CFProcessPath(void) {
9ce05555 123 if (__CFProcessPath) return __CFProcessPath;
cf7d2af9
A
124 wchar_t buf[CFMaxPathSize] = {0};
125 DWORD rlen = GetModuleFileNameW(NULL, buf, sizeof(buf) / sizeof(buf[0]));
126 if (0 < rlen) {
127 char asciiBuf[CFMaxPathSize] = {0};
128 int res = WideCharToMultiByte(CP_UTF8, 0, buf, rlen, asciiBuf, sizeof(asciiBuf) / sizeof(asciiBuf[0]), NULL, NULL);
129 if (0 < res) {
130 __CFProcessPath = strdup(asciiBuf);
131 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
132 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
133 }
134 }
135 if (!__CFProcessPath) {
136 __CFProcessPath = "";
137 __CFprogname = __CFProcessPath;
138 }
139 return __CFProcessPath;
140}
141#endif
bd5b749c 142
856091c5 143#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
cf7d2af9
A
144const char *_CFProcessPath(void) {
145 if (__CFProcessPath) return __CFProcessPath;
bd5b749c
A
146#if DEPLOYMENT_TARGET_MACOSX
147 if (!issetugid()) {
cf7d2af9
A
148 const char *path = (char *)__CFgetenv("CFProcessPath");
149 if (path) {
150 __CFProcessPath = strdup(path);
151 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
152 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
153 return __CFProcessPath;
9ce05555
A
154 }
155 }
bd5b749c 156#endif
cf7d2af9
A
157 uint32_t size = CFMaxPathSize;
158 char buffer[size];
159 if (0 == _NSGetExecutablePath(buffer, &size)) {
cf7d2af9
A
160 __CFProcessPath = strdup(buffer);
161 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
162 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
9ce05555
A
163 }
164 if (!__CFProcessPath) {
165 __CFProcessPath = "";
d8925383 166 __CFprogname = __CFProcessPath;
9ce05555
A
167 }
168 return __CFProcessPath;
169}
cf7d2af9 170#endif
9ce05555 171
8ca704e1
A
172#if DEPLOYMENT_TARGET_LINUX
173#include <unistd.h>
174
175const char *_CFProcessPath(void) {
176 if (__CFProcessPath) return __CFProcessPath;
177 char buf[CFMaxPathSize + 1];
178
179 ssize_t res = readlink("/proc/self/exe", buf, CFMaxPathSize);
180 if (res > 0) {
181 // null terminate, readlink does not
182 buf[res] = 0;
183 __CFProcessPath = strdup(buf);
184 __CFprogname = strrchr(__CFProcessPath, PATH_SEP);
185 __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath);
186 } else {
187 __CFProcessPath = "";
188 __CFprogname = __CFProcessPath;
189 }
190 return __CFProcessPath;
191}
192#endif
193
a48904a4 194CF_PRIVATE CFStringRef _CFProcessNameString(void) {
9ce05555
A
195 static CFStringRef __CFProcessNameString = NULL;
196 if (!__CFProcessNameString) {
197 const char *processName = *_CFGetProgname();
198 if (!processName) processName = "";
cf7d2af9
A
199 CFStringRef newStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, processName, kCFPlatformInterfaceStringEncoding);
200 if (!OSAtomicCompareAndSwapPtrBarrier(NULL, (void *) newStr, (void * volatile *)& __CFProcessNameString)) {
201 CFRelease(newStr); // someone else made the assignment, so just release the extra string.
202 }
9ce05555
A
203 }
204 return __CFProcessNameString;
205}
206
d8925383 207
856091c5 208#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
8ca704e1
A
209
210#include <pwd.h>
856091c5 211#include <sys/param.h>
8ca704e1 212
856091c5
A
213// Set the fallBackToHome parameter to true if we should fall back to the HOME environment variable if all else fails. Otherwise return NULL.
214static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd, bool fallBackToHome) {
215 const char *fixedHomePath = issetugid() ? NULL : __CFgetenv("CFFIXED_USER_HOME");
216 const char *homePath = NULL;
217
218 // Calculate the home directory we will use
219 // First try CFFIXED_USER_HOME (only if not setugid), then fall back to the upwd, then fall back to HOME environment variable
9ce05555 220 CFURLRef home = NULL;
856091c5
A
221 if (!issetugid() && fixedHomePath) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)fixedHomePath, strlen(fixedHomePath), true);
222 if (!home && upwd && upwd->pw_dir) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)upwd->pw_dir, strlen(upwd->pw_dir), true);
223 if (fallBackToHome && !home) homePath = __CFgetenv("HOME");
224 if (fallBackToHome && !home && homePath) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)homePath, strlen(homePath), true);
225
9ce05555
A
226 return home;
227}
228
856091c5
A
229#endif
230
231
232#define CFMaxHostNameLength 256
233#define CFMaxHostNameSize (CFMaxHostNameLength+1)
234
a48904a4 235CF_PRIVATE CFStringRef _CFStringCreateHostName(void) {
856091c5
A
236 char myName[CFMaxHostNameSize];
237
238 // return @"" instead of nil a la CFUserName() and Ali Ozer
239 if (0 != gethostname(myName, CFMaxHostNameSize)) myName[0] = '\0';
240 return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding);
241}
242
243/* These are sanitized versions of the above functions. We might want to eliminate the above ones someday.
244 These can return NULL.
245*/
246CF_EXPORT CFStringRef CFGetUserName(void) {
247 return CFCopyUserName();
248}
9ce05555 249
856091c5
A
250CF_EXPORT CFStringRef CFCopyUserName(void) {
251 CFStringRef result = NULL;
252#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
253 uid_t euid;
254 __CFGetUGIDs(&euid, NULL);
255 struct passwd *upwd = getpwuid(euid ? euid : getuid());
9ce05555 256 if (upwd && upwd->pw_name) {
856091c5 257 result = CFStringCreateWithCString(kCFAllocatorSystemDefault, upwd->pw_name, kCFPlatformInterfaceStringEncoding);
9ce05555 258 } else {
cf7d2af9 259 const char *cuser = __CFgetenv("USER");
856091c5
A
260 if (cuser) {
261 result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cuser, kCFPlatformInterfaceStringEncoding);
262 }
9ce05555 263 }
856091c5
A
264#elif DEPLOYMENT_TARGET_WINDOWS
265 wchar_t username[1040];
266 DWORD size = 1040;
267 username[0] = 0;
268 if (GetUserNameW(username, &size)) {
269 // discount the extra NULL by decrementing the size
270 result = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)username, size - 1);
271 } else {
272 const char *cname = __CFgetenv("USERNAME");
273 if (cname) {
274 result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding);
275 }
276 }
277#else
278#error Dont know how to compute user name on this platform
9ce05555 279#endif
856091c5
A
280 if (!result)
281 result = (CFStringRef)CFRetain(CFSTR(""));
282 return result;
283}
9ce05555 284
856091c5
A
285CFURLRef CFCopyHomeDirectoryURL(void) {
286#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
287 uid_t euid;
288 __CFGetUGIDs(&euid, NULL);
289 struct passwd *upwd = getpwuid(euid ? euid : getuid());
290 return _CFCopyHomeDirURLForUser(upwd, true);
cf7d2af9 291#elif DEPLOYMENT_TARGET_WINDOWS
cf7d2af9
A
292 CFURLRef retVal = NULL;
293 CFIndex len = 0;
294 CFStringRef str = NULL;
856091c5 295
8ca704e1
A
296 UniChar pathChars[MAX_PATH];
297 if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (wchar_t *)pathChars)) {
298 len = (CFIndex)wcslen((wchar_t *)pathChars);
299 str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathChars, len);
300 retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true);
301 CFRelease(str);
302 }
856091c5 303
8ca704e1
A
304 if (!retVal) {
305 // Fall back to environment variable, but this will not be unicode compatible
cf7d2af9
A
306 const char *cpath = __CFgetenv("HOMEPATH");
307 const char *cdrive = __CFgetenv("HOMEDRIVE");
9ce05555
A
308 if (cdrive && cpath) {
309 char fullPath[CFMaxPathSize];
bd5b749c
A
310 strlcpy(fullPath, cdrive, sizeof(fullPath));
311 strlcat(fullPath, cpath, sizeof(fullPath));
312 str = CFStringCreateWithCString(kCFAllocatorSystemDefault, fullPath, kCFPlatformInterfaceStringEncoding);
cf7d2af9 313 retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true);
9ce05555 314 CFRelease(str);
cf7d2af9
A
315 }
316 }
856091c5 317
cf7d2af9 318 if (!retVal) {
8ca704e1
A
319 // Last resort: We have to get "some" directory location, so fall-back to the processes current directory.
320 UniChar currDir[MAX_PATH];
321 DWORD dwChars = GetCurrentDirectoryW(MAX_PATH + 1, (wchar_t *)currDir);
322 if (dwChars > 0) {
323 len = (CFIndex)wcslen((wchar_t *)currDir);
324 str = CFStringCreateWithCharacters(kCFAllocatorDefault, currDir, len);
325 retVal = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true);
cf7d2af9
A
326 CFRelease(str);
327 }
cf7d2af9 328 }
856091c5 329
8ca704e1
A
330 // We could do more here (as in KB Article Q101507). If that article is to be believed, we should only run into this case on Win95, or through user error.
331 CFStringRef testPath = CFURLCopyFileSystemPath(retVal, kCFURLWindowsPathStyle);
cf7d2af9
A
332 if (CFStringGetLength(testPath) == 0) {
333 CFRelease(retVal);
8ca704e1 334 retVal = NULL;
cf7d2af9 335 }
8ca704e1 336 if (testPath) CFRelease(testPath);
856091c5 337
cf7d2af9 338 return retVal;
9ce05555
A
339#else
340#error Dont know how to compute users home directories on this platform
341#endif
342}
343
856091c5
A
344CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) {
345#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
346 if (!uName) {
347 uid_t euid;
348 __CFGetUGIDs(&euid, NULL);
349 struct passwd *upwd = getpwuid(euid ? euid : getuid());
350 return _CFCopyHomeDirURLForUser(upwd, true);
351 } else {
352 struct passwd *upwd = NULL;
353 char buf[128], *user;
354 SInt32 len = CFStringGetLength(uName), size = CFStringGetMaximumSizeForEncoding(len, kCFPlatformInterfaceStringEncoding);
355 CFIndex usedSize;
356 if (size < 127) {
357 user = buf;
358 } else {
359 user = CFAllocatorAllocate(kCFAllocatorSystemDefault, size+1, 0);
360 }
361 if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, (uint8_t *)user, size, &usedSize) == len) {
362 user[usedSize] = '\0';
363 upwd = getpwnam(user);
364 }
365 if (buf != user) {
366 CFAllocatorDeallocate(kCFAllocatorSystemDefault, user);
367 }
368 return _CFCopyHomeDirURLForUser(upwd, false);
369 }
cf7d2af9 370#elif DEPLOYMENT_TARGET_WINDOWS
856091c5
A
371 // This code can only get the directory for the current user
372 CFStringRef userName = uName ? CFCopyUserName() : NULL;
373 if (uName && !CFEqual(uName, userName)) {
374 CFLog(kCFLogLevelError, CFSTR("CFCopyHomeDirectoryURLForUser(): Unable to get home directory for other user"));
375 if (userName) CFRelease(userName);
376 return NULL;
9ce05555 377 }
856091c5
A
378 if (userName) CFRelease(userName);
379 return CFCopyHomeDirectoryURL();
9ce05555 380#else
856091c5 381#error Dont know how to compute users home directories on this platform
9ce05555 382#endif
9ce05555
A
383}
384
9ce05555 385
9ce05555
A
386#undef CFMaxHostNameLength
387#undef CFMaxHostNameSize
388
cf7d2af9
A
389#if DEPLOYMENT_TARGET_WINDOWS
390CF_INLINE CFIndex strlen_UniChar(const UniChar* p) {
391 CFIndex result = 0;
392 while ((*p++) != 0)
393 ++result;
394 return result;
395}
396
397//#include <shfolder.h>
398/*
399 * _CFCreateApplicationRepositoryPath returns the path to the application's
400 * repository in a CFMutableStringRef. The path returned will be:
401 * <nFolder_path>\Apple Computer\<bundle_name>\
402 * or if the bundle name cannot be obtained:
403 * <nFolder_path>\Apple Computer\
404 * where nFolder_path is obtained by calling SHGetFolderPath with nFolder
405 * (for example, with CSIDL_APPDATA or CSIDL_LOCAL_APPDATA).
406 *
407 * The CFMutableStringRef result must be released by the caller.
408 *
409 * If anything fails along the way, the result will be NULL.
410 */
411CF_EXPORT CFMutableStringRef _CFCreateApplicationRepositoryPath(CFAllocatorRef alloc, int nFolder) {
412 CFMutableStringRef result = NULL;
413 UniChar szPath[MAX_PATH];
414
415 // get the current path to the data repository: CSIDL_APPDATA (roaming) or CSIDL_LOCAL_APPDATA (nonroaming)
416 if (S_OK == SHGetFolderPathW(NULL, nFolder, NULL, 0, (wchar_t *) szPath)) {
417 CFStringRef directoryPath;
418
419 // make it a CFString
420 directoryPath = CFStringCreateWithCharacters(alloc, szPath, strlen_UniChar(szPath));
421 if (directoryPath) {
422 CFBundleRef bundle;
423 CFStringRef bundleName;
424 CFStringRef completePath;
425
426 // attempt to get the bundle name
427 bundle = CFBundleGetMainBundle();
428 if (bundle) {
429 bundleName = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
430 }
431 else {
432 bundleName = NULL;
433 }
434
435 if (bundleName) {
436 // the path will be "<directoryPath>\Apple Computer\<bundleName>\" if there is a bundle name
437 completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple Computer\\%@\\"), directoryPath, bundleName);
438 }
439 else {
440 // or "<directoryPath>\Apple Computer\" if there is no bundle name.
441 completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple Computer\\"), directoryPath);
442 }
443
444 CFRelease(directoryPath);
445
446 // make a mutable copy to return
447 if (completePath) {
448 result = CFStringCreateMutableCopy(alloc, 0, completePath);
449 CFRelease(completePath);
450 }
451 }
452 }
453
454 return ( result );
455}
456#endif
457
8ca704e1
A
458#pragma mark -
459#pragma mark Thread Functions
460
461#if DEPLOYMENT_TARGET_WINDOWS
462
463// This code from here:
464// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
465
466const DWORD MS_VC_EXCEPTION=0x406D1388;
467#pragma pack(push,8)
468typedef struct tagTHREADNAME_INFO
469{
470 DWORD dwType; // Must be 0x1000.
471 LPCSTR szName; // Pointer to name (in user addr space).
472 DWORD dwThreadID; // Thread ID (-1=caller thread).
473 DWORD dwFlags; // Reserved for future use, must be zero.
474} THREADNAME_INFO;
475#pragma pack(pop)
476
477CF_EXPORT void _NS_pthread_setname_np(const char *name) {
478 THREADNAME_INFO info;
479 info.dwType = 0x1000;
480 info.szName = name;
481 info.dwThreadID = GetCurrentThreadId();
482 info.dwFlags = 0;
483
484 __try
485 {
486 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
487 }
488 __except(EXCEPTION_EXECUTE_HANDLER)
489 {
490 }
491}
492
493static pthread_t __initialPthread = { NULL, 0 };
494
495CF_EXPORT int _NS_pthread_main_np() {
496 pthread_t me = pthread_self();
497 if (NULL == __initialPthread.p) {
498 __initialPthread.p = me.p;
499 __initialPthread.x = me.x;
500 }
501 return (pthread_equal(__initialPthread, me));
502}
503
504#endif
505
506#pragma mark -
507#pragma mark Thread Local Data
508
509// If slot >= CF_TSD_MAX_SLOTS, the SPI functions will crash at NULL + slot address.
510// If thread data has been torn down, these functions should crash on CF_TSD_BAD_PTR + slot address.
511#define CF_TSD_MAX_SLOTS 70
512
856091c5 513#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
a48904a4 514static const unsigned long CF_TSD_KEY = __PTK_FRAMEWORK_COREFOUNDATION_KEY5;
8ca704e1
A
515#endif
516
517// Windows and Linux, not sure how many times the destructor could get called; CF_TSD_MAX_DESTRUCTOR_CALLS could be 1
518
519#define CF_TSD_BAD_PTR ((void *)0x1000)
520
521typedef void (*tsdDestructor)(void *);
522
523// Data structure to hold TSD data, cleanup functions for each
524typedef struct __CFTSDTable {
525 uint32_t destructorCount;
526 uintptr_t data[CF_TSD_MAX_SLOTS];
527 tsdDestructor destructors[CF_TSD_MAX_SLOTS];
528} __CFTSDTable;
529
530static void __CFTSDFinalize(void *arg);
531
532#if DEPLOYMENT_TARGET_WINDOWS
533
8ca704e1
A
534static DWORD __CFTSDIndexKey = 0xFFFFFFFF;
535
536// Called from CFRuntime's startup code, on Windows only
a48904a4 537CF_PRIVATE void __CFTSDWindowsInitialize() {
8ca704e1
A
538 __CFTSDIndexKey = TlsAlloc();
539}
540
541// Called from CFRuntime's cleanup code, on Windows only
a48904a4 542CF_PRIVATE void __CFTSDWindowsCleanup() {
8ca704e1
A
543 TlsFree(__CFTSDIndexKey);
544}
545
546// Called for each thread as it exits, on Windows only
a48904a4 547CF_PRIVATE void __CFFinalizeWindowsThreadData() {
8ca704e1
A
548 // Normally, this should call the finalizer several times to emulate the behavior of pthreads on Windows. However, a few bugs keep us from doing this:
549 // <rdar://problem/8989063> REGRESSION(CF-610-CF-611): Crash closing Safari in BonjourDB destructor (Windows)
550 // <rdar://problem/9326814> SyncUIHandler crashes after conflict is resolved and we do SyncNow
551 // and a bug in dispatch keeps us from using pthreadsWin32 directly, because it does not deal with the case of a dispatch_async happening during process exit (it attempts to create a thread, but that is illegal on Win32 and causes a hang).
552 // So instead we just finalize once, which is the behavior pre-Airwolf anyway
553 __CFTSDFinalize(TlsGetValue(__CFTSDIndexKey));
554}
555
556#endif
557
558#if DEPLOYMENT_TARGET_LINUX
559
560static pthread_key_t __CFTSDIndexKey;
561
562// Called from CFRuntime's startup code, on Linux only
a48904a4 563CF_PRIVATE void __CFTSDLinuxInitialize() {
8ca704e1
A
564 (void)pthread_key_create(&__CFTSDIndexKey, __CFTSDFinalize);
565}
566
567#endif
568
569static void __CFTSDSetSpecific(void *arg) {
856091c5 570#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
a48904a4 571 _pthread_setspecific_direct(CF_TSD_KEY, arg);
8ca704e1
A
572#elif DEPLOYMENT_TARGET_LINUX
573 pthread_setspecific(__CFTSDIndexKey, arg);
574#elif DEPLOYMENT_TARGET_WINDOWS
575 TlsSetValue(__CFTSDIndexKey, arg);
576#endif
577}
578
579static void *__CFTSDGetSpecific() {
856091c5 580#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
a48904a4 581 return _pthread_getspecific_direct(CF_TSD_KEY);
8ca704e1
A
582#elif DEPLOYMENT_TARGET_LINUX
583 return pthread_getspecific(__CFTSDIndexKey);
584#elif DEPLOYMENT_TARGET_WINDOWS
585 return TlsGetValue(__CFTSDIndexKey);
586#endif
587}
588
589static void __CFTSDFinalize(void *arg) {
856091c5 590 // Set our TSD so we're called again by pthreads. It will call the destructor PTHREAD_DESTRUCTOR_ITERATIONS times as long as a value is set in the thread specific data. We handle each case below.
8ca704e1
A
591 __CFTSDSetSpecific(arg);
592
593 if (!arg || arg == CF_TSD_BAD_PTR) {
594 // We've already been destroyed. The call above set the bad pointer again. Now we just return.
595 return;
596 }
597
598 __CFTSDTable *table = (__CFTSDTable *)arg;
599 table->destructorCount++;
600
856091c5 601 // On first calls invoke destructor. Later we destroy the data.
8ca704e1
A
602 // Note that invocation of the destructor may cause a value to be set again in the per-thread data slots. The destructor count and destructors are preserved.
603 // This logic is basically the same as what pthreads does. We just skip the 'created' flag.
8ca704e1
A
604 for (int32_t i = 0; i < CF_TSD_MAX_SLOTS; i++) {
605 if (table->data[i] && table->destructors[i]) {
606 uintptr_t old = table->data[i];
607 table->data[i] = (uintptr_t)NULL;
608 table->destructors[i]((void *)(old));
609 }
610 }
8ca704e1 611
856091c5 612 if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { // On PTHREAD_DESTRUCTOR_ITERATIONS-1 call, destroy our data
8ca704e1
A
613 free(table);
614
615 // Now if the destructor is called again we will take the shortcut at the beginning of this function.
616 __CFTSDSetSpecific(CF_TSD_BAD_PTR);
617 return;
618 }
619}
620
856091c5 621#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
8ca704e1
A
622extern int pthread_key_init_np(int, void (*)(void *));
623#endif
624
625// Get or initialize a thread local storage. It is created on demand.
626static __CFTSDTable *__CFTSDGetTable() {
627 __CFTSDTable *table = (__CFTSDTable *)__CFTSDGetSpecific();
628 // Make sure we're not setting data again after destruction.
629 if (table == CF_TSD_BAD_PTR) {
630 return NULL;
631 }
632 // Create table on demand
633 if (!table) {
634 // This memory is freed in the finalize function
635 table = (__CFTSDTable *)calloc(1, sizeof(__CFTSDTable));
636 // Windows and Linux have created the table already, we need to initialize it here for other platforms. On Windows, the cleanup function is called by DllMain when a thread exits. On Linux the destructor is set at init time.
856091c5 637#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
8ca704e1
A
638 pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize);
639#endif
640 __CFTSDSetSpecific(table);
641 }
642
643 return table;
644}
645
646
647// For the use of CF and Foundation only
648CF_EXPORT void *_CFGetTSD(uint32_t slot) {
649 if (slot > CF_TSD_MAX_SLOTS) {
650 _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (get)", slot);
651 HALT;
652 }
653 __CFTSDTable *table = __CFTSDGetTable();
654 if (!table) {
655 // Someone is getting TSD during thread destruction. The table is gone, so we can't get any data anymore.
656 _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d retrieved but the thread data has already been torn down.", slot);
657 return NULL;
658 }
659 uintptr_t *slots = (uintptr_t *)(table->data);
660 return (void *)slots[slot];
661}
662
663// For the use of CF and Foundation only
664CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) {
665 if (slot > CF_TSD_MAX_SLOTS) {
666 _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (set)", slot);
667 HALT;
668 }
669 __CFTSDTable *table = __CFTSDGetTable();
670 if (!table) {
671 // Someone is setting TSD during thread destruction. The table is gone, so we can't get any data anymore.
672 _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d set but the thread data has already been torn down.", slot);
673 return NULL;
674 }
675
676 void *oldVal = (void *)table->data[slot];
677
678 table->data[slot] = (uintptr_t)newVal;
679 table->destructors[slot] = destructor;
680
681 return oldVal;
682}
683
856091c5 684
8ca704e1
A
685#pragma mark -
686#pragma mark Windows Wide to UTF8 and UTF8 to Wide
687
cf7d2af9
A
688#if DEPLOYMENT_TARGET_WINDOWS
689/* On Windows, we want to use UTF-16LE for path names to get full unicode support. Internally, however, everything remains in UTF-8 representation. These helper functions stand between CF and the Microsoft CRT to ensure that we are using the right representation on both sides. */
690
691#include <sys/stat.h>
692#include <share.h>
693
694// Creates a buffer of wchar_t to hold a UTF16LE version of the UTF8 str passed in. Caller must free the buffer when done. If resultLen is non-NULL, it is filled out with the number of characters in the string.
695static wchar_t *createWideFileSystemRepresentation(const char *str, CFIndex *resultLen) {
696 // Get the real length of the string in UTF16 characters
697 CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, str, kCFStringEncodingUTF8);
698 CFIndex strLen = CFStringGetLength(cfStr);
699
700 // Allocate a wide buffer to hold the converted string, including space for a NULL terminator
701 wchar_t *wideBuf = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t));
702
703 // Copy the string into the buffer and terminate
704 CFStringGetCharacters(cfStr, CFRangeMake(0, strLen), (UniChar *)wideBuf);
705 wideBuf[strLen] = 0;
706
707 CFRelease(cfStr);
708 if (resultLen) *resultLen = strLen;
709 return wideBuf;
710}
711
712// Copies a UTF16 buffer into a supplied UTF8 buffer.
713static void copyToNarrowFileSystemRepresentation(const wchar_t *wide, CFIndex dstBufSize, char *dstbuf) {
714 // Get the real length of the wide string in UTF8 characters
715 CFStringRef cfStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)wide, wcslen(wide));
716 CFIndex strLen = CFStringGetLength(cfStr);
717 CFIndex bytesUsed;
718
719 // Copy the wide string into the buffer and terminate
720 CFStringGetBytes(cfStr, CFRangeMake(0, strLen), kCFStringEncodingUTF8, 0, false, (uint8_t *)dstbuf, dstBufSize, &bytesUsed);
721 dstbuf[bytesUsed] = 0;
722
723 CFRelease(cfStr);
724}
725
726CF_EXPORT int _NS_stat(const char *name, struct _stat *st) {
727 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
728 int res = _wstat(wide, st);
729 free(wide);
730 return res;
731}
732
733CF_EXPORT int _NS_mkdir(const char *name) {
734 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
735 int res = _wmkdir(wide);
736 free(wide);
737 return res;
738}
739
740CF_EXPORT int _NS_rmdir(const char *name) {
741 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
742 int res = _wrmdir(wide);
743 free(wide);
744 return res;
745}
746
747CF_EXPORT int _NS_chmod(const char *name, int mode) {
748 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
8ca704e1
A
749
750 // Convert mode
751 int newMode = 0;
752 if (mode | 0400) newMode |= _S_IREAD;
753 if (mode | 0200) newMode |= _S_IWRITE;
754 if (mode | 0100) newMode |= _S_IEXEC;
755
756 int res = _wchmod(wide, newMode);
cf7d2af9
A
757 free(wide);
758 return res;
759}
760
761CF_EXPORT int _NS_unlink(const char *name) {
762 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
763 int res = _wunlink(wide);
764 free(wide);
765 return res;
766}
767
768// Warning: this doesn't support dstbuf as null even though 'getcwd' does
769CF_EXPORT char *_NS_getcwd(char *dstbuf, size_t size) {
770 if (!dstbuf) {
771 CFLog(kCFLogLevelWarning, CFSTR("CFPlatform: getcwd called with null buffer"));
772 return 0;
773 }
774
775 wchar_t *buf = _wgetcwd(NULL, 0);
776 if (!buf) {
777 return NULL;
778 }
779
780 // Convert result to UTF8
781 copyToNarrowFileSystemRepresentation(buf, (CFIndex)size, dstbuf);
782 free(buf);
783 return dstbuf;
784}
785
786CF_EXPORT char *_NS_getenv(const char *name) {
8ca704e1
A
787 // todo: wide getenv
788 // We have to be careful what happens here, because getenv is called during cf initialization, and things like cfstring may not be working yet
cf7d2af9
A
789 return getenv(name);
790}
791
792CF_EXPORT int _NS_rename(const char *oldName, const char *newName) {
793 wchar_t *oldWide = createWideFileSystemRepresentation(oldName, NULL);
794 wchar_t *newWide = createWideFileSystemRepresentation(newName, NULL);
795 // _wrename on Windows does not behave exactly as rename() on Mac OS -- if the file exists, the Windows one will fail whereas the Mac OS version will replace
796 // To simulate the Mac OS behavior, we use the Win32 API then fill out errno if something goes wrong
797 BOOL winRes = MoveFileExW(oldWide, newWide, MOVEFILE_REPLACE_EXISTING);
798 DWORD error = GetLastError();
799 if (!winRes) {
800 switch (error) {
801 case ERROR_SUCCESS:
802 errno = 0;
803 break;
804 case ERROR_FILE_NOT_FOUND:
805 case ERROR_PATH_NOT_FOUND:
806 case ERROR_OPEN_FAILED:
807 errno = ENOENT;
808 break;
809 case ERROR_ACCESS_DENIED:
810 errno = EACCES;
811 break;
812 default:
813 errno = error;
814 }
815 }
816 free(oldWide);
817 free(newWide);
818 return (winRes ? 0 : -1);
819}
820
821CF_EXPORT int _NS_open(const char *name, int oflag, int pmode) {
822 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
823 int fd;
824 _wsopen_s(&fd, wide, oflag, _SH_DENYNO, _S_IREAD | _S_IWRITE);
825 free(wide);
826 return fd;
827}
828
829CF_EXPORT int _NS_chdir(const char *name) {
830 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
831 int res = _wchdir(wide);
832 free(wide);
833 return res;
834}
835
836CF_EXPORT int _NS_access(const char *name, int amode) {
837 // execute is always true
838 if (amode == 1) return 0;
839
840 wchar_t *wide = createWideFileSystemRepresentation(name, NULL);
841 // we only care about the read-only (04) and write-only (02) bits, so mask octal 06
842 int res = _waccess(wide, amode & 06);
843 free(wide);
844 return res;
845}
846
847// This is a bit different than the standard 'mkstemp', because the size parameter is needed so we know the size of the UTF8 buffer
848// Also, we don't avoid the race between creating a temporary file name and opening it on Windows like we do on Mac
849CF_EXPORT int _NS_mkstemp(char *name, int bufSize) {
850 CFIndex nameLen;
851 wchar_t *wide = createWideFileSystemRepresentation(name, &nameLen);
852
853 // First check to see if the directory that this new temporary file will be created in exists. If not, set errno to ENOTDIR. This mimics the behavior of mkstemp on MacOS more closely.
854 // Look for the last '\' in the path
855 wchar_t *lastSlash = wcsrchr(wide, '\\');
856 if (!lastSlash) {
857 free(wide);
858 return -1;
859 }
860
861 // Set the last slash to NULL temporarily and use it for _wstat
862 *lastSlash = 0;
863 struct _stat dirInfo;
864 int res = _wstat(wide, &dirInfo);
865 if (res < 0) {
866 if (errno == ENOENT) {
867 errno = ENOTDIR;
868 }
869 free(wide);
870 return -1;
871 }
872 // Restore the last slash
873 *lastSlash = '\\';
874
875 errno_t err = _wmktemp_s(wide, nameLen + 1);
876 if (err != 0) {
877 free(wide);
878 return 0;
879 }
880
881 int fd;
882 _wsopen_s(&fd, wide, _O_RDWR | _O_CREAT | CF_OPENFLGS, _SH_DENYNO, _S_IREAD | _S_IWRITE);
883
884 // Convert the wide name back into the UTF8 buffer the caller supplied
885 copyToNarrowFileSystemRepresentation(wide, bufSize, name);
886 free(wide);
887 return fd;
888}
889
cf7d2af9 890
8ca704e1
A
891// Utilities to convert from a volume name to a drive letter
892
893Boolean _isAFloppy(char driveLetter)
894{
895 HANDLE h;
896 TCHAR tsz[8];
897 Boolean retval = false;
898 int iDrive;
899
900 if (driveLetter >= 'a' && driveLetter <= 'z') {
901 driveLetter = driveLetter - 'a' + 'A';
902 }
903
904 if ((driveLetter < 'A') || (driveLetter > 'Z')) {
905 // invalid driveLetter; I guess it's not a floppy...
906 return false;
907 }
908
909 iDrive = driveLetter - 'A' + 1;
910
911 // On Windows NT, use the technique described in the Knowledge Base article Q115828 and in the "FLOPPY" SDK sample.
912 wsprintf(tsz, TEXT("\\\\.\\%c:"), TEXT('@') + iDrive);
913 h = CreateFile(tsz, 0, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
914 if (h != INVALID_HANDLE_VALUE)
915 {
916 DISK_GEOMETRY Geom[20];
917 DWORD cb;
918
919 if (DeviceIoControl (h, IOCTL_DISK_GET_MEDIA_TYPES, 0, 0,
920 Geom, sizeof(Geom), &cb, 0)
921 && cb > 0)
922 {
923 switch (Geom[0].MediaType)
924 {
925 case F5_1Pt2_512: // 5.25 1.2MB floppy
926 case F5_360_512: // 5.25 360K floppy
927 case F5_320_512: // 5.25 320K floppy
928 case F5_320_1024: // 5.25 320K floppy
929 case F5_180_512: // 5.25 180K floppy
930 case F5_160_512: // 5.25 160K floppy
931 case F3_1Pt44_512: // 3.5 1.44MB floppy
932 case F3_2Pt88_512: // 3.5 2.88MB floppy
933 case F3_20Pt8_512: // 3.5 20.8MB floppy
934 case F3_720_512: // 3.5 720K floppy
935 retval = true;
936 break;
937 }
938 }
939
940 CloseHandle(h);
941 }
942
943 return retval;
944}
945
946
947extern CFStringRef CFCreateWindowsDrivePathFromVolumeName(CFStringRef volNameStr) {
948 if (!volNameStr) return NULL;
949
950 // This code is designed to match as closely as possible code from QuickTime's library
951 CFIndex strLen = CFStringGetLength(volNameStr);
952 if (strLen == 0) {
953 return NULL;
954 }
955
956 // Get drive names
957 long length, result;
958 wchar_t *driveNames = NULL;
959
960 // Get the size of the buffer to store the list of drives
961 length = GetLogicalDriveStringsW(0, 0);
962 if (!length) {
963 return NULL;
964 }
965
966 driveNames = (wchar_t *)malloc((length + 1) * sizeof(wchar_t));
967 result = GetLogicalDriveStringsW(length, driveNames);
968
969 if (!result || result > length) {
970 free(driveNames);
971 return NULL;
972 }
973
974 // Get the volume name string into a wide buffer
975 wchar_t *theVolumeName = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t));
976 CFStringGetCharacters(volNameStr, CFRangeMake(0, strLen), (UniChar *)theVolumeName);
977 theVolumeName[strLen] = 0;
978
979 // lowercase volume name
980 _wcslwr(theVolumeName);
981
982 // Iterate through the drive names, looking for something that matches
983 wchar_t *drivePtr = driveNames;
984 CFStringRef drivePathResult = NULL;
985
986 while (*drivePtr) {
987 _wcslwr(drivePtr);
988
989 if (!_isAFloppy((char)*drivePtr)) {
990 UINT oldErrorMode;
991 DWORD whoCares1, whoCares2;
992 BOOL getVolInfoSucceeded;
993 UniChar thisVolumeName[MAX_PATH];
994
995 // Convert this drive string into a volume name
996 oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
997 getVolInfoSucceeded = GetVolumeInformationW(drivePtr, (LPWSTR)thisVolumeName, sizeof(thisVolumeName), NULL, &whoCares1, &whoCares2, NULL, 0);
998 SetErrorMode(oldErrorMode);
999
1000 if (getVolInfoSucceeded) {
1001 _wcslwr((wchar_t *)thisVolumeName);
1002
1003 // If the volume corresponding to this drive matches the input volume
1004 // then this drive is the winner.
1005 if (!wcscmp((const wchar_t *)thisVolumeName, theVolumeName) ||
1006 (*thisVolumeName == 0x00 && (CFStringCompare(volNameStr, CFSTR("NONAME"), 0) == kCFCompareEqualTo))) {
1007 drivePathResult = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)drivePtr, wcslen(drivePtr));
1008 break;
1009 }
1010 }
1011 }
1012
1013 drivePtr += wcslen(drivePtr) + 1;
1014 }
1015
1016
1017 free(driveNames);
1018 free(theVolumeName);
1019 return drivePathResult;
1020}
1021
856091c5
A
1022struct timezone {
1023 int tz_minuteswest; /* minutes west of Greenwich */
1024 int tz_dsttime; /* type of dst correction */
1025};
1026
a48904a4 1027CF_PRIVATE int _NS_gettimeofday(struct timeval *tv, struct timezone *tz) {
856091c5
A
1028 if (tv) {
1029 FILETIME ft;
1030 GetSystemTimeAsFileTime(&ft);
1031 unsigned __int64 t = 0;
1032 t |= ft.dwHighDateTime;
1033 t <<= 32;
1034 t |= ft.dwLowDateTime;
1035
1036 // Convert to microseconds
1037 t /= 10;
1038
1039 // Difference between 1/1/1970 and 1/1/1601
1040 t -= 11644473600000000Ui64;
1041
1042 // Convert microseconds to seconds
1043 tv->tv_sec = (long)(t / 1000000UL);
1044 tv->tv_usec = (long)(t % 1000000UL);
1045 }
1046
1047 // We don't support tz
1048 return 0;
1049}
1050
8ca704e1
A
1051#endif // DEPLOYMENT_TARGET_WINDOWS
1052
1053#pragma mark -
1054#pragma mark Linux OSAtomic
1055
1056#if DEPLOYMENT_TARGET_LINUX
1057
1058bool OSAtomicCompareAndSwapPtr(void *oldp, void *newp, void *volatile *dst)
1059{
1060 return __sync_bool_compare_and_swap(dst, oldp, newp);
1061}
1062
1063bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst)
1064{
1065 return __sync_val_compare_and_swap(dst, oldl, newl);
1066}
1067
1068bool OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void *volatile *dst)
1069{
1070 return __sync_bool_compare_and_swap(dst, oldp, newp);
1071}
1072
1073int32_t OSAtomicAdd32Barrier( int32_t theAmount, volatile int32_t *theValue ) {
1074 return __sync_fetch_and_add(theValue, theAmount) + theAmount;
1075}
1076
1077bool OSAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) {
1078 return __sync_bool_compare_and_swap(theValue, oldValue, newValue);
1079}
1080
a48904a4
A
1081bool OSAtomicCompareAndSwap64Barrier(int64_t oldValue, int64_t newValue, volatile int64_t *theValue) {
1082 return __sync_bool_compare_and_swap(theValue, oldValue, newValue);
1083}
1084
8ca704e1
A
1085int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst)
1086{
1087 return OSAtomicAdd32Barrier(-1, dst);
1088}
1089
1090int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst)
1091{
1092 return OSAtomicAdd32Barrier(1, dst);
1093}
1094
1095int32_t OSAtomicAdd32( int32_t theAmount, volatile int32_t *theValue ) {
1096 return OSAtomicAdd32Barrier(theAmount, theValue);
1097}
1098
1099int32_t OSAtomicIncrement32(volatile int32_t *theValue) {
1100 return OSAtomicIncrement32Barrier(theValue);
1101}
1102
1103int32_t OSAtomicDecrement32(volatile int32_t *theValue) {
1104 return OSAtomicDecrement32Barrier(theValue);
1105}
1106
1107void OSMemoryBarrier() {
1108 __sync_synchronize();
1109}
1110
a48904a4
A
1111#include <Block_private.h>
1112
1113void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) {
1114 struct Block_layout *layout = (struct Block_layout *)block;
1115 pthread_once(predicate, (void (*)(void))layout->invoke);
1116}
1117
8ca704e1
A
1118#endif // DEPLOYMENT_TARGET_LINUX
1119
1120#pragma mark -
1121#pragma mark Windows and Linux Helpers
1122
1123#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1124
1125#include <stdio.h>
1126
a48904a4 1127CF_PRIVATE int asprintf(char **ret, const char *format, ...) {
8ca704e1
A
1128 va_list args;
1129 size_t sz = 1024;
1130 *ret = (char *) malloc(sz * sizeof(char));
1131 if (!*ret) return -1;
1132 va_start(args, format);
1133 int cnt = vsnprintf(*ret, sz, format, args);
1134 va_end(args);
1135 if (cnt < sz - 1) return cnt;
1136 sz = cnt + 8;
1137 char *oldret = *ret;
1138 *ret = (char *) realloc(*ret, sz * sizeof(char));
1139 if (!*ret && oldret) free(oldret);
1140 if (!*ret) return -1;
1141 va_start(args, format);
1142 cnt = vsnprintf(*ret, sz, format, args);
1143 va_end(args);
1144 if (cnt < sz - 1) return cnt;
1145 free(*ret);
1146 *ret = NULL;
1147 return -1;
1148}
1149
1150#endif
856091c5 1151