1/* 2 * Copyright (c) 2007 Apple Inc. All Rights Reserved. 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 */ 23 24/*********************************************************************** 25* objc-os.h 26* OS portability layer. 27**********************************************************************/ 28 29#ifndef _OBJC_OS_H 30#define _OBJC_OS_H 31 32#include <TargetConditionals.h> 33#include "objc-config.h" 34 35#ifdef __LP64__ 36# define WORD_SHIFT 3UL 37# define WORD_MASK 7UL 38# define WORD_BITS 64 39#else 40# define WORD_SHIFT 2UL 41# define WORD_MASK 3UL 42# define WORD_BITS 32 43#endif 44 45static inline uint32_t word_align(uint32_t x) { 46 return (x + WORD_MASK) & ~WORD_MASK; 47} 48static inline size_t word_align(size_t x) { 49 return (x + WORD_MASK) & ~WORD_MASK; 50} 51 52#if TARGET_OS_MAC 53 54# ifndef __STDC_LIMIT_MACROS 55# define __STDC_LIMIT_MACROS 56# endif 57 58# include <stdio.h> 59# include <stdlib.h> 60# include <stdint.h> 61# include <stdarg.h> 62# include <string.h> 63# include <ctype.h> 64# include <errno.h> 65# include <dlfcn.h> 66# include <fcntl.h> 67# include <assert.h> 68# include <limits.h> 69# include <syslog.h> 70# include <unistd.h> 71# include <pthread.h> 72# include <crt_externs.h> 73# include <AssertMacros.h> 74# undef check 75# include <Availability.h> 76# include <TargetConditionals.h> 77# include <sys/mman.h> 78# include <sys/time.h> 79# include <sys/stat.h> 80# include <sys/param.h> 81# include <mach/mach.h> 82# include <mach/vm_param.h> 83# include <mach-o/dyld.h> 84# include <mach-o/ldsyms.h> 85# include <mach-o/loader.h> 86# include <mach-o/getsect.h> 87# include <mach-o/dyld_priv.h> 88# include <malloc/malloc.h> 89# include <os/lock_private.h> 90# include <libkern/OSAtomic.h> 91# include <libkern/OSCacheControl.h> 92# include <System/pthread_machdep.h> 93# include "objc-probes.h" // generated dtrace probe definitions. 94 95// Some libc functions call objc_msgSend() 96// so we can't use them without deadlocks. 97void syslog(int, const char *, ...) UNAVAILABLE_ATTRIBUTE; 98void vsyslog(int, const char *, va_list) UNAVAILABLE_ATTRIBUTE; 99 100 101#define ALWAYS_INLINE inline __attribute__((always_inline)) 102#define NEVER_INLINE inline __attribute__((noinline)) 103 104 105 106static ALWAYS_INLINE uintptr_t 107addc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout) 108{ 109 return __builtin_addcl(lhs, rhs, carryin, carryout); 110} 111 112static ALWAYS_INLINE uintptr_t 113subc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout) 114{ 115 return __builtin_subcl(lhs, rhs, carryin, carryout); 116} 117 118 119#if __arm64__ 120 121static ALWAYS_INLINE 122uintptr_t 123LoadExclusive(uintptr_t *src) 124{ 125 uintptr_t result; 126 asm("ldxr %x0, [%x1]" 127 : "=r" (result) 128 : "r" (src), "m" (*src)); 129 return result; 130} 131 132static ALWAYS_INLINE 133bool 134StoreExclusive(uintptr_t *dst, uintptr_t oldvalue __unused, uintptr_t value) 135{ 136 uint32_t result; 137 asm("stxr %w0, %x2, [%x3]" 138 : "=r" (result), "=m" (*dst) 139 : "r" (value), "r" (dst)); 140 return !result; 141} 142 143 144static ALWAYS_INLINE 145bool 146StoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue __unused, uintptr_t value) 147{ 148 uint32_t result; 149 asm("stlxr %w0, %x2, [%x3]" 150 : "=r" (result), "=m" (*dst) 151 : "r" (value), "r" (dst)); 152 return !result; 153} 154 155 156#elif __arm__ 157 158static ALWAYS_INLINE 159uintptr_t 160LoadExclusive(uintptr_t *src) 161{ 162 return *src; 163} 164 165static ALWAYS_INLINE 166bool 167StoreExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value) 168{ 169 return OSAtomicCompareAndSwapPtr((void *)oldvalue, (void *)value, 170 (void **)dst); 171} 172 173static ALWAYS_INLINE 174bool 175StoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value) 176{ 177 return OSAtomicCompareAndSwapPtrBarrier((void *)oldvalue, (void *)value, 178 (void **)dst); 179} 180 181 182#elif __x86_64__ || __i386__ 183 184static ALWAYS_INLINE 185uintptr_t 186LoadExclusive(uintptr_t *src) 187{ 188 return *src; 189} 190 191static ALWAYS_INLINE 192bool 193StoreExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value) 194{ 195 196 return __sync_bool_compare_and_swap((void **)dst, (void *)oldvalue, (void *)value); 197} 198 199static ALWAYS_INLINE 200bool 201StoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value) 202{ 203 return StoreExclusive(dst, oldvalue, value); 204} 205 206#else 207# error unknown architecture 208#endif 209 210 211#define spinlock_t os_lock_handoff_s 212#define spinlock_trylock(l) os_lock_trylock(l) 213#define spinlock_lock(l) os_lock_lock(l) 214#define spinlock_unlock(l) os_lock_unlock(l) 215#define SPINLOCK_INITIALIZER OS_LOCK_HANDOFF_INIT 216 217 218#if !TARGET_OS_IPHONE 219# include <CrashReporterClient.h> 220#else 221 // CrashReporterClient not yet available on iOS 222 __BEGIN_DECLS 223 extern const char *CRSetCrashLogMessage(const char *msg); 224 extern const char *CRGetCrashLogMessage(void); 225 extern const char *CRSetCrashLogMessage2(const char *msg); 226 __END_DECLS 227#endif 228 229# if __cplusplus 230# include <vector> 231# include <algorithm> 232# include <functional> 233 using namespace std; 234# endif 235 236# define PRIVATE_EXTERN __attribute__((visibility("hidden"))) 237# undef __private_extern__ 238# define __private_extern__ use_PRIVATE_EXTERN_instead 239# undef private_extern 240# define private_extern use_PRIVATE_EXTERN_instead 241 242/* Use this for functions that are intended to be breakpoint hooks. 243 If you do not, the compiler may optimize them away. 244 BREAKPOINT_FUNCTION( void stop_on_error(void) ); */ 245# define BREAKPOINT_FUNCTION(prototype) \ 246 OBJC_EXTERN __attribute__((noinline, used, visibility("hidden"))) \ 247 prototype { asm(""); } 248 249#elif TARGET_OS_WIN32 250 251# define WINVER 0x0501 // target Windows XP and later 252# define _WIN32_WINNT 0x0501 // target Windows XP and later 253# define WIN32_LEAN_AND_MEAN 254 // hack: windef.h typedefs BOOL as int 255# define BOOL WINBOOL 256# include <windows.h> 257# undef BOOL 258 259# include <stdio.h> 260# include <stdlib.h> 261# include <stdint.h> 262# include <stdarg.h> 263# include <string.h> 264# include <assert.h> 265# include <malloc.h> 266# include <Availability.h> 267 268# if __cplusplus 269# include <vector> 270# include <algorithm> 271# include <functional> 272 using namespace std; 273# define __BEGIN_DECLS extern "C" { 274# define __END_DECLS } 275# else 276# define __BEGIN_DECLS /*empty*/ 277# define __END_DECLS /*empty*/ 278# endif 279 280# define PRIVATE_EXTERN 281# define __attribute__(x) 282# define inline __inline 283 284/* Use this for functions that are intended to be breakpoint hooks. 285 If you do not, the compiler may optimize them away. 286 BREAKPOINT_FUNCTION( void MyBreakpointFunction(void) ); */ 287# define BREAKPOINT_FUNCTION(prototype) \ 288 __declspec(noinline) prototype { __asm { } } 289 290/* stub out dtrace probes */ 291# define OBJC_RUNTIME_OBJC_EXCEPTION_RETHROW() do {} while(0) 292# define OBJC_RUNTIME_OBJC_EXCEPTION_THROW(arg0) do {} while(0) 293 294#else 295# error unknown OS 296#endif 297 298 299#include <objc/objc.h> 300#include <objc/objc-api.h> 301 302__BEGIN_DECLS 303 304extern void _objc_fatal(const char *fmt, ...) __attribute__((noreturn, format (printf, 1, 2))); 305 306#define INIT_ONCE_PTR(var, create, delete) \ 307 do { \ 308 if (var) break; \ 309 typeof(var) v = create; \ 310 while (!var) { \ 311 if (OSAtomicCompareAndSwapPtrBarrier(0, (void*)v, (void**)&var)){ \ 312 goto done; \ 313 } \ 314 } \ 315 delete; \ 316 done:; \ 317 } while (0) 318 319#define INIT_ONCE_32(var, create, delete) \ 320 do { \ 321 if (var) break; \ 322 typeof(var) v = create; \ 323 while (!var) { \ 324 if (OSAtomicCompareAndSwap32Barrier(0, v, (volatile int32_t *)&var)) { \ 325 goto done; \ 326 } \ 327 } \ 328 delete; \ 329 done:; \ 330 } while (0) 331 332 333// Thread keys reserved by libc for our use. 334// Keys [0..4] are used by autozone. 335#if defined(__PTK_FRAMEWORK_OBJC_KEY5) 336# define SUPPORT_DIRECT_THREAD_KEYS 1 337# define TLS_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY5) 338# define SYNC_DATA_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY6) 339# define SYNC_COUNT_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY7) 340# define AUTORELEASE_POOL_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY8) 341# if SUPPORT_RETURN_AUTORELEASE 342# define AUTORELEASE_POOL_RECLAIM_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY9) 343# endif 344#else 345# define SUPPORT_DIRECT_THREAD_KEYS 0 346#endif 347 348 349#if TARGET_OS_WIN32 350 351// Compiler compatibility 352 353// OS compatibility 354 355#define strdup _strdup 356 357#define issetugid() 0 358 359#define MIN(x, y) ((x) < (y) ? (x) : (y)) 360 361static __inline void bcopy(const void *src, void *dst, size_t size) { memcpy(dst, src, size); } 362static __inline void bzero(void *dst, size_t size) { memset(dst, 0, size); } 363 364int asprintf(char **dstp, const char *format, ...); 365 366typedef void * malloc_zone_t; 367 368static __inline malloc_zone_t malloc_default_zone(void) { return (malloc_zone_t)-1; } 369static __inline void *malloc_zone_malloc(malloc_zone_t z, size_t size) { return malloc(size); } 370static __inline void *malloc_zone_calloc(malloc_zone_t z, size_t size, size_t count) { return calloc(size, count); } 371static __inline void *malloc_zone_realloc(malloc_zone_t z, void *p, size_t size) { return realloc(p, size); } 372static __inline void malloc_zone_free(malloc_zone_t z, void *p) { free(p); } 373static __inline malloc_zone_t malloc_zone_from_ptr(const void *p) { return (malloc_zone_t)-1; } 374static __inline size_t malloc_size(const void *p) { return _msize((void*)p); /* fixme invalid pointer check? */ } 375 376 377// AssertMacros 378 379#define require_action_string(cond, dest, act, msg) do { if (!(cond)) { { act; } goto dest; } } while (0) 380#define require_noerr_string(err, dest, msg) do { if (err) goto dest; } while (0) 381#define require_string(cond, dest, msg) do { if (!(cond)) goto dest; } while (0) 382 383 384// OSAtomic 385 386static __inline BOOL OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) 387{ 388 // fixme barrier is overkill 389 long original = InterlockedCompareExchange(dst, newl, oldl); 390 return (original == oldl); 391} 392 393static __inline BOOL OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void * volatile *dst) 394{ 395 void *original = InterlockedCompareExchangePointer(dst, newp, oldp); 396 return (original == oldp); 397} 398 399static __inline BOOL OSAtomicCompareAndSwap32Barrier(int32_t oldl, int32_t newl, int32_t volatile *dst) 400{ 401 long original = InterlockedCompareExchange((volatile long *)dst, newl, oldl); 402 return (original == oldl); 403} 404 405static __inline int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst) 406{ 407 return InterlockedDecrement((volatile long *)dst); 408} 409 410static __inline int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst) 411{ 412 return InterlockedIncrement((volatile long *)dst); 413} 414 415 416// Internal data types 417 418typedef DWORD objc_thread_t; // thread ID 419static __inline int thread_equal(objc_thread_t t1, objc_thread_t t2) { 420 return t1 == t2; 421} 422static __inline objc_thread_t thread_self(void) { 423 return GetCurrentThreadId(); 424} 425 426typedef struct { 427 DWORD key; 428 void (*dtor)(void *); 429} tls_key_t; 430static __inline tls_key_t tls_create(void (*dtor)(void*)) { 431 // fixme need dtor registry for DllMain to call on thread detach 432 tls_key_t k; 433 k.key = TlsAlloc(); 434 k.dtor = dtor; 435 return k; 436} 437static __inline void *tls_get(tls_key_t k) { 438 return TlsGetValue(k.key); 439} 440static __inline void tls_set(tls_key_t k, void *value) { 441 TlsSetValue(k.key, value); 442} 443 444typedef struct { 445 CRITICAL_SECTION *lock; 446} mutex_t; 447#define MUTEX_INITIALIZER {0}; 448extern void mutex_init(mutex_t *m); 449static __inline int _mutex_lock_nodebug(mutex_t *m) { 450 // fixme error check 451 if (!m->lock) { 452 mutex_init(m); 453 } 454 EnterCriticalSection(m->lock); 455 return 0; 456} 457static __inline bool _mutex_try_lock_nodebug(mutex_t *m) { 458 // fixme error check 459 if (!m->lock) { 460 mutex_init(m); 461 } 462 return TryEnterCriticalSection(m->lock); 463} 464static __inline int _mutex_unlock_nodebug(mutex_t *m) { 465 // fixme error check 466 LeaveCriticalSection(m->lock); 467 return 0; 468} 469 470 471typedef mutex_t spinlock_t; 472#define spinlock_lock(l) mutex_lock(l) 473#define spinlock_unlock(l) mutex_unlock(l) 474#define SPINLOCK_INITIALIZER MUTEX_INITIALIZER 475 476 477typedef struct { 478 HANDLE mutex; 479} recursive_mutex_t; 480#define RECURSIVE_MUTEX_INITIALIZER {0}; 481#define RECURSIVE_MUTEX_NOT_LOCKED 1 482extern void recursive_mutex_init(recursive_mutex_t *m); 483static __inline int _recursive_mutex_lock_nodebug(recursive_mutex_t *m) { 484 assert(m->mutex); 485 return WaitForSingleObject(m->mutex, INFINITE); 486} 487static __inline bool _recursive_mutex_try_lock_nodebug(recursive_mutex_t *m) { 488 assert(m->mutex); 489 return (WAIT_OBJECT_0 == WaitForSingleObject(m->mutex, 0)); 490} 491static __inline int _recursive_mutex_unlock_nodebug(recursive_mutex_t *m) { 492 assert(m->mutex); 493 return ReleaseMutex(m->mutex) ? 0 : RECURSIVE_MUTEX_NOT_LOCKED; 494} 495 496 497/* 498typedef HANDLE mutex_t; 499static inline void mutex_init(HANDLE *m) { *m = CreateMutex(NULL, FALSE, NULL); } 500static inline void _mutex_lock(mutex_t *m) { WaitForSingleObject(*m, INFINITE); } 501static inline bool mutex_try_lock(mutex_t *m) { return WaitForSingleObject(*m, 0) == WAIT_OBJECT_0; } 502static inline void _mutex_unlock(mutex_t *m) { ReleaseMutex(*m); } 503*/ 504 505// based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html 506// Vista-only CONDITION_VARIABLE would be better 507typedef struct { 508 HANDLE mutex; 509 HANDLE waiters; // semaphore for those in cond_wait() 510 HANDLE waitersDone; // auto-reset event after everyone gets a broadcast 511 CRITICAL_SECTION waitCountLock; // guards waitCount and didBroadcast 512 unsigned int waitCount; 513 int didBroadcast; 514} monitor_t; 515#define MONITOR_INITIALIZER { 0 } 516#define MONITOR_NOT_ENTERED 1 517extern int monitor_init(monitor_t *c); 518 519static inline int _monitor_enter_nodebug(monitor_t *c) { 520 if (!c->mutex) { 521 int err = monitor_init(c); 522 if (err) return err; 523 } 524 return WaitForSingleObject(c->mutex, INFINITE); 525} 526static inline int _monitor_exit_nodebug(monitor_t *c) { 527 if (!ReleaseMutex(c->mutex)) return MONITOR_NOT_ENTERED; 528 else return 0; 529} 530static inline int _monitor_wait_nodebug(monitor_t *c) { 531 int last; 532 EnterCriticalSection(&c->waitCountLock); 533 c->waitCount++; 534 LeaveCriticalSection(&c->waitCountLock); 535 536 SignalObjectAndWait(c->mutex, c->waiters, INFINITE, FALSE); 537 538 EnterCriticalSection(&c->waitCountLock); 539 c->waitCount--; 540 last = c->didBroadcast && c->waitCount == 0; 541 LeaveCriticalSection(&c->waitCountLock); 542 543 if (last) { 544 // tell broadcaster that all waiters have awoken 545 SignalObjectAndWait(c->waitersDone, c->mutex, INFINITE, FALSE); 546 } else { 547 WaitForSingleObject(c->mutex, INFINITE); 548 } 549 550 // fixme error checking 551 return 0; 552} 553static inline int monitor_notify(monitor_t *c) { 554 int haveWaiters; 555 556 EnterCriticalSection(&c->waitCountLock); 557 haveWaiters = c->waitCount > 0; 558 LeaveCriticalSection(&c->waitCountLock); 559 560 if (haveWaiters) { 561 ReleaseSemaphore(c->waiters, 1, 0); 562 } 563 564 // fixme error checking 565 return 0; 566} 567static inline int monitor_notifyAll(monitor_t *c) { 568 EnterCriticalSection(&c->waitCountLock); 569 if (c->waitCount == 0) { 570 LeaveCriticalSection(&c->waitCountLock); 571 return 0; 572 } 573 c->didBroadcast = 1; 574 ReleaseSemaphore(c->waiters, c->waitCount, 0); 575 LeaveCriticalSection(&c->waitCountLock); 576 577 // fairness: wait for everyone to move from waiters to mutex 578 WaitForSingleObject(c->waitersDone, INFINITE); 579 // not under waitCountLock, but still under mutex 580 c->didBroadcast = 0; 581 582 // fixme error checking 583 return 0; 584} 585 586 587// fixme no rwlock yet 588 589#define rwlock_t mutex_t 590#define rwlock_init(r) mutex_init(r) 591#define _rwlock_read_nodebug(m) _mutex_lock_nodebug(m) 592#define _rwlock_write_nodebug(m) _mutex_lock_nodebug(m) 593#define _rwlock_try_read_nodebug(m) _mutex_try_lock_nodebug(m) 594#define _rwlock_try_write_nodebug(m) _mutex_try_lock_nodebug(m) 595#define _rwlock_unlock_read_nodebug(m) _mutex_unlock_nodebug(m) 596#define _rwlock_unlock_write_nodebug(m) _mutex_unlock_nodebug(m) 597 598 599typedef IMAGE_DOS_HEADER headerType; 600// fixme YES bundle? NO bundle? sometimes? 601#define headerIsBundle(hi) YES 602OBJC_EXTERN IMAGE_DOS_HEADER __ImageBase; 603#define libobjc_header ((headerType *)&__ImageBase) 604 605// Prototypes 606 607 608#elif TARGET_OS_MAC 609 610 611// OS headers 612#include <mach-o/loader.h> 613#ifndef __LP64__ 614# define SEGMENT_CMD LC_SEGMENT 615#else 616# define SEGMENT_CMD LC_SEGMENT_64 617#endif 618 619#ifndef VM_MEMORY_OBJC_DISPATCHERS 620# define VM_MEMORY_OBJC_DISPATCHERS 0 621#endif 622 623 624// Compiler compatibility 625 626// OS compatibility 627 628// Internal data types 629 630typedef pthread_t objc_thread_t; 631 632static __inline int thread_equal(objc_thread_t t1, objc_thread_t t2) { 633 return pthread_equal(t1, t2); 634} 635static __inline objc_thread_t thread_self(void) { 636 return pthread_self(); 637} 638 639 640typedef pthread_key_t tls_key_t; 641 642static inline tls_key_t tls_create(void (*dtor)(void*)) { 643 tls_key_t k; 644 pthread_key_create(&k, dtor); 645 return k; 646} 647static inline void *tls_get(tls_key_t k) { 648 return pthread_getspecific(k); 649} 650static inline void tls_set(tls_key_t k, void *value) { 651 pthread_setspecific(k, value); 652} 653 654#if SUPPORT_DIRECT_THREAD_KEYS 655 656#if !NDEBUG 657static bool is_valid_direct_key(tls_key_t k) { 658 return ( k == SYNC_DATA_DIRECT_KEY 659 || k == SYNC_COUNT_DIRECT_KEY 660 || k == AUTORELEASE_POOL_KEY 661# if SUPPORT_RETURN_AUTORELEASE 662 || k == AUTORELEASE_POOL_RECLAIM_KEY 663# endif 664 ); 665} 666#endif 667 668#if __arm__ 669 670// rdar://9162780 _pthread_get/setspecific_direct are inefficient 671// copied from libdispatch 672 673__attribute__((const)) 674static ALWAYS_INLINE void** 675tls_base(void) 676{ 677 uintptr_t p; 678#if defined(__arm__) && defined(_ARM_ARCH_6) 679 __asm__("mrc p15, 0, %[p], c13, c0, 3" : [p] "=&r" (p)); 680 return (void**)(p & ~0x3ul); 681#else 682#error tls_base not implemented 683#endif 684} 685 686 687static ALWAYS_INLINE void 688tls_set_direct(void **tsdb, tls_key_t k, void *v) 689{ 690 assert(is_valid_direct_key(k)); 691 692 tsdb[k] = v; 693} 694#define tls_set_direct(k, v) \ 695 tls_set_direct(tls_base(), (k), (v)) 696 697 698static ALWAYS_INLINE void * 699tls_get_direct(void **tsdb, tls_key_t k) 700{ 701 assert(is_valid_direct_key(k)); 702 703 return tsdb[k]; 704} 705#define tls_get_direct(k) \ 706 tls_get_direct(tls_base(), (k)) 707 708// arm 709#else 710// not arm 711 712static inline void *tls_get_direct(tls_key_t k) 713{ 714 assert(is_valid_direct_key(k)); 715 716 if (_pthread_has_direct_tsd()) { 717 return _pthread_getspecific_direct(k); 718 } else { 719 return pthread_getspecific(k); 720 } 721} 722static inline void tls_set_direct(tls_key_t k, void *value) 723{ 724 assert(is_valid_direct_key(k)); 725 726 if (_pthread_has_direct_tsd()) { 727 _pthread_setspecific_direct(k, value); 728 } else { 729 pthread_setspecific(k, value); 730 } 731} 732 733// not arm 734#endif 735 736// SUPPORT_DIRECT_THREAD_KEYS 737#endif 738 739 740typedef pthread_mutex_t mutex_t; 741#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER; 742 743static inline int _mutex_lock_nodebug(mutex_t *m) { 744 return pthread_mutex_lock(m); 745} 746static inline bool _mutex_try_lock_nodebug(mutex_t *m) { 747 return !pthread_mutex_trylock(m); 748} 749static inline int _mutex_unlock_nodebug(mutex_t *m) { 750 return pthread_mutex_unlock(m); 751} 752 753 754typedef struct { 755 pthread_mutex_t *mutex; 756} recursive_mutex_t; 757#define RECURSIVE_MUTEX_INITIALIZER {0}; 758#define RECURSIVE_MUTEX_NOT_LOCKED EPERM 759extern void recursive_mutex_init(recursive_mutex_t *m); 760 761static inline int _recursive_mutex_lock_nodebug(recursive_mutex_t *m) { 762 assert(m->mutex); 763 return pthread_mutex_lock(m->mutex); 764} 765static inline bool _recursive_mutex_try_lock_nodebug(recursive_mutex_t *m) { 766 assert(m->mutex); 767 return !pthread_mutex_trylock(m->mutex); 768} 769static inline int _recursive_mutex_unlock_nodebug(recursive_mutex_t *m) { 770 assert(m->mutex); 771 return pthread_mutex_unlock(m->mutex); 772} 773 774 775typedef struct { 776 pthread_mutex_t mutex; 777 pthread_cond_t cond; 778} monitor_t; 779#define MONITOR_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER } 780#define MONITOR_NOT_ENTERED EPERM 781 782static inline int monitor_init(monitor_t *c) { 783 int err = pthread_mutex_init(&c->mutex, NULL); 784 if (err) return err; 785 err = pthread_cond_init(&c->cond, NULL); 786 if (err) { 787 pthread_mutex_destroy(&c->mutex); 788 return err; 789 } 790 return 0; 791} 792static inline int _monitor_enter_nodebug(monitor_t *c) { 793 return pthread_mutex_lock(&c->mutex); 794} 795static inline int _monitor_exit_nodebug(monitor_t *c) { 796 return pthread_mutex_unlock(&c->mutex); 797} 798static inline int _monitor_wait_nodebug(monitor_t *c) { 799 return pthread_cond_wait(&c->cond, &c->mutex); 800} 801static inline int monitor_notify(monitor_t *c) { 802 return pthread_cond_signal(&c->cond); 803} 804static inline int monitor_notifyAll(monitor_t *c) { 805 return pthread_cond_broadcast(&c->cond); 806} 807 808 809// semaphore_create formatted for INIT_ONCE use 810static inline semaphore_t create_semaphore(void) 811{ 812 semaphore_t sem; 813 kern_return_t k; 814 k = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0); 815 if (k) _objc_fatal("semaphore_create failed (0x%x)", k); 816 return sem; 817} 818 819 820/* Custom read-write lock 821 - reader is atomic add/subtract 822 - writer is pthread mutex plus atomic add/subtract 823 - fairness: new readers wait if a writer wants in 824 - fairness: when writer completes, readers (probably) precede new writer 825 826 state: xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyz 827 x: blocked reader count 828 y: active reader count 829 z: readers allowed flag 830*/ 831typedef struct { 832 pthread_rwlock_t rwl; 833} rwlock_t; 834 835static inline void rwlock_init(rwlock_t *l) 836{ 837 int err __unused = pthread_rwlock_init(&l->rwl, NULL); 838 assert(err == 0); 839} 840 841static inline void _rwlock_read_nodebug(rwlock_t *l) 842{ 843 int err __unused = pthread_rwlock_rdlock(&l->rwl); 844 assert(err == 0); 845} 846 847static inline void _rwlock_unlock_read_nodebug(rwlock_t *l) 848{ 849 int err __unused = pthread_rwlock_unlock(&l->rwl); 850 assert(err == 0); 851} 852 853 854static inline bool _rwlock_try_read_nodebug(rwlock_t *l) 855{ 856 int err = pthread_rwlock_tryrdlock(&l->rwl); 857 assert(err == 0 || err == EBUSY); 858 return (err == 0); 859} 860 861 862static inline void _rwlock_write_nodebug(rwlock_t *l) 863{ 864 int err __unused = pthread_rwlock_wrlock(&l->rwl); 865 assert(err == 0); 866} 867 868static inline void _rwlock_unlock_write_nodebug(rwlock_t *l) 869{ 870 int err __unused = pthread_rwlock_unlock(&l->rwl); 871 assert(err == 0); 872} 873 874static inline bool _rwlock_try_write_nodebug(rwlock_t *l) 875{ 876 int err = pthread_rwlock_trywrlock(&l->rwl); 877 assert(err == 0 || err == EBUSY); 878 return (err == 0); 879} 880 881 882#ifndef __LP64__ 883typedef struct mach_header headerType; 884typedef struct segment_command segmentType; 885typedef struct section sectionType; 886#else 887typedef struct mach_header_64 headerType; 888typedef struct segment_command_64 segmentType; 889typedef struct section_64 sectionType; 890#endif 891#define headerIsBundle(hi) (hi->mhdr->filetype == MH_BUNDLE) 892#define libobjc_header ((headerType *)&_mh_dylib_header) 893 894// Prototypes 895 896/* Secure /tmp usage */ 897extern int secure_open(const char *filename, int flags, uid_t euid); 898 899 900#else 901 902 903#error unknown OS 904 905 906#endif 907 908__END_DECLS 909 910#endif 911