解决思路
对于常用的某几种锁,操作系统会记录其持有线程(owner)是谁的信息。
pthread_mutex 互斥锁
互斥锁的结构为pthread_mutex_s
,对应的源码在prototypes_internal.h中定义,如下:
struct pthread_mutex_s {
long sig; //8
_pthread_lock lock; //4
union {
uint32_t value;
struct pthread_mutex_options_s options;
} mtxopts; //4
int16_t prioceiling; //2
int16_t priority; //2
#if defined(__LP64__)
uint32_t _pad; //4
#endif
union {
struct {
uint32_t m_tid[2]; // thread id of thread that has mutex locked
uint32_t m_seq[2]; // mutex sequence id
uint32_t m_mis[2]; // for misaligned locks m_tid/m_seq will span into here
} psynch;
struct _pthread_mutex_ulock_s ulock;
};
#if defined(__LP64__)
uint32_t _reserved[4];
#else
uint32_t _reserved[1];
#endif
};
typedef struct pthread_mutex_s pthread_mutex_t;
其中拥有该锁的线程ID保存在变量m_tid
中,相对pthread_mutex_s
结构的偏移为24字节,也就是0x18
,所以如果知道互斥锁的地址,即可通过地址获取到互斥锁的拥有者线程ID
owner_tid = *(int *)((char *)&mutex + 0x18)
当pthread_mutex 等待锁的时候,会停留在__psynch_mutexwait
函数,对应的锁会放在寄存器x19
中,持有该锁的tid
获取方法如下
(lldb) p/x *((int*)($x19 + 0x18))
(int) 0x001f734e
对于NSLock
,如果知道对应NSLock的地址,则可以通过NSLock获取到对应的tid,方法如下
(lldb) p/x *((int*)((char*)self->_lock + 0x20))
(int) 0x001f734e
通过thread list
打印当前线程列表,可知该锁被thread #7
持有
(lldb) thread list
Process 4551 stopped
* thread #1: tid = 0x1f725d, 0x00000001fbe09ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
thread #3: tid = 0x1f734a, 0x000000021e6bb9fc libsystem_pthread.dylib`start_wqthread
thread #7: tid = 0x1f734e, 0x00000001fbe09978 libsystem_kernel.dylib`__semwait_signal + 8, queue = 'com.apple.root.default-qos'
thread #8: tid = 0x1f734f, 0x00000001fbe09178 libsystem_kernel.dylib`mach_msg2_trap + 8, name = 'com.apple.uikit.eventfetch-thread'
thread #9: tid = 0x1f7350, 0x000000021e6bb9fc libsystem_pthread.dylib`start_wqthread
thread #10: tid = 0x1f7351, 0x000000021e6bb9fc libsystem_pthread.dylib`start_wqthread
_psynch_mutexwait
的定义在darwin-libpthread的kern_synch.c 文件,定义如下,tid
为mutex的持有线程tid
int _psynch_mutexwait(__unused proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t *retval)
根据ARM汇编的参数传递,tid保存在x3
寄存器,此时寄存器的值还没有被污染,可以直接使用x3
来打印持有该锁的tid
(lldb) p/x $x3
(unsigned long) 0x00000000001f734e
_pthread_mutex_firstfit_lock_wait(pthread_mutex_t *mutex, mutex_seq newseq, uint64_t oldtid)
实现在pthread_mutex.c
调用栈如下:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
frame #0: 0x00000001fbe09ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8
frame #1: 0x000000021e6bbd68 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
* frame #2: 0x000000021e6bb7f0 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
frame #3: 0x00000001009b810c WeTest`-[ViewController viewDidLoad](self=0x0000000101907e10, _cmd="viewDidLoad") at ViewController.m:27:5
frame #4: 0x00000001b6b61c8c UIKitCore`-[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 84
frame #5: 0x00000001b6916854 UIKitCore`-[UIViewController loadViewIfRequired] + 936
frame #6: 0x00000001b6915048 UIKitCore`-[UIViewController view] + 24
frame #7: 0x00000001b6988084 UIKitCore`-[UIWindow addRootViewControllerViewIfPossible] + 136
frame #8: 0x00000001b6987f78 UIKitCore`-[UIWindow _updateLayerOrderingAndSetLayerHidden:actionBlock:] + 216
frame #9: 0x00000001b6987c78 UIKitCore`-[UIWindow _setHidden:forced:] + 256
frame #10: 0x00000001b6987b04 UIKitCore`-[UIWindow _mainQueue_makeKeyAndVisible] + 40
frame #11: 0x00000001b6becd5c UIKitCore`-[UIWindowScene _performDeferredInitialWindowUpdateForConnection] + 208
frame #12: 0x00000001b6a93e14 UIKitCore`+[UIScene _sceneForFBSScene:create:withSession:connectionOptions:] + 1232
frame #13: 0x00000001b6b50e8c UIKitCore`-[UIApplication _connectUISceneFromFBSScene:transitionContext:] + 808
frame #14: 0x00000001b6b509b4 UIKitCore`-[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 360
frame #15: 0x00000001b6b507e0 UIKitCore`-[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 288
frame #16: 0x00000001ccb696d4 FrontBoardServices`-[FBSScene _callOutQueue_didCreateWithTransitionContext:completion:] + 324
frame #17: 0x00000001ccb69570 FrontBoardServices`__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke.108 + 280
frame #18: 0x00000001ccb6819c FrontBoardServices`-[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 168
frame #19: 0x00000001ccb73f8c FrontBoardServices`__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke + 352
frame #20: 0x000000010174eb34 libdispatch.dylib`_dispatch_client_callout + 20
frame #21: 0x0000000101752530 libdispatch.dylib`_dispatch_block_invoke_direct + 300
frame #22: 0x00000001ccb64520 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 52
frame #23: 0x00000001ccb644a0 FrontBoardServices`-[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 240
frame #24: 0x00000001ccb64378 FrontBoardServices`-[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 28
frame #25: 0x00000001b470d12c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
frame #26: 0x00000001b470c3a8 CoreFoundation`__CFRunLoopDoSource0 + 176
frame #27: 0x00000001b470abbc CoreFoundation`__CFRunLoopDoSources0 + 340
frame #28: 0x00000001b4709898 CoreFoundation`__CFRunLoopRun + 828
frame #29: 0x00000001b4709478 CoreFoundation`CFRunLoopRunSpecific + 608
frame #30: 0x00000001f7c624f8 GraphicsServices`GSEventRunModal + 164
frame #31: 0x00000001b6b2d62c UIKitCore`-[UIApplication _run] + 888
frame #32: 0x00000001b6b2cc68 UIKitCore`UIApplicationMain + 340
frame #33: 0x00000001009b85d4 WeTest`main(argc=1, argv=0x000000016f44b7d8) at main.m:17:12
frame #34: 0x00000001d742edcc dyld`start + 2240
NSLock
对于NSLock 类型对象 lock:
- 对应的
pthread_mutex_t
的地址为&lock + 0x8
- 对应的tid地址为
&lock + 0x20
,
案例分析
堆栈
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
* frame #0: 0x00000001e8471ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8
frame #1: 0x000000020ad23d68 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
frame #2: 0x000000020ad237f0 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
frame #3: 0x00000001007312e0 QQKSong`-[HippyExtAnimationModule animationDidStop:finished:](self=0x000000028168bb40, _cmd=<unavailable>, anim=<unavailable>, flag=<unavailable>) at HippyExtAnimationModule.m:308:5 [opt]
frame #4: 0x00000001a238b67c QuartzCore`-[CALayer addAnimation:forKey:] + 512
frame #5: 0x0000000100732098 QQKSong`__50-[HippyExtAnimationModule connectAnimationToView:]_block_invoke_2(.block_descriptor=<unavailable>, ani=<unavailable>, idx=<unavailable>, stop=<unavailable>) at HippyExtAnimationModule.m:419:9 [opt]
frame #6: 0x00000001a0d733f4 CoreFoundation`__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ + 24
frame #7: 0x00000001a0d73120 CoreFoundation`-[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 320
frame #8: 0x0000000100731e5c QQKSong`-[HippyExtAnimationModule connectAnimationToView:](self=0x000000028168bb40, _cmd=<unavailable>, view=<unavailable>) at HippyExtAnimationModule.m:417:5 [opt]
frame #9: 0x0000000100730638 QQKSong`__47-[HippyExtAnimationModule paramForAnimationId:]_block_invoke_3(.block_descriptor=<unavailable>, tag=<unavailable>, idx=<unavailable>, stop=<unavailable>) at HippyExtAnimationModule.m:228:17 [opt]
frame #10: 0x00000001a0d733f4 CoreFoundation`__NSARRAY_IS_CALLING_OUT_TO_A_BLOCK__ + 24
frame #11: 0x00000001a0d73120 CoreFoundation`-[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 320
frame #12: 0x0000000100730510 QQKSong`__47-[HippyExtAnimationModule paramForAnimationId:]_block_invoke_2(.block_descriptor=0x0000000282332990) at HippyExtAnimationModule.m:221:9 [opt]
frame #13: 0x00000001a8d2f6a8 libdispatch.dylib`_dispatch_call_block_and_release + 32
frame #14: 0x00000001a8d31300 libdispatch.dylib`_dispatch_client_callout + 20
frame #15: 0x00000001a8d3f998 libdispatch.dylib`_dispatch_main_queue_drain + 984
frame #16: 0x00000001a8d3f5b0 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 44
frame #17: 0x00000001a0d7501c CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
frame #18: 0x00000001a0d71d28 CoreFoundation`__CFRunLoopRun + 1996
frame #19: 0x00000001a0d71478 CoreFoundation`CFRunLoopRunSpecific + 608
frame #20: 0x00000001e42ca4f8 GraphicsServices`GSEventRunModal + 164
frame #21: 0x00000001a319562c UIKitCore`-[UIApplication _run] + 888
frame #22: 0x00000001a3194c68 UIKitCore`UIApplicationMain + 340
frame #23: 0x0000000102a8ebb4 QQKSong`UIApplicationMain_wsl(argc=1, argv=0x000000016f8e7788, principalClassName="KSApplication", delegateClassName="KSAppDelegate") at WSGlobalTaskMgr.mm:881:12
frame #24: 0x000000010053a958 QQKSong`main(argc=1, argv=0x000000016f8e7788) at main.m:40:16
frame #25: 0x00000001c3a96dcc dyld`start + 2240
获取 owner_tid
(lldb) p/x *((int*)($x19 + 0x18))
(int) 0x000c342d
获取线程列表,拥有锁的线程ID为0x000c342d
为当前线程,应为同一个线程多次lock 一个非递归锁
(lldb) thread list
Process 1790 stopped
* thread #1: tid = 0xc342d, 0x00000001e8471ca8 libsystem_kernel.dylib`__psynch_mutexwait + 8, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
thread #2: tid = 0xc362b, 0x00000001e847ef38 libsystem_kernel.dylib`kevent64 + 8, name = 'im_logic_thread'
thread #5: tid = 0xc3630, 0x00000001e8471b1c libsystem_kernel.dylib`__psynch_cvwait + 8
thread #6: tid = 0xc3631, 0x00000001e8471b1c libsystem_kernel.dylib`__psynch_cvwait + 8
thread #7: tid = 0xc3632, 0x00000001e8471b1c libsystem_kernel.dylib`__psynch_cvwait + 8
.....
查看代码
@implementation HippyExtAnimationModule {
NSMutableDictionary<NSNumber *, HippyExtAnimation *> *_animationById;
NSMutableDictionary<NSNumber *, NSMutableArray<HippyExtAnimationViewParams *> *> *_paramsByAnimationId;
NSMutableDictionary<NSNumber *, HippyExtAnimationViewParams *> *_paramsByHippyTag;
NSLock *_lock;
HippyExtAnimationIdCount *_virtualAnimations;
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
[_lock lock];
NSNumber *animationId = [anim valueForKey:@"animationID"];
NSNumber *viewId = [anim valueForKey:@"viewID"];
NSMutableArray<HippyExtAnimationViewParams *> *params = [_paramsByAnimationId[animationId] copy];
[self.bridge.uiManager executeBlockOnUIManagerQueue:^{
[params enumerateObjectsUsingBlock:^(HippyExtAnimationViewParams *p, __unused NSUInteger idx, __unused BOOL *stop) {
[p.animationIdWithPropDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *obj, __unused BOOL *stop1) {
HippyExtAnimation *ani = self->_animationById[obj];
if (![obj isEqual:animationId]) {
return;
}
[p setValue:@(ani.endValue) forProp:key];
ani.state = HippyExtAnimationFinishState;
HippyLogInfo(@"[Hippy_OC_Log][Animation],Animation_Did_Stop:%@ finish:%@ prop:%@ value:%@", animationId, @(flag), key, @(ani.endValue));
}];
}];
}];
[_lock unlock];
//其它代码
}
根据NSLock锁验证前面的线程ID获取正确
(lldb) p/x *((int*)((char*)self->_lock + 0x20))
(int) 0x000c342d
递归原因:
- connectAnimationToView里面加锁
- 在animationDidStop里面尝试再次加锁
- (void)connectAnimationToView:(UIView *)view {
[_lock lock];
NSNumber *hippyTag = view.hippyTag;
HippyExtAnimationViewParams *p = _paramsByHippyTag[hippyTag];
NSMutableArray<CAAnimation *> *animations = [NSMutableArray new];
[p.animationIdWithPropDictionary enumerateKeysAndObjectsUsingBlock:^(NSString *prop, NSNumber *animationId, __unused BOOL *stop) {
HippyExtAnimation *animation = self->_animationById[animationId];
if (animation.state != HippyExtAnimationReadyState) {
return;
}
CAAnimation *ani = [animation animationOfView:view forProp:prop];
animation.state = HippyExtAnimationStartedState;
[ani setValue:animationId forKey:@"animationID"];
if (animation.parentAnimationId) {
[ani setValue:animation.parentAnimationId forKey:@"animationParentID"];
}
[ani setValue:view.hippyTag forKey:@"viewID"];
ani.delegate = self;
[animations addObject:ani];
HippyLogInfo(@"[Hippy_OC_Log][Animation],Connect_Animation:[%@] to view [%@] prop [%@] from [%@] to [%@]", animationId, view.hippyTag, prop, @(animation.startValue),
@(animation.endValue));
}];
[animations enumerateObjectsUsingBlock:^(CAAnimation *_Nonnull ani, __unused NSUInteger idx, __unused BOOL *stop) {
NSNumber *animationId = [ani valueForKey:@"animationID"];
[view.layer addAnimation:ani forKey:[NSString stringWithFormat:@"%@", animationId]];
}];
[_lock unlock];
}
各函数所在模块
如下堆栈可知
-
__psynch_mutexwait
:
模块: libsystem_kernel
源码: https://github.com/apple/darwin-libpthread/blob/main/kern/kern_synch.c -
_pthread_mutex_firstfit_lock_wait
:
模块: libsystem_pthread
源码: https://github.com/apple/darwin-libpthread/blob/main/src/pthread_mutex.c -
_pthread_mutex_firstfit_lock_slow
: libsystem_pthread
* frame #0: 0x00000001d358dca0 libsystem_kernel.dylib`__psynch_mutexwait
frame #1: 0x00000001f5e3fd68 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84
frame #2: 0x00000001f5e3f7f0 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 248
frame #3: 0x000000019c089d20 libc++.1.dylib`std::__1::mutex::lock() + 16
frame #4: 0x00000001121606bc ImSDK_Plus`___lldb_unnamed_symbol1953 + 117764
frame #5: 0x0000000112160ec8 ImSDK_Plus`___lldb_unnamed_symbol1953 + 119824
frame #6: 0x00000001f5e404d4 libsystem_pthread.dylib`_pthread_start + 136
相关模块的源码链接
- libsystem_kernel:
- libsystem_pthread: https://github.com/apple/darwin-libpthread
参考文献
- 如何知道一个锁到底被哪个线程占用?
- ARMv8-aarch64 寄存器和指令集
- libsystem_pthread源码: darwin-libpthread
源码
_pthread_mutex_firstfit_lock_wait
static int
_pthread_mutex_firstfit_lock_wait(pthread_mutex_t *mutex, mutex_seq newseq,
uint64_t oldtid)
{
uint64_t *tidaddr;
MUTEX_GETTID_ADDR(mutex, &tidaddr);
uint64_t selfid = _pthread_threadid_self_np_direct();
PLOCKSTAT_MUTEX_BLOCK((pthread_mutex_t *)mutex);
do {
uint32_t uval;
do {
PTHREAD_TRACE(psynch_ffmutex_wait | DBG_FUNC_START, mutex,
newseq.lgenval, newseq.ugenval, mutex->mtxopts.value);
uval = __psynch_mutexwait(mutex, newseq.lgenval, newseq.ugenval,
oldtid, mutex->mtxopts.value);
PTHREAD_TRACE(psynch_ffmutex_wait | DBG_FUNC_END, mutex,
uval, 0, 0);
oldtid = os_atomic_load_wide(tidaddr, relaxed);
} while (uval == (uint32_t)-1);
} while (!_pthread_mutex_firstfit_lock_updatebits(mutex, selfid, &newseq));
PLOCKSTAT_MUTEX_BLOCKED((pthread_mutex_t *)mutex, BLOCK_SUCCESS_PLOCKSTAT);
return 0;
}
对应汇编如下
第一个参数为pthread_mutex_t,对应的寄存器为x0,在此过程中,把x0保存到寄存器x19,而在后续过程中没有使用它,所以在x19中保存着pthread_mutex_t对象的指针
寄存器X19
至X29
是被调用者保存寄存器,也称为Callee-saved
寄存器。如果在函数中使用这些寄存器,你必须在函数入口处将它们推入栈中(保存它们的状态),并在函数退出之前从栈中恢复它们。
libsystem_pthread.dylib`:
0x1f5e3fd14 <+0>: pacibsp
0x1f5e3fd18 <+4>: stp x24, x23, [sp, #-0x40]!
0x1f5e3fd1c <+8>: stp x22, x21, [sp, #0x10]
0x1f5e3fd20 <+12>: stp x20, x19, [sp, #0x20]
0x1f5e3fd24 <+16>: stp x29, x30, [sp, #0x30]
0x1f5e3fd28 <+20>: add x29, sp, #0x30
0x1f5e3fd2c <+24>: mov x3, x2
0x1f5e3fd30 <+28>: mov x19, x0
0x1f5e3fd34 <+32>: add x8, x0, #0x1f
0x1f5e3fd38 <+36>: and x22, x8, #0xfffffffffffffff8
0x1f5e3fd3c <+40>: mrs x8, TPIDRRO_EL0
0x1f5e3fd40 <+44>: ldur x23, [x8, #-0x8]
0x1f5e3fd44 <+48>: add x8, x0, #0x27
0x1f5e3fd48 <+52>: and x24, x8, #0xfffffffffffffff8
0x1f5e3fd4c <+56>: mov x20, x1
0x1f5e3fd50 <+60>: lsr x21, x1, #32
0x1f5e3fd54 <+64>: ldr w4, [x19, #0xc]
0x1f5e3fd58 <+68>: mov x0, x19
0x1f5e3fd5c <+72>: mov x1, x20
0x1f5e3fd60 <+76>: mov x2, x21
0x1f5e3fd64 <+80>: bl 0x1f67e95b0
-> 0x1f5e3fd68 <+84>: ldr x3, [x22]
0x1f5e3fd6c <+88>: cmn w0, #0x1
0x1f5e3fd70 <+92>: b.eq 0x1f5e3fd54 ; <+64>
0x1f5e3fd74 <+96>: ldr x8, [x24]
0x1f5e3fd78 <+100>: mov x1, x8
0x1f5e3fd7c <+104>: add w9, w1, #0x100
0x1f5e3fd80 <+108>: orr w10, w1, #0x2
0x1f5e3fd84 <+112>: tst x8, #0x2
0x1f5e3fd88 <+116>: csel x9, x10, x9, eq
0x1f5e3fd8c <+120>: mov x20, x8
0x1f5e3fd90 <+124>: bfxil x20, x9, #0, #32
0x1f5e3fd94 <+128>: casa x8, x20, [x24]
0x1f5e3fd98 <+132>: cmp x8, x1
0x1f5e3fd9c <+136>: b.ne 0x1f5e3fd78 ; <+100>
0x1f5e3fda0 <+140>: tbnz w1, #0x1, 0x1f5e3fd50 ; <+60>
0x1f5e3fda4 <+144>: str x23, [x22]
0x1f5e3fda8 <+148>: ldp x29, x30, [sp, #0x30]
0x1f5e3fdac <+152>: ldp x20, x19, [sp, #0x20]
0x1f5e3fdb0 <+156>: ldp x22, x21, [sp, #0x10]
0x1f5e3fdb4 <+160>: ldp x24, x23, [sp], #0x40
0x1f5e3fdb8 <+164>: retab
__psynch_mutexwait 汇编
libsystem_kernel.dylib`:
-> 0x1d358dca0 <+0>: mov x16, #0x12d
0x1d358dca4 <+4>: svc #0x80
0x1d358dca8 <+8>: b.lo 0x1d358dcc8 ; <+40>
0x1d358dcac <+12>: pacibsp
0x1d358dcb0 <+16>: stp x29, x30, [sp, #-0x10]!
0x1d358dcb4 <+20>: mov x29, sp
0x1d358dcb8 <+24>: bl 0x1d358d76c ; cerror_nocancel
0x1d358dcbc <+28>: mov sp, x29
0x1d358dcc0 <+32>: ldp x29, x30, [sp], #0x10
0x1d358dcc4 <+36>: retab
0x1d358dcc8 <+40>: ret
(lldb) p/x $x19
(unsigned long) 0x000000028153f700
(lldb) p/x $x0
(unsigned long) 0x000000028153f700
互斥锁对应的结构为pthread_mutex_t,如下
typedef struct _pthread_mutex
{
long sig; /* Unique signature for this structure */
pthread_lock_t lock; /* Used for internal mutex on structure */
union {
uint32_t value;
struct _pthread_mutex_options options;
} mtxopts;
int16_t prioceiling;
int16_t priority; /* Priority to restore when mutex unlocked */
uint32_t waiters; /* Count of threads waiting for this mutex */
pthread_t owner; /* Which thread has this mutex locked */
struct _pthread_mutex *next, *prev; /* List of other mutexes he owns */
struct _pthread_cond *busy; /* List of condition variables using this mutex */
semaphore_t sem; /* Semaphore used for waiting */
semaphore_t order;
} pthread_mutex_t;