+#pragma mark -
+#pragma mark Thread Functions
+
+#if DEPLOYMENT_TARGET_WINDOWS
+
+// This code from here:
+// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+
+const DWORD MS_VC_EXCEPTION=0x406D1388;
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+CF_EXPORT void _NS_pthread_setname_np(const char *name) {
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = GetCurrentThreadId();
+ info.dwFlags = 0;
+
+ __try
+ {
+ RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+}
+
+static pthread_t __initialPthread = { NULL, 0 };
+
+CF_EXPORT int _NS_pthread_main_np() {
+ pthread_t me = pthread_self();
+ if (NULL == __initialPthread.p) {
+ __initialPthread.p = me.p;
+ __initialPthread.x = me.x;
+ }
+ return (pthread_equal(__initialPthread, me));
+}
+
+#endif
+
+#pragma mark -
+#pragma mark Thread Local Data
+
+// If slot >= CF_TSD_MAX_SLOTS, the SPI functions will crash at NULL + slot address.
+// If thread data has been torn down, these functions should crash on CF_TSD_BAD_PTR + slot address.
+#define CF_TSD_MAX_SLOTS 70
+
+#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
+#define CF_TSD_KEY 55
+#endif
+
+// Windows and Linux, not sure how many times the destructor could get called; CF_TSD_MAX_DESTRUCTOR_CALLS could be 1
+
+#define CF_TSD_BAD_PTR ((void *)0x1000)
+
+typedef void (*tsdDestructor)(void *);
+
+// Data structure to hold TSD data, cleanup functions for each
+typedef struct __CFTSDTable {
+ uint32_t destructorCount;
+ uintptr_t data[CF_TSD_MAX_SLOTS];
+ tsdDestructor destructors[CF_TSD_MAX_SLOTS];
+} __CFTSDTable;
+
+static void __CFTSDFinalize(void *arg);
+
+#if DEPLOYMENT_TARGET_WINDOWS
+
+#include "CFVersionCheck.h"
+
+static DWORD __CFTSDIndexKey = 0xFFFFFFFF;
+
+// Called from CFRuntime's startup code, on Windows only
+__private_extern__ void __CFTSDWindowsInitialize() {
+ __CFTSDIndexKey = TlsAlloc();
+}
+
+// Called from CFRuntime's cleanup code, on Windows only
+__private_extern__ void __CFTSDWindowsCleanup() {
+ TlsFree(__CFTSDIndexKey);
+}
+
+// Called for each thread as it exits, on Windows only
+__private_extern__ void __CFFinalizeWindowsThreadData() {
+ // 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:
+ // <rdar://problem/8989063> REGRESSION(CF-610-CF-611): Crash closing Safari in BonjourDB destructor (Windows)
+ // <rdar://problem/9326814> SyncUIHandler crashes after conflict is resolved and we do SyncNow
+ // 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).
+ // So instead we just finalize once, which is the behavior pre-Airwolf anyway
+ __CFTSDFinalize(TlsGetValue(__CFTSDIndexKey));
+}
+
+#endif
+
+#if DEPLOYMENT_TARGET_LINUX
+
+static pthread_key_t __CFTSDIndexKey;
+
+// Called from CFRuntime's startup code, on Linux only
+__private_extern__ void __CFTSDLinuxInitialize() {
+ (void)pthread_key_create(&__CFTSDIndexKey, __CFTSDFinalize);
+}
+
+#endif
+
+static void __CFTSDSetSpecific(void *arg) {
+#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
+ pthread_setspecific(CF_TSD_KEY, arg);
+#elif DEPLOYMENT_TARGET_LINUX
+ pthread_setspecific(__CFTSDIndexKey, arg);
+#elif DEPLOYMENT_TARGET_WINDOWS
+ TlsSetValue(__CFTSDIndexKey, arg);
+#endif
+}
+
+static void *__CFTSDGetSpecific() {
+#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
+ return pthread_getspecific(CF_TSD_KEY);
+#elif DEPLOYMENT_TARGET_LINUX
+ return pthread_getspecific(__CFTSDIndexKey);
+#elif DEPLOYMENT_TARGET_WINDOWS
+ return TlsGetValue(__CFTSDIndexKey);
+#endif
+}
+
+static void __CFTSDFinalize(void *arg) {
+ // Set our TSD so we're called again by pthreads. It will call the destructor 5 times as long as a value is set in the thread specific data. We handle each case below.
+ __CFTSDSetSpecific(arg);
+
+ if (!arg || arg == CF_TSD_BAD_PTR) {
+ // We've already been destroyed. The call above set the bad pointer again. Now we just return.
+ return;
+ }
+
+ __CFTSDTable *table = (__CFTSDTable *)arg;
+ table->destructorCount++;
+
+ // On 1st, 2nd, 3rd, 4th calls, invoke destructor
+ // 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.
+ // This logic is basically the same as what pthreads does. We just skip the 'created' flag.
+#if COCOA_ARR0
+ uintptr_t pool = _CFAutoreleasePoolPush();
+#endif
+ for (int32_t i = 0; i < CF_TSD_MAX_SLOTS; i++) {
+ if (table->data[i] && table->destructors[i]) {
+ uintptr_t old = table->data[i];
+ table->data[i] = (uintptr_t)NULL;
+ table->destructors[i]((void *)(old));
+ }
+ }
+#if COCOA_ARR0
+ _CFAutoreleasePoolPop(pool);
+#endif
+
+ if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { // On 4th call, destroy our data
+ free(table);
+
+ // Now if the destructor is called again we will take the shortcut at the beginning of this function.
+ __CFTSDSetSpecific(CF_TSD_BAD_PTR);
+ return;
+ }
+}
+
+#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
+extern int pthread_key_init_np(int, void (*)(void *));
+#endif
+
+// Get or initialize a thread local storage. It is created on demand.
+static __CFTSDTable *__CFTSDGetTable() {
+ __CFTSDTable *table = (__CFTSDTable *)__CFTSDGetSpecific();
+ // Make sure we're not setting data again after destruction.
+ if (table == CF_TSD_BAD_PTR) {
+ return NULL;
+ }
+ // Create table on demand
+ if (!table) {
+ // This memory is freed in the finalize function
+ table = (__CFTSDTable *)calloc(1, sizeof(__CFTSDTable));
+ // 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.
+#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
+ pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize);
+#endif
+ __CFTSDSetSpecific(table);
+ }
+
+ return table;
+}
+
+
+// For the use of CF and Foundation only
+CF_EXPORT void *_CFGetTSD(uint32_t slot) {
+ if (slot > CF_TSD_MAX_SLOTS) {
+ _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (get)", slot);
+ HALT;
+ }
+ __CFTSDTable *table = __CFTSDGetTable();
+ if (!table) {
+ // Someone is getting TSD during thread destruction. The table is gone, so we can't get any data anymore.
+ _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d retrieved but the thread data has already been torn down.", slot);
+ return NULL;
+ }
+ uintptr_t *slots = (uintptr_t *)(table->data);
+ return (void *)slots[slot];
+}
+
+// For the use of CF and Foundation only
+CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) {
+ if (slot > CF_TSD_MAX_SLOTS) {
+ _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (set)", slot);
+ HALT;
+ }
+ __CFTSDTable *table = __CFTSDGetTable();
+ if (!table) {
+ // Someone is setting TSD during thread destruction. The table is gone, so we can't get any data anymore.
+ _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d set but the thread data has already been torn down.", slot);
+ return NULL;
+ }
+
+ void *oldVal = (void *)table->data[slot];
+
+ table->data[slot] = (uintptr_t)newVal;
+ table->destructors[slot] = destructor;
+
+ return oldVal;
+}
+
+#pragma mark -
+#pragma mark Windows Wide to UTF8 and UTF8 to Wide
+