diff --git a/arc.m b/arc.m index e18872b3..0540391a 100644 --- a/arc.m +++ b/arc.m @@ -12,9 +12,44 @@ #import "objc/objc-arc.h" #import "objc/blocks_runtime.h" -#ifndef NO_PTHREADS -#include -pthread_key_t ARCThreadKey; +#if defined(_WIN32) +// We're using the Fiber-Local Storage APIs on Windows +// because the TLS APIs won't pass app certification. +// Additionally, the FLS API surface is 1:1 mapped to +// the TLS API surface when fibers are not in use. +# include "safewindows.h" +# define arc_tls_store FlsSetValue +# define arc_tls_load FlsGetValue +# define TLS_CALLBACK(name) void WINAPI name + +typedef DWORD arc_tls_key_t; +typedef void WINAPI(*arc_cleanup_function_t)(void*); +static inline arc_tls_key_t arc_tls_key_create(arc_cleanup_function_t cleanupFunction) +{ + return FlsAlloc(cleanupFunction); +} + +#else // if defined(_WIN32) + +# ifndef NO_PTHREADS +# include +# define arc_tls_store pthread_setspecific +# define arc_tls_load pthread_getspecific +# define TLS_CALLBACK(name) void name + +typedef pthread_key_t arc_tls_key_t; +typedef void (*arc_cleanup_function_t)(void*); +static inline arc_tls_key_t arc_tls_key_create(arc_cleanup_function_t cleanupFunction) +{ + pthread_key_t key; + pthread_key_create(&key, cleanupFunction); + return key; +} +# endif +#endif + +#ifdef arc_tls_store +arc_tls_key_t ARCThreadKey; #endif extern void _NSConcreteMallocBlock; @@ -60,14 +95,14 @@ - (void)release; static inline struct arc_tls* getARCThreadData(void) { -#ifdef NO_PTHREADS +#ifndef arc_tls_store return NULL; -#else - struct arc_tls *tls = pthread_getspecific(ARCThreadKey); +#else // !defined arc_tls_store + struct arc_tls *tls = arc_tls_load(ARCThreadKey); if (NULL == tls) { tls = calloc(sizeof(struct arc_tls), 1); - pthread_setspecific(ARCThreadKey, tls); + arc_tls_store(ARCThreadKey, tls); } return tls; #endif @@ -133,7 +168,8 @@ static void emptyPool(struct arc_tls *tls, id *stop) //fprintf(stderr, "New insert: %p. Stop: %p\n", tls->pool->insert, stop); } -static void cleanupPools(struct arc_tls* tls) +#ifdef arc_tls_store +static TLS_CALLBACK(cleanupPools)(struct arc_tls* tls) { if (tls->returnRetained) { @@ -151,6 +187,7 @@ static void cleanupPools(struct arc_tls* tls) } free(tls); } +#endif static Class AutoreleasePool; @@ -596,8 +633,8 @@ PRIVATE void init_arc(void) { weak_ref_initialize(&weakRefs, 128); INIT_LOCK(weakRefLock); -#ifndef NO_PTHREADS - pthread_key_create(&ARCThreadKey, (void(*)(void*))cleanupPools); +#ifdef arc_tls_store + ARCThreadKey = arc_tls_key_create((arc_cleanup_function_t)cleanupPools); #endif } diff --git a/lock.h b/lock.h index d39f07b3..2f3cd119 100644 --- a/lock.h +++ b/lock.h @@ -6,15 +6,13 @@ #ifndef __LIBOBJC_LOCK_H_INCLUDED__ #define __LIBOBJC_LOCK_H_INCLUDED__ -#ifdef WIN32 -#define BOOL _WINBOOL -# include -#undef BOOL -typedef HANDLE mutex_t; -# define INIT_LOCK(x) x = CreateMutex(NULL, FALSE, NULL) -# define LOCK(x) WaitForSingleObject(*x, INFINITE) -# define UNLOCK(x) ReleaseMutex(*x) -# define DESTROY_LOCK(x) CloseHandle(*x) +#ifdef _WIN32 +# include "safewindows.h" +typedef CRITICAL_SECTION mutex_t; +# define INIT_LOCK(x) InitializeCriticalSection(&(x)) +# define LOCK(x) EnterCriticalSection(x) +# define UNLOCK(x) LeaveCriticalSection(x) +# define DESTROY_LOCK(x) DeleteCriticalSection(x) #else # include diff --git a/safewindows.h b/safewindows.h new file mode 100644 index 00000000..8a0850d2 --- /dev/null +++ b/safewindows.h @@ -0,0 +1,20 @@ +#ifndef __LIBOBJC_SAFEWINDOWS_H_INCLUDED__ +#define __LIBOBJC_SAFEWINDOWS_H_INCLUDED__ + +#pragma push_macro("BOOL") + +#ifdef BOOL +#undef BOOL +#endif +#define BOOL _WINBOOL + +#include + +// Windows.h defines interface -> struct +#ifdef interface +#undef interface +#endif + +#pragma pop_macro("BOOL") + +#endif // __LIBOBJC_SAFEWINDOWS_H_INCLUDED__ diff --git a/spinlock.h b/spinlock.h index e65e6081..2efec475 100644 --- a/spinlock.h +++ b/spinlock.h @@ -1,5 +1,5 @@ -#ifdef __MINGW32__ -#include +#ifdef _WIN32 +#include "safewindows.h" static unsigned sleep(unsigned seconds) { Sleep(seconds*1000);