X-Git-Url: https://git.saurik.com/apple/objc4.git/blobdiff_plain/7c0e6487d7b67b6bf6c632300ee4b74e8950b051..7af964d1562d70f51a8e9aca24215ac3d83d0624:/runtime/objc-os.h diff --git a/runtime/objc-os.h b/runtime/objc-os.h new file mode 100644 index 0000000..e2f5613 --- /dev/null +++ b/runtime/objc-os.h @@ -0,0 +1,843 @@ +/* + * Copyright (c) 2007 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/*********************************************************************** +* objc-os.h +* OS portability layer. +**********************************************************************/ + +#ifndef _OBJC_OS_H +#define _OBJC_OS_H + +#include + +#if TARGET_OS_MAC + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include "objc-probes.h" // generated dtrace probe definitions. + +# if __cplusplus +# include +# include + using namespace std; +# include + using namespace __gnu_cxx; +# endif + +#elif TARGET_OS_WIN32 + +# define WINVER 0x0501 // target Windows XP and later +# define _WIN32_WINNT 0x0501 // target Windows XP and later +# define WIN32_LEAN_AND_MEAN + // hack: windef.h typedefs BOOL as int +# define BOOL WINBOOL +# include +# undef BOOL + +# include +# include +# include +# include +# include +# include +# include +# include + +# if __cplusplus +# include +# include + using namespace std; +# include + using namespace stdext; +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS /*empty*/ +# define __END_DECLS /*empty*/ +# endif + +# define __private_extern__ +# define __attribute__(x) +# define inline __inline + +/* stub out dtrace probes */ +# define OBJC_RUNTIME_OBJC_EXCEPTION_RETHROW() do {} while(0) +# define OBJC_RUNTIME_OBJC_EXCEPTION_THROW(arg0) do {} while(0) + +#else +# error unknown OS +#endif + + +#include +#include + +__BEGIN_DECLS + +extern void _objc_fatal(const char *fmt, ...) __attribute__((noreturn, format (printf, 1, 2))); + +#define INIT_ONCE_PTR(var, create, delete) \ + do { \ + if (var) break; \ + typeof(var) v = create; \ + while (!var) { \ + if (OSAtomicCompareAndSwapPtrBarrier(0, v, (void**)&var)) { \ + goto done; \ + } \ + } \ + delete; \ + done:; \ + } while (0) + +#define INIT_ONCE_32(var, create, delete) \ + do { \ + if (var) break; \ + typeof(var) v = create; \ + while (!var) { \ + if (OSAtomicCompareAndSwap32Barrier(0, v, (volatile int32_t *)&var)) { \ + goto done; \ + } \ + } \ + delete; \ + done:; \ + } while (0) + + +// Thread keys reserved by libc for our use. +// Keys [0..4] are used by autozone. +#if defined(__PTK_FRAMEWORK_OBJC_KEY5) +# define TLS_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY5) +# define SYNC_DATA_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY6) +# define SYNC_COUNT_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY7) +// define DIRECT_4_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY8) +// define DIRECT_5_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY9) +#else +# define NO_DIRECT_THREAD_KEYS 1 +#endif + + +#if TARGET_OS_WIN32 + +// Compiler compatibility + +// OS compatibility + +#define strdup _strdup + +#define issetugid() 0 + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +static __inline void bcopy(const void *src, void *dst, size_t size) { memcpy(dst, src, size); } +static __inline void bzero(void *dst, size_t size) { memset(dst, 0, size); } + +int asprintf(char **dstp, const char *format, ...); + +typedef void * malloc_zone_t; + +static __inline malloc_zone_t malloc_default_zone(void) { return (malloc_zone_t)-1; } +static __inline void *malloc_zone_malloc(malloc_zone_t z, size_t size) { return malloc(size); } +static __inline void *malloc_zone_calloc(malloc_zone_t z, size_t size, size_t count) { return calloc(size, count); } +static __inline void *malloc_zone_realloc(malloc_zone_t z, void *p, size_t size) { return realloc(p, size); } +static __inline void malloc_zone_free(malloc_zone_t z, void *p) { free(p); } +static __inline malloc_zone_t malloc_zone_from_ptr(const void *p) { return (malloc_zone_t)-1; } +static __inline size_t malloc_size(const void *p) { return _msize((void*)p); /* fixme invalid pointer check? */ } + + +// AssertMacros + +#define require_action_string(cond, dest, act, msg) do { if (!(cond)) { { act; } goto dest; } } while (0) +#define require_noerr_string(err, dest, msg) do { if (err) goto dest; } while (0) +#define require_string(cond, dest, msg) do { if (!(cond)) goto dest; } while (0) + + +// OSAtomic + +static __inline BOOL OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) +{ + // fixme barrier is overkill + long original = InterlockedCompareExchange(dst, newl, oldl); + return (original == oldl); +} + +static __inline BOOL OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void * volatile *dst) +{ + void *original = InterlockedCompareExchangePointer(dst, newp, oldp); + return (original == oldp); +} + +static __inline BOOL OSAtomicCompareAndSwap32Barrier(int32_t oldl, int32_t newl, int32_t volatile *dst) +{ + long original = InterlockedCompareExchange((volatile long *)dst, newl, oldl); + return (original == oldl); +} + +static __inline int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst) +{ + return InterlockedDecrement((volatile long *)dst); +} + +static __inline int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst) +{ + return InterlockedIncrement((volatile long *)dst); +} + + +// Internal data types + +typedef DWORD objc_thread_t; // thread ID +static __inline int thread_equal(objc_thread_t t1, objc_thread_t t2) { + return t1 == t2; +} +static __inline objc_thread_t thread_self(void) { + return GetCurrentThreadId(); +} + +typedef struct { + DWORD key; + void (*dtor)(void *); +} tls_key_t; +static __inline void tls_create(tls_key_t *k, void (*dtor)(void*)) { + // fixme need dtor registry for DllMain to call on thread detach + k->key = TlsAlloc(); + k->dtor = dtor; +} +static __inline void *tls_get(tls_key_t k) { + return TlsGetValue(k.key); +} +static __inline void tls_set(tls_key_t k, void *value) { + TlsSetValue(k.key, value); +} + +typedef struct { + CRITICAL_SECTION *lock; +} mutex_t; +#define MUTEX_INITIALIZER {0}; +extern void mutex_init(mutex_t *m); +static __inline int _mutex_lock_nodebug(mutex_t *m) { + // fixme error check + if (!m->lock) { + mutex_init(m); + } + EnterCriticalSection(m->lock); + return 0; +} +static __inline int _mutex_try_lock_nodebug(mutex_t *m) { + // fixme error check + if (!m->lock) { + mutex_init(m); + } + return TryEnterCriticalSection(m->lock); +} +static __inline int _mutex_unlock_nodebug(mutex_t *m) { + // fixme error check + LeaveCriticalSection(m->lock); + return 0; +} + + +typedef mutex_t OSSpinLock; +#define OSSpinLockLock(l) mutex_lock(l) +#define OSSpinLockUnlock(l) mutex_unlock(l) +#define OS_SPINLOCK_INIT MUTEX_INITIALIZER + + +typedef struct { + HANDLE mutex; +} recursive_mutex_t; +#define RECURSIVE_MUTEX_INITIALIZER {0}; +#define RECURSIVE_MUTEX_NOT_LOCKED 1 +extern void recursive_mutex_init(recursive_mutex_t *m); +static __inline int _recursive_mutex_lock_nodebug(recursive_mutex_t *m) { + assert(m->mutex); + return WaitForSingleObject(m->mutex, INFINITE); +} +static __inline int _recursive_mutex_try_lock_nodebug(recursive_mutex_t *m) { + assert(m->mutex); + return (WAIT_OBJECT_0 == WaitForSingleObject(m->mutex, 0)); +} +static __inline int _recursive_mutex_unlock_nodebug(recursive_mutex_t *m) { + assert(m->mutex); + return ReleaseMutex(m->mutex) ? 0 : RECURSIVE_MUTEX_NOT_LOCKED; +} + + +/* +typedef HANDLE mutex_t; +static inline void mutex_init(HANDLE *m) { *m = CreateMutex(NULL, FALSE, NULL); } +static inline void _mutex_lock(mutex_t *m) { WaitForSingleObject(*m, INFINITE); } +static inline int mutex_try_lock(mutex_t *m) { return WaitForSingleObject(*m, 0) == WAIT_OBJECT_0; } +static inline void _mutex_unlock(mutex_t *m) { ReleaseMutex(*m); } +*/ + +// based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html +// Vista-only CONDITION_VARIABLE would be better +typedef struct { + HANDLE mutex; + HANDLE waiters; // semaphore for those in cond_wait() + HANDLE waitersDone; // auto-reset event after everyone gets a broadcast + CRITICAL_SECTION waitCountLock; // guards waitCount and didBroadcast + unsigned int waitCount; + int didBroadcast; +} monitor_t; +#define MONITOR_INITIALIZER { 0 } +#define MONITOR_NOT_ENTERED 1 +extern int monitor_init(monitor_t *c); + +static inline int _monitor_enter_nodebug(monitor_t *c) { + if (!c->mutex) { + int err = monitor_init(c); + if (err) return err; + } + return WaitForSingleObject(c->mutex, INFINITE); +} +static inline int _monitor_exit_nodebug(monitor_t *c) { + if (!ReleaseMutex(c->mutex)) return MONITOR_NOT_ENTERED; + else return 0; +} +static inline int _monitor_wait_nodebug(monitor_t *c) { + int last; + EnterCriticalSection(&c->waitCountLock); + c->waitCount++; + LeaveCriticalSection(&c->waitCountLock); + + SignalObjectAndWait(c->mutex, c->waiters, INFINITE, FALSE); + + EnterCriticalSection(&c->waitCountLock); + c->waitCount--; + last = c->didBroadcast && c->waitCount == 0; + LeaveCriticalSection(&c->waitCountLock); + + if (last) { + // tell broadcaster that all waiters have awoken + SignalObjectAndWait(c->waitersDone, c->mutex, INFINITE, FALSE); + } else { + WaitForSingleObject(c->mutex, INFINITE); + } + + // fixme error checking + return 0; +} +static inline int monitor_notify(monitor_t *c) { + int haveWaiters; + + EnterCriticalSection(&c->waitCountLock); + haveWaiters = c->waitCount > 0; + LeaveCriticalSection(&c->waitCountLock); + + if (haveWaiters) { + ReleaseSemaphore(c->waiters, 1, 0); + } + + // fixme error checking + return 0; +} +static inline int monitor_notifyAll(monitor_t *c) { + EnterCriticalSection(&c->waitCountLock); + if (c->waitCount == 0) { + LeaveCriticalSection(&c->waitCountLock); + return 0; + } + c->didBroadcast = 1; + ReleaseSemaphore(c->waiters, c->waitCount, 0); + LeaveCriticalSection(&c->waitCountLock); + + // fairness: wait for everyone to move from waiters to mutex + WaitForSingleObject(c->waitersDone, INFINITE); + // not under waitCountLock, but still under mutex + c->didBroadcast = 0; + + // fixme error checking + return 0; +} + + +// fixme no rwlock yet + +#define rwlock_t mutex_t +#define rwlock_init(r) mutex_init(r) +#define _rwlock_read_nodebug(m) _mutex_lock_nodebug(m) +#define _rwlock_write_nodebug(m) _mutex_lock_nodebug(m) +#define _rwlock_try_read_nodebug(m) _mutex_try_lock_nodebug(m) +#define _rwlock_try_write_nodebug(m) _mutex_try_lock_nodebug(m) +#define _rwlock_unlock_read_nodebug(m) _mutex_unlock_nodebug(m) +#define _rwlock_unlock_write_nodebug(m) _mutex_unlock_nodebug(m) + + +typedef struct { + struct objc_module **modules; + size_t moduleCount; + struct old_protocol **protocols; + size_t protocolCount; + void *imageinfo; + size_t imageinfoBytes; + SEL *selrefs; + size_t selrefCount; + struct objc_class **clsrefs; + size_t clsrefCount; +} os_header_info; + +typedef IMAGE_DOS_HEADER headerType; +// fixme YES bundle? NO bundle? sometimes? +#define headerIsBundle(hi) YES +OBJC_EXTERN IMAGE_DOS_HEADER __ImageBase; +#define libobjc_header ((headerType *)&__ImageBase) + +// Prototypes + + +#elif TARGET_OS_MAC + + +// OS headers + + +// Compiler compatibility + +// OS compatibility + +// Internal data types + +typedef pthread_t objc_thread_t; + +static __inline int thread_equal(objc_thread_t t1, objc_thread_t t2) { + return pthread_equal(t1, t2); +} +static __inline objc_thread_t thread_self(void) { + return pthread_self(); +} + + +typedef pthread_key_t tls_key_t; + +static inline void tls_create(tls_key_t *k, void (*dtor)(void*)) { + pthread_key_create(k, dtor); +} +static inline void *tls_get(tls_key_t k) { + return pthread_getspecific(k); +} +static inline void tls_set(tls_key_t k, void *value) { + pthread_setspecific(k, value); +} + +#ifndef NO_DIRECT_THREAD_KEYS +static inline void *tls_get_direct(tls_key_t k) +{ + assert(k == SYNC_DATA_DIRECT_KEY || + k == SYNC_COUNT_DIRECT_KEY); + + if (_pthread_has_direct_tsd()) { + return _pthread_getspecific_direct(k); + } else { + return pthread_getspecific(k); + } +} +static inline void tls_set_direct(tls_key_t k, void *value) +{ + assert(k == SYNC_DATA_DIRECT_KEY || + k == SYNC_COUNT_DIRECT_KEY); + + if (_pthread_has_direct_tsd()) { + _pthread_setspecific_direct(k, value); + } else { + pthread_setspecific(k, value); + } +} +#endif + + +typedef pthread_mutex_t mutex_t; +#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER; + +extern int DebuggerMode; +extern void gdb_objc_debuggerModeFailure(void); +extern BOOL isManagedDuringDebugger(void *lock); +extern BOOL isLockedDuringDebugger(mutex_t *lock); + +static inline int _mutex_lock_nodebug(mutex_t *m) { + if (DebuggerMode && isManagedDuringDebugger(m)) { + if (! isLockedDuringDebugger(m)) { + gdb_objc_debuggerModeFailure(); + } + return 0; + } + return pthread_mutex_lock(m); +} +static inline int _mutex_try_lock_nodebug(mutex_t *m) { + if (DebuggerMode && isManagedDuringDebugger(m)) { + if (! isLockedDuringDebugger(m)) { + gdb_objc_debuggerModeFailure(); + } + return 1; + } + return !pthread_mutex_trylock(m); +} +static inline int _mutex_unlock_nodebug(mutex_t *m) { + if (DebuggerMode && isManagedDuringDebugger(m)) { + return 0; + } + return pthread_mutex_unlock(m); +} + + +typedef struct { + pthread_mutex_t *mutex; +} recursive_mutex_t; +#define RECURSIVE_MUTEX_INITIALIZER {0}; +#define RECURSIVE_MUTEX_NOT_LOCKED EPERM +extern void recursive_mutex_init(recursive_mutex_t *m); + +static inline int _recursive_mutex_lock_nodebug(recursive_mutex_t *m) { + assert(m->mutex); + if (DebuggerMode && isManagedDuringDebugger(m)) { + if (! isLockedDuringDebugger((mutex_t *)m)) { + gdb_objc_debuggerModeFailure(); + } + return 0; + } + return pthread_mutex_lock(m->mutex); +} +static inline int _recursive_mutex_try_lock_nodebug(recursive_mutex_t *m) { + assert(m->mutex); + if (DebuggerMode && isManagedDuringDebugger(m)) { + if (! isLockedDuringDebugger((mutex_t *)m)) { + gdb_objc_debuggerModeFailure(); + } + return 1; + } + return !pthread_mutex_trylock(m->mutex); +} +static inline int _recursive_mutex_unlock_nodebug(recursive_mutex_t *m) { + assert(m->mutex); + if (DebuggerMode && isManagedDuringDebugger(m)) { + return 0; + } + return pthread_mutex_unlock(m->mutex); +} + + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; +} monitor_t; +#define MONITOR_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER } +#define MONITOR_NOT_ENTERED EPERM + +static inline int monitor_init(monitor_t *c) { + int err = pthread_mutex_init(&c->mutex, NULL); + if (err) return err; + err = pthread_cond_init(&c->cond, NULL); + if (err) { + pthread_mutex_destroy(&c->mutex); + return err; + } + return 0; +} +static inline int _monitor_enter_nodebug(monitor_t *c) { + assert(!isManagedDuringDebugger(c)); + return pthread_mutex_lock(&c->mutex); +} +static inline int _monitor_exit_nodebug(monitor_t *c) { + return pthread_mutex_unlock(&c->mutex); +} +static inline int _monitor_wait_nodebug(monitor_t *c) { + return pthread_cond_wait(&c->cond, &c->mutex); +} +static inline int monitor_notify(monitor_t *c) { + return pthread_cond_signal(&c->cond); +} +static inline int monitor_notifyAll(monitor_t *c) { + return pthread_cond_broadcast(&c->cond); +} + + +// semaphore_create formatted for INIT_ONCE use +static inline semaphore_t create_semaphore(void) +{ + semaphore_t sem; + kern_return_t k; + k = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0); + if (k) _objc_fatal("semaphore_create failed (0x%x)", k); + return sem; +} + + +/* Custom read-write lock + - reader is atomic add/subtract + - writer is pthread mutex plus atomic add/subtract + - fairness: new readers wait if a writer wants in + - fairness: when writer completes, readers (probably) precede new writer + + state: xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyz + x: blocked reader count + y: active reader count + z: readers allowed flag +*/ +typedef struct { + volatile int32_t state; + semaphore_t readersDone; + semaphore_t writerDone; + pthread_mutex_t writerMutex; +} rwlock_t; + +extern BOOL isReadingDuringDebugger(rwlock_t *lock); +extern BOOL isWritingDuringDebugger(rwlock_t *lock); + +static inline void rwlock_init(rwlock_t *l) +{ + l->state = 1; + l->readersDone = create_semaphore(); + l->writerDone = create_semaphore(); + l->writerMutex = (mutex_t)MUTEX_INITIALIZER; +} + +static inline void _rwlock_read_nodebug(rwlock_t *l) +{ + if (DebuggerMode && isManagedDuringDebugger(l)) { + if (! isReadingDuringDebugger(l)) { + gdb_objc_debuggerModeFailure(); + } + return; + } + while (1) { + // Increment "blocked readers" or "active readers" count. + int32_t old = l->state; + if (old % 2 == 1) { + // Readers OK. Increment active reader count. + if (OSAtomicCompareAndSwap32Barrier(old, old + 2, &l->state)) { + // Success. Read lock acquired. + return; + } else { + // CAS failed (writer or another reader). Redo from start. + } + } + else { + // Readers not OK. Increment blocked reader count. + if (OSAtomicCompareAndSwap32(old, old + 0x10000, &l->state)) { + // Success. Wait for writer to complete, then retry. + semaphore_wait(l->writerDone); + } else { + // CAS failed (writer or another reader). Redo from start. + } + } + } +} + +static inline void _rwlock_unlock_read_nodebug(rwlock_t *l) +{ + if (DebuggerMode && isManagedDuringDebugger(l)) { + return; + } + // Decrement "active readers" count. + int32_t newState = OSAtomicAdd32Barrier(-2, &l->state); + if ((newState & 0xffff) == 0) { + // No active readers, and readers OK flag is clear. + // We're the last reader out and there's a writer waiting. Wake it. + semaphore_signal(l->readersDone); + } +} + + +static inline int _rwlock_try_read_nodebug(rwlock_t *l) +{ + int i; + if (DebuggerMode && isManagedDuringDebugger(l)) { + if (! isReadingDuringDebugger(l)) { + gdb_objc_debuggerModeFailure(); + } + return 1; + } + for (i = 0; i < 16; i++) { + int32_t old = l->state; + if (old % 2 != 1) { + // Readers not OK. Fail. + return 0; + } else { + // Readers OK. + if (OSAtomicCompareAndSwap32Barrier(old, old + 2, &l->state)) { + // Success. Read lock acquired. + return 1; + } else { + // CAS failed (writer or another reader). Redo from start. + // trylock will fail against writer, + // but retry a few times against reader. + } + } + } + + // Too many retries. Give up. + return 0; +} + + +static inline void _rwlock_write_nodebug(rwlock_t *l) +{ + if (DebuggerMode && isManagedDuringDebugger(l)) { + if (! isWritingDuringDebugger(l)) { + gdb_objc_debuggerModeFailure(); + } + return; + } + + // Only one writer allowed at a time. + pthread_mutex_lock(&l->writerMutex); + + // Clear "readers OK" bit and "blocked readers" count. + int32_t newState = OSAtomicAnd32(0x0000fffe, (uint32_t *)&l->state); + + if (newState == 0) { + // No "active readers". Success. + OSMemoryBarrier(); + } else { + // Wait for "active readers" to complete. + semaphore_wait(l->readersDone); + } +} + +static inline void _rwlock_unlock_write_nodebug(rwlock_t *l) +{ + if (DebuggerMode && isManagedDuringDebugger(l)) { + return; + } + + // Reinstate "readers OK" bit and clear reader counts. + int32_t oldState; + do { + oldState = l->state; + } while (!OSAtomicCompareAndSwap32Barrier(oldState, 0x1, &l->state)); + + // Unblock any "blocked readers" that arrived while we held the lock + oldState = oldState >> 16; + while (oldState--) { + semaphore_signal(l->writerDone); + } + + // Allow a new writer. + pthread_mutex_unlock(&l->writerMutex); +} + +static inline int _rwlock_try_write_nodebug(rwlock_t *l) +{ + if (DebuggerMode && isManagedDuringDebugger(l)) { + if (! isWritingDuringDebugger(l)) { + gdb_objc_debuggerModeFailure(); + } + return 1; + } + + if (pthread_mutex_trylock(&l->writerMutex)) { + // Some other writer is in the way - fail + return 0; + } + + // Similar to _rwlock_write_nodebug, but less intrusive with readers active + + int32_t oldState, newState; + oldState = l->state; + newState = oldState & 0x0000fffe; + if (newState != 0) { + // Readers active. Give up. + pthread_mutex_unlock(&l->writerMutex); + return 0; + } + if (!OSAtomicCompareAndSwap32Barrier(oldState, newState, &l->state)) { + // CAS failed (reader interupted). Give up. + pthread_mutex_unlock(&l->writerMutex); + return 0; + } + + return 1; +} + + +#ifndef __LP64__ +typedef struct mach_header headerType; +typedef struct segment_command segmentType; +typedef struct section sectionType; +#else +typedef struct mach_header_64 headerType; +typedef struct segment_command_64 segmentType; +typedef struct section_64 sectionType; +#endif +#define headerIsBundle(hi) (hi->mhdr->filetype == MH_BUNDLE) +#define libobjc_header ((headerType *)&_mh_dylib_header) + +typedef struct { + Dl_info dl_info; + const segmentType * objcSegmentHeader; + const segmentType * dataSegmentHeader; + ptrdiff_t image_slide; +#if !__OBJC2__ + struct old_protocol **proto_refs; +#endif +} os_header_info; + +// Prototypes + +/* Secure /tmp usage */ +extern int secure_open(const char *filename, int flags, uid_t euid); + + +#else + + +#error unknown OS + + +#endif + +__END_DECLS + +#endif