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