Don't use os_unfair_lock on 32-bit platforms

This commit is contained in:
Ali 2022-07-08 19:54:18 +02:00
parent 76ab659aa2
commit 93664ad233
3 changed files with 104 additions and 5 deletions

View File

@ -31,7 +31,8 @@ void ASRecursiveUnfairLockLock(ASRecursiveUnfairLock *l)
// because only we are `self`. And if it's already `self` then we already have
// the lock, because we reset it to NULL before we unlock. So (thread == self) is
// invariant.
#if AS_USE_OS_LOCK
const pthread_t s = pthread_self();
if (os_unfair_lock_trylock(&l->_lock)) {
// Owned by nobody. We now have the lock. Assign self.
@ -43,14 +44,28 @@ void ASRecursiveUnfairLockLock(ASRecursiveUnfairLock *l)
os_unfair_lock_lock(&l->_lock);
rul_set_thread(l, s);
}
#else
const pthread_t s = pthread_self();
if (OSSpinLockTry(&l->_lock)) {
// Owned by nobody. We now have the lock. Assign self.
rul_set_thread(l, s);
} else if (rul_get_thread(l) == s) {
// Owned by self (recursive lock). nop.
} else {
// Owned by other thread. Block and then set thread to self.
OSSpinLockLock(&l->_lock);
rul_set_thread(l, s);
}
#endif
l->_count++;
}
BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l)
{
// Same as Lock above. See comments there.
// Same as Lock above. See comments there.
#if AS_USE_OS_LOCK
const pthread_t s = pthread_self();
if (os_unfair_lock_trylock(&l->_lock)) {
// Owned by nobody. We now have the lock. Assign self.
@ -61,6 +76,18 @@ BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l)
// Owned by other thread. Fail.
return NO;
}
#else
const pthread_t s = pthread_self();
if (OSSpinLockTry(&l->_lock)) {
// Owned by nobody. We now have the lock. Assign self.
rul_set_thread(l, s);
} else if (rul_get_thread(l) == s) {
// Owned by self (recursive lock). nop.
} else {
// Owned by other thread. Fail.
return NO;
}
#endif
l->_count++;
return YES;
@ -78,6 +105,10 @@ void ASRecursiveUnfairLockUnlock(ASRecursiveUnfairLock *l)
// try to re-lock, and fail the -tryLock, and read _thread, then we'll mistakenly
// think that we still own the lock and proceed without blocking.
rul_set_thread(l, NULL);
#if AS_USE_OS_LOCK
os_unfair_lock_unlock(&l->_lock);
#else
OSSpinLockUnlock(&l->_lock);
#endif
}
}

View File

@ -10,6 +10,15 @@
#import <UIKit/UIKit.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <pthread/pthread.h>
#if defined(__aarch64__)
#define AS_USE_OS_LOCK true
#else
#define AS_USE_OS_LOCK false
#endif
#if AS_USE_OS_LOCK
#import <os/lock.h>
// Note: We don't use ATOMIC_VAR_INIT here because C++ compilers don't like it,
@ -46,3 +55,43 @@ AS_EXTERN OS_UNFAIR_LOCK_AVAILABILITY
void ASRecursiveUnfairLockUnlock(ASRecursiveUnfairLock *l);
NS_ASSUME_NONNULL_END
#else
#import <libkern/OSAtomic.h>
// Note: We don't use ATOMIC_VAR_INIT here because C++ compilers don't like it,
// and it literally does absolutely nothing.
#define AS_RECURSIVE_UNFAIR_LOCK_INIT ((ASRecursiveUnfairLock){ OS_SPINLOCK_INIT, NULL, 0})
NS_ASSUME_NONNULL_BEGIN
typedef struct {
OSSpinLock _lock;
_Atomic(pthread_t) _thread; // Write-protected by lock
int _count; // Protected by lock
} ASRecursiveUnfairLock;
/**
* Lock, blocking if needed.
*/
AS_EXTERN
void ASRecursiveUnfairLockLock(ASRecursiveUnfairLock *l);
/**
* Try to lock without blocking. Returns whether we took the lock.
*/
AS_EXTERN
BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l);
/**
* Unlock. Calling this on a thread that does not own
* the lock will result in an assertion failure, and undefined
* behavior if foundation assertions are disabled.
*/
AS_EXTERN
void ASRecursiveUnfairLockUnlock(ASRecursiveUnfairLock *l);
NS_ASSUME_NONNULL_END
#endif

View File

@ -9,7 +9,6 @@
#import <Foundation/Foundation.h>
#import <os/lock.h>
#import <pthread.h>
#import <AsyncDisplayKit/ASAssert.h>
@ -148,7 +147,11 @@ namespace AS {
success = _recursive.try_lock();
break;
case Unfair:
#if AS_USE_OS_LOCK
success = os_unfair_lock_trylock(&_unfair);
#else
success = OSSpinLockTry(&_unfair);
#endif
break;
case RecursiveUnfair:
success = ASRecursiveUnfairLockTryLock(&_runfair);
@ -169,7 +172,11 @@ namespace AS {
_recursive.lock();
break;
case Unfair:
#if AS_USE_OS_LOCK
os_unfair_lock_lock(&_unfair);
#else
OSSpinLockLock(&_unfair);
#endif
break;
case RecursiveUnfair:
ASRecursiveUnfairLockLock(&_runfair);
@ -188,7 +195,11 @@ namespace AS {
_recursive.unlock();
break;
case Unfair:
#if AS_USE_OS_LOCK
os_unfair_lock_unlock(&_unfair);
#else
OSSpinLockUnlock(&_unfair);
#endif
break;
case RecursiveUnfair:
ASRecursiveUnfairLockUnlock(&_runfair);
@ -226,7 +237,11 @@ namespace AS {
} else {
if (gMutex_unfair) {
_type = Unfair;
#if AS_USE_OS_LOCK
_unfair = OS_UNFAIR_LOCK_INIT;
#else
_unfair = OS_SPINLOCK_INIT;
#endif
} else {
_type = Plain;
new (&_plain) std::mutex();
@ -261,7 +276,11 @@ namespace AS {
Type _type;
union {
os_unfair_lock _unfair;
#if AS_USE_OS_LOCK
os_unfair_lock _unfair;
#else
OSSpinLock _unfair;
#endif
ASRecursiveUnfairLock _runfair;
std::mutex _plain;
std::recursive_mutex _recursive;