-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobjc-os.h
1132 lines (918 loc) · 30.8 KB
/
objc-os.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* 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 <TargetConditionals.h>
#include "objc-config.h"
#ifdef __LP64__ /// LP64指的是LONG/POINTER字长为64位
# define WORD_SHIFT 3UL
# define WORD_MASK 7UL
# define WORD_BITS 64
#else
# define WORD_SHIFT 2UL
# define WORD_MASK 3UL
# define WORD_BITS 32
#endif
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
static inline size_t word_align(size_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
// Mix-in for classes that must not be copied.
class nocopy_t {
private:
nocopy_t(const nocopy_t&) = delete;
const nocopy_t& operator=(const nocopy_t&) = delete;
protected:
constexpr nocopy_t() = default;
~nocopy_t() = default;
};
#if TARGET_OS_MAC
# define OS_UNFAIR_LOCK_INLINE 1
# ifndef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS
# endif
# include <stdio.h>
# include <stdlib.h>
# include <stdint.h>
# include <stdarg.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include <dlfcn.h>
# include <fcntl.h>
# include <assert.h>
# include <limits.h>
# include <syslog.h>
# include <unistd.h>
# include <pthread.h>
# include <crt_externs.h>
# undef check
# include <Availability.h>
# include <TargetConditionals.h>
# include <sys/mman.h>
# include <sys/time.h>
# include <sys/stat.h>
# include <sys/param.h>
# include <sys/reason.h>
# include <mach/mach.h>
# include <mach/vm_param.h>
# include <mach/mach_time.h>
# include <mach-o/dyld.h>
# include <mach-o/ldsyms.h>
# include <mach-o/loader.h>
# include <mach-o/getsect.h>
# include <mach-o/dyld_priv.h>
# include <malloc/malloc.h>
# include <os/lock_private.h>
# include <libkern/OSAtomic.h>
# include <libkern/OSCacheControl.h>
# include <System/pthread_machdep.h>
# include "objc-probes.h" // generated dtrace probe definitions.
// Some libc functions call objc_msgSend()
// so we can't use them without deadlocks.
void syslog(int, const char *, ...) UNAVAILABLE_ATTRIBUTE;
void vsyslog(int, const char *, va_list) UNAVAILABLE_ATTRIBUTE;
#define ALWAYS_INLINE inline __attribute__((always_inline))
#define NEVER_INLINE inline __attribute__((noinline))
/**
这个指令是gcc引入的,作用是"允许程序员将最有可能执行的分支告诉编译器"。
这个指令的写法为:__builtin_expect(EXP, N)。返回值为EXP表达式的返回值
意思是:EXP==N的概率很大。一般的使用方法是将__builtin_expect指令封装为fastpath和slowpath宏。
__builtin_expect(bool(x),1)表示 x 的值为真的可能性更大;
__builtin_expect(bool(x),0)表示 x 的值为假的可能性更大。
也就是说,使用fastpath(),执行 if 后面的语句的机会更大,使用 slowpath(),执行 else 后面的语句的机会更大。
通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。
http://velep.com/archives/795.html
*/
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
/**
# define ALWAYS_INLINE inline __attribute__((always_inline))
inline 是一种降低函数调用成本的方法,其本质是在调用声明为 inline 的函数时,会直接把函数的实现替换过去,这样减少了调用函数的成本。
当然 inline 是一种以空间换时间的做法,滥用 inline 会导致应用程序的体积增大。
有的时候编译器未必会真的按照你声明 inline 的方式去用函数的实现替换函数的调用。
这里使用强制内联
*/
static ALWAYS_INLINE uintptr_t
addc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)
{
return __builtin_addcl(lhs, rhs, carryin, carryout);
}
static ALWAYS_INLINE uintptr_t
subc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)
{
return __builtin_subcl(lhs, rhs, carryin, carryout);
}
#if __arm64__
// Pointer-size register prefix for inline asm
# if __LP64__
# define p "x" // true arm64
# else
# define p "w" // arm64_32
# endif
static ALWAYS_INLINE
uintptr_t
LoadExclusive(uintptr_t *src)
{
uintptr_t result;
asm("ldxr %" p "0, [%x1]"
: "=r" (result)
: "r" (src), "m" (*src));
return result;
}
static ALWAYS_INLINE
bool
StoreExclusive(uintptr_t *dst, uintptr_t oldvalue __unused, uintptr_t value)
{
uint32_t result;
asm("stxr %w0, %" p "2, [%x3]"
: "=&r" (result), "=m" (*dst)
: "r" (value), "r" (dst));
return !result;
}
static ALWAYS_INLINE
bool
StoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue __unused, uintptr_t value)
{
uint32_t result;
asm("stlxr %w0, %" p "2, [%x3]"
: "=&r" (result), "=m" (*dst)
: "r" (value), "r" (dst));
return !result;
}
static ALWAYS_INLINE
void
ClearExclusive(uintptr_t *dst)
{
// pretend it writes to *dst for instruction ordering purposes
asm("clrex" : "=m" (*dst));
}
#undef p
#elif __arm__
static ALWAYS_INLINE
uintptr_t
LoadExclusive(uintptr_t *src)
{
return *src;
}
static ALWAYS_INLINE
bool
StoreExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)
{
return OSAtomicCompareAndSwapPtr((void *)oldvalue, (void *)value,
(void **)dst);
}
static ALWAYS_INLINE
bool
StoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)
{
return OSAtomicCompareAndSwapPtrBarrier((void *)oldvalue, (void *)value,
(void **)dst);
}
static ALWAYS_INLINE
void
ClearExclusive(uintptr_t *dst __unused)
{
}
#elif __x86_64__ || __i386__
static ALWAYS_INLINE
uintptr_t
LoadExclusive(uintptr_t *src)
{
return *src;
}
static ALWAYS_INLINE
bool
StoreExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)
{
// 比较oldvalue和dst指针指向的值,若两者相等则将value写入dst指针的内容且返回true,否则不写入且返回false;
return __sync_bool_compare_and_swap((void **)dst, (void *)oldvalue, (void *)value);
}
static ALWAYS_INLINE
bool
StoreReleaseExclusive(uintptr_t *dst, uintptr_t oldvalue, uintptr_t value)
{
return StoreExclusive(dst, oldvalue, value);
}
static ALWAYS_INLINE
void
ClearExclusive(uintptr_t *dst __unused)
{
}
#else
# error unknown architecture
#endif
#if !TARGET_OS_IPHONE
# include <CrashReporterClient.h>
#else
// CrashReporterClient not yet available on iOS
__BEGIN_DECLS
extern const char *CRSetCrashLogMessage(const char *msg);
extern const char *CRGetCrashLogMessage(void);
__END_DECLS
#endif
# if __cplusplus
# include <vector>
# include <algorithm>
# include <functional>
using namespace std;
# endif
# define PRIVATE_EXTERN __attribute__((visibility("hidden")))
# undef __private_extern__
# define __private_extern__ use_PRIVATE_EXTERN_instead
# undef private_extern
# define private_extern use_PRIVATE_EXTERN_instead
/* Use this for functions that are intended to be breakpoint hooks.
If you do not, the compiler may optimize them away.
BREAKPOINT_FUNCTION( void stop_on_error(void) ); */
# define BREAKPOINT_FUNCTION(prototype) \
OBJC_EXTERN __attribute__((noinline, used, visibility("hidden"))) \
prototype { asm(""); }
#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 <windows.h>
# undef BOOL
# include <stdio.h>
# include <stdlib.h>
# include <stdint.h>
# include <stdarg.h>
# include <string.h>
# include <assert.h>
# include <malloc.h>
# include <Availability.h>
# if __cplusplus
# include <vector>
# include <algorithm>
# include <functional>
using namespace std;
# 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
/* Use this for functions that are intended to be breakpoint hooks.
If you do not, the compiler may optimize them away.
BREAKPOINT_FUNCTION( void MyBreakpointFunction(void) ); */
# define BREAKPOINT_FUNCTION(prototype) \
__declspec(noinline) prototype { __asm { } }
/* 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 <objc/objc.h>
#include <objc/objc-api.h>
extern void _objc_fatal(const char *fmt, ...)
__attribute__((noreturn, format (printf, 1, 2)));
extern void _objc_fatal_with_reason(uint64_t reason, uint64_t flags,
const char *fmt, ...)
__attribute__((noreturn, format (printf, 3, 4)));
#define INIT_ONCE_PTR(var, create, delete) \
do { \
if (var) break; \
typeof(var) v = create; \
while (!var) { \
if (OSAtomicCompareAndSwapPtrBarrier(0, (void*)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.
#if defined(__PTK_FRAMEWORK_OBJC_KEY0)
# define SUPPORT_DIRECT_THREAD_KEYS 1
# define TLS_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY0)
# define SYNC_DATA_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY1)
# define SYNC_COUNT_DIRECT_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY2)
# define AUTORELEASE_POOL_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY3)
# if SUPPORT_RETURN_AUTORELEASE
# define RETURN_DISPOSITION_KEY ((tls_key_t)__PTK_FRAMEWORK_OBJC_KEY4)
# endif
#else
# define SUPPORT_DIRECT_THREAD_KEYS 0
#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? */ }
// 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 tls_key_t tls_create(void (*dtor)(void*)) {
// fixme need dtor registry for DllMain to call on thread detach
tls_key_t k;
k.key = TlsAlloc();
k.dtor = dtor;
return k;
}
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 bool _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 spinlock_t;
#define spinlock_lock(l) mutex_lock(l)
#define spinlock_unlock(l) mutex_unlock(l)
#define SPINLOCK_INITIALIZER 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 bool _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 bool 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_leave_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;
}
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
#include <mach-o/loader.h>
#ifndef __LP64__
# define SEGMENT_CMD LC_SEGMENT
#else
# define SEGMENT_CMD LC_SEGMENT_64
#endif
#ifndef VM_MEMORY_OBJC_DISPATCHERS
# define VM_MEMORY_OBJC_DISPATCHERS 0
#endif
// Compiler compatibility
// OS compatibility
static inline uint64_t nanoseconds() {
return mach_absolute_time();
}
// 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 tls_key_t tls_create(void (*dtor)(void*)) {
tls_key_t k;
pthread_key_create(&k, dtor);
return k;
}
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);
}
#if SUPPORT_DIRECT_THREAD_KEYS
#if DEBUG
static bool is_valid_direct_key(tls_key_t k) {
return ( k == SYNC_DATA_DIRECT_KEY
|| k == SYNC_COUNT_DIRECT_KEY
|| k == AUTORELEASE_POOL_KEY
# if SUPPORT_RETURN_AUTORELEASE
|| k == RETURN_DISPOSITION_KEY
# endif
);
}
#endif
static inline void *tls_get_direct(tls_key_t k)
{
assert(is_valid_direct_key(k));
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(is_valid_direct_key(k));
if (_pthread_has_direct_tsd()) {
_pthread_setspecific_direct(k, value);
} else {
pthread_setspecific(k, value);
}
}
// SUPPORT_DIRECT_THREAD_KEYS
#endif
static inline pthread_t pthread_self_direct()
{
return (pthread_t)
_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
}
static inline mach_port_t mach_thread_self_direct()
{
return (mach_port_t)(uintptr_t)
_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF);
}
template <bool Debug> class mutex_tt;
template <bool Debug> class monitor_tt;
template <bool Debug> class recursive_mutex_tt;
#if DEBUG
# define LOCKDEBUG 1
#else
# define LOCKDEBUG 0
#endif
using spinlock_t = mutex_tt<LOCKDEBUG>;
using mutex_t = mutex_tt<LOCKDEBUG>;
using monitor_t = monitor_tt<LOCKDEBUG>;
using recursive_mutex_t = recursive_mutex_tt<LOCKDEBUG>;
// Use fork_unsafe_lock to get a lock that isn't
// acquired and released around fork().
// All fork-safe locks are checked in debug builds.
struct fork_unsafe_lock_t {
constexpr fork_unsafe_lock_t() = default;
};
extern const fork_unsafe_lock_t fork_unsafe_lock;
#include "objc-lockdebug.h"
template <bool Debug>
class mutex_tt : nocopy_t {
os_unfair_lock mLock;
public:
constexpr mutex_tt() : mLock(OS_UNFAIR_LOCK_INIT) {
lockdebug_remember_mutex(this);
}
constexpr mutex_tt(const fork_unsafe_lock_t unsafe) : mLock(OS_UNFAIR_LOCK_INIT) { }
void lock() {
lockdebug_mutex_lock(this);
os_unfair_lock_lock_with_options_inline
(&mLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION);
}
void unlock() {
lockdebug_mutex_unlock(this);
os_unfair_lock_unlock_inline(&mLock);
}
void forceReset() {
lockdebug_mutex_unlock(this);
bzero(&mLock, sizeof(mLock));
mLock = os_unfair_lock OS_UNFAIR_LOCK_INIT;
}
void assertLocked() {
lockdebug_mutex_assert_locked(this);
}
void assertUnlocked() {
lockdebug_mutex_assert_unlocked(this);
}
// Address-ordered lock discipline for a pair of locks.
static void lockTwo(mutex_tt *lock1, mutex_tt *lock2) {
if (lock1 < lock2) {
lock1->lock();
lock2->lock();
} else {
lock2->lock();
if (lock2 != lock1) lock1->lock();
}
}
static void unlockTwo(mutex_tt *lock1, mutex_tt *lock2) {
lock1->unlock();
if (lock2 != lock1) lock2->unlock();
}
// Scoped lock and unlock
class locker : nocopy_t {
mutex_tt& lock;
public:
locker(mutex_tt& newLock)
: lock(newLock) { lock.lock(); }
~locker() { lock.unlock(); }
};
// Either scoped lock and unlock, or NOP.
class conditional_locker : nocopy_t {
mutex_tt& lock;
bool didLock;
public:
conditional_locker(mutex_tt& newLock, bool shouldLock)
: lock(newLock), didLock(shouldLock)
{
if (shouldLock) lock.lock();
}
~conditional_locker() { if (didLock) lock.unlock(); }
};
};
using mutex_locker_t = mutex_tt<LOCKDEBUG>::locker;
using conditional_mutex_locker_t = mutex_tt<LOCKDEBUG>::conditional_locker;
template <bool Debug>
class recursive_mutex_tt : nocopy_t {
os_unfair_recursive_lock mLock;
public:
constexpr recursive_mutex_tt() : mLock(OS_UNFAIR_RECURSIVE_LOCK_INIT) {
lockdebug_remember_recursive_mutex(this);
}
constexpr recursive_mutex_tt(const fork_unsafe_lock_t unsafe)
: mLock(OS_UNFAIR_RECURSIVE_LOCK_INIT)
{ }
void lock()
{
lockdebug_recursive_mutex_lock(this);
os_unfair_recursive_lock_lock(&mLock);
}
void unlock()
{
lockdebug_recursive_mutex_unlock(this);
os_unfair_recursive_lock_unlock(&mLock);
}
void forceReset()
{
lockdebug_recursive_mutex_unlock(this);
bzero(&mLock, sizeof(mLock));
mLock = os_unfair_recursive_lock OS_UNFAIR_RECURSIVE_LOCK_INIT;
}
bool tryUnlock()
{
if (os_unfair_recursive_lock_tryunlock4objc(&mLock)) {
lockdebug_recursive_mutex_unlock(this);
return true;
}
return false;
}
void assertLocked() {
lockdebug_recursive_mutex_assert_locked(this);
}
void assertUnlocked() {
lockdebug_recursive_mutex_assert_unlocked(this);
}
};
template <bool Debug>
class monitor_tt {
pthread_mutex_t mutex;
pthread_cond_t cond;
public:
constexpr monitor_tt()
: mutex(PTHREAD_MUTEX_INITIALIZER), cond(PTHREAD_COND_INITIALIZER)
{
lockdebug_remember_monitor(this);
}
monitor_tt(const fork_unsafe_lock_t unsafe)
: mutex(PTHREAD_MUTEX_INITIALIZER), cond(PTHREAD_COND_INITIALIZER)
{ }
void enter()
{
lockdebug_monitor_enter(this);
int err = pthread_mutex_lock(&mutex);
if (err) _objc_fatal("pthread_mutex_lock failed (%d)", err);
}
void leave()
{
lockdebug_monitor_leave(this);
int err = pthread_mutex_unlock(&mutex);
if (err) _objc_fatal("pthread_mutex_unlock failed (%d)", err);
}
void wait()
{
lockdebug_monitor_wait(this);
int err = pthread_cond_wait(&cond, &mutex);
if (err) _objc_fatal("pthread_cond_wait failed (%d)", err);
}
void notify()
{
int err = pthread_cond_signal(&cond);
if (err) _objc_fatal("pthread_cond_signal failed (%d)", err);
}
void notifyAll()
{
int err = pthread_cond_broadcast(&cond);
if (err) _objc_fatal("pthread_cond_broadcast failed (%d)", err);
}
void forceReset()
{
lockdebug_monitor_leave(this);
bzero(&mutex, sizeof(mutex));
bzero(&cond, sizeof(cond));
mutex = pthread_mutex_t PTHREAD_MUTEX_INITIALIZER;
cond = pthread_cond_t PTHREAD_COND_INITIALIZER;
}
void assertLocked()
{
lockdebug_monitor_assert_locked(this);
}
void assertUnlocked()
{
lockdebug_monitor_assert_unlocked(this);
}
};
// 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;
}
#ifndef __LP64__
typedef struct mach_header headerType;
typedef struct segment_command segmentType;
typedef struct section sectionType;