thread: Locking mutexes and rwlocks are now void functions.

Almost nothing checks these return values, and there's no reason a valid
lock should fail to operate. The cases where a lock isn't valid (it's a
bogus pointer, it was previously destroyed, a thread is unlocking a lock it
doesn't own, etc) are undefined behavior and always were, and should be
treated as an application bug.

Reference Issue #8096.
This commit is contained in:
Ryan C. Gordon
2023-10-25 10:00:26 -04:00
parent 082ef41566
commit 899eb0d042
21 changed files with 496 additions and 746 deletions

View File

@@ -30,7 +30,7 @@ SDL_Mutex *SDL_CreateMutex(void)
SDL_Mutex *mutex;
pthread_mutexattr_t attr;
/* Allocate the structure */
// Allocate the structure
mutex = (SDL_Mutex *)SDL_calloc(1, sizeof(*mutex));
if (mutex) {
pthread_mutexattr_init(&attr);
@@ -39,7 +39,7 @@ SDL_Mutex *SDL_CreateMutex(void)
#elif defined(SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP)
pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#else
/* No extra attributes necessary */
// No extra attributes necessary
#endif
if (pthread_mutex_init(&mutex->id, &attr) != 0) {
SDL_SetError("pthread_mutex_init() failed");
@@ -60,116 +60,96 @@ void SDL_DestroyMutex(SDL_Mutex *mutex)
}
}
/* Lock the mutex */
int SDL_LockMutex(SDL_Mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
void SDL_LockMutex(SDL_Mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (mutex != NULL) {
#ifdef FAKE_RECURSIVE_MUTEX
pthread_t this_thread;
#endif
if (mutex == NULL) {
return 0;
}
#ifdef FAKE_RECURSIVE_MUTEX
this_thread = pthread_self();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
/* The order of operations is important.
We set the locking thread id after we obtain the lock
so unlocks from other threads will fail.
*/
if (pthread_mutex_lock(&mutex->id) == 0) {
pthread_t this_thread = pthread_self();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
/* The order of operations is important.
We set the locking thread id after we obtain the lock
so unlocks from other threads will fail.
*/
const int rc = pthread_mutex_lock(&mutex->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
mutex->owner = this_thread;
mutex->recursive = 0;
} else {
return SDL_SetError("pthread_mutex_lock() failed");
}
}
#else
if (pthread_mutex_lock(&mutex->id) != 0) {
return SDL_SetError("pthread_mutex_lock() failed");
}
const int rc = pthread_mutex_lock(&mutex->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
#endif
return 0;
}
}
int SDL_TryLockMutex(SDL_Mutex *mutex)
{
int retval;
int result;
#ifdef FAKE_RECURSIVE_MUTEX
pthread_t this_thread;
#endif
int retval = 0;
if (mutex == NULL) {
return 0;
}
retval = 0;
if (mutex != NULL) {
#ifdef FAKE_RECURSIVE_MUTEX
this_thread = pthread_self();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
/* The order of operations is important.
We set the locking thread id after we obtain the lock
so unlocks from other threads will fail.
*/
result = pthread_mutex_trylock(&mutex->id);
if (result == 0) {
mutex->owner = this_thread;
mutex->recursive = 0;
} else if (result == EBUSY) {
retval = SDL_MUTEX_TIMEDOUT;
pthread_t this_thread = pthread_self();
if (mutex->owner == this_thread) {
++mutex->recursive;
} else {
retval = SDL_SetError("pthread_mutex_trylock() failed");
/* The order of operations is important.
We set the locking thread id after we obtain the lock
so unlocks from other threads will fail.
*/
const int result = pthread_mutex_trylock(&mutex->id);
if (result == 0) {
mutex->owner = this_thread;
mutex->recursive = 0;
} else if (result == EBUSY) {
retval = SDL_MUTEX_TIMEDOUT;
} else {
SDL_assert(!"Error trying to lock mutex"); // assume we're in a lot of trouble if this assert fails.
retval = SDL_MUTEX_TIMEDOUT;
}
}
}
#else
result = pthread_mutex_trylock(&mutex->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_MUTEX_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_mutex_trylock() failed");
const int result = pthread_mutex_trylock(&mutex->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_MUTEX_TIMEDOUT;
} else {
SDL_assert(!"Error trying to lock mutex"); // assume we're in a lot of trouble if this assert fails.
retval = SDL_MUTEX_TIMEDOUT;
}
}
}
#endif
}
return retval;
}
int SDL_UnlockMutex(SDL_Mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
void SDL_UnlockMutex(SDL_Mutex *mutex) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (mutex == NULL) {
return 0;
}
if (mutex != NULL) {
#ifdef FAKE_RECURSIVE_MUTEX
/* We can only unlock the mutex if we own it */
if (pthread_self() == mutex->owner) {
if (mutex->recursive) {
--mutex->recursive;
// We can only unlock the mutex if we own it
if (pthread_self() == mutex->owner) {
if (mutex->recursive) {
--mutex->recursive;
} else {
/* The order of operations is important.
First reset the owner so another thread doesn't lock
the mutex and set the ownership before we reset it,
then release the lock semaphore.
*/
mutex->owner = 0;
pthread_mutex_unlock(&mutex->id);
}
} else {
/* The order of operations is important.
First reset the owner so another thread doesn't lock
the mutex and set the ownership before we reset it,
then release the lock semaphore.
*/
mutex->owner = 0;
pthread_mutex_unlock(&mutex->id);
return SDL_SetError("mutex not owned by this thread");
}
} else {
return SDL_SetError("mutex not owned by this thread");
}
#else
if (pthread_mutex_unlock(&mutex->id) != 0) {
return SDL_SetError("pthread_mutex_unlock() failed");
const int rc = pthread_mutex_unlock(&mutex->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
#endif // FAKE_RECURSIVE_MUTEX
}
#endif /* FAKE_RECURSIVE_MUTEX */
return 0;
}

View File

@@ -55,42 +55,36 @@ void SDL_DestroyRWLock(SDL_RWLock *rwlock)
}
}
int SDL_LockRWLockForReading(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
void SDL_LockRWLockForReading(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (pthread_rwlock_rdlock(&rwlock->id) != 0) {
return SDL_SetError("pthread_rwlock_rdlock() failed");
if (rwlock) {
const int rc = pthread_rwlock_rdlock(&rwlock->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
}
return 0;
}
int SDL_LockRWLockForWriting(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
void SDL_LockRWLockForWriting(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (pthread_rwlock_wrlock(&rwlock->id) != 0) {
return SDL_SetError("pthread_rwlock_wrlock() failed");
if (rwlock) {
const int rc = pthread_rwlock_wrlock(&rwlock->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
}
return 0;
}
int SDL_TryLockRWLockForReading(SDL_RWLock *rwlock)
{
int retval = 0;
if (rwlock == NULL) {
retval = SDL_InvalidParamError("rwlock");
} else {
if (rwlock) {
const int result = pthread_rwlock_tryrdlock(&rwlock->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_RWLOCK_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_rwlock_tryrdlock() failed");
retval = SDL_RWLOCK_TIMEDOUT;
if (result != EBUSY) {
SDL_assert(!"Error trying to lock rwlock for reading"); // assume we're in a lot of trouble if this assert fails.
}
}
}
return retval;
}
@@ -98,15 +92,12 @@ int SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock)
{
int retval = 0;
if (rwlock == NULL) {
retval = SDL_InvalidParamError("rwlock");
} else {
if (rwlock) {
const int result = pthread_rwlock_trywrlock(&rwlock->id);
if (result != 0) {
if (result == EBUSY) {
retval = SDL_RWLOCK_TIMEDOUT;
} else {
retval = SDL_SetError("pthread_rwlock_tryrdlock() failed");
retval = SDL_RWLOCK_TIMEDOUT;
if (result != EBUSY) {
SDL_assert(!"Error trying to lock rwlock for writing"); // assume we're in a lot of trouble if this assert fails.
}
}
}
@@ -114,13 +105,11 @@ int SDL_TryLockRWLockForWriting(SDL_RWLock *rwlock)
return retval;
}
int SDL_UnlockRWLock(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS /* clang doesn't know about NULL mutexes */
void SDL_UnlockRWLock(SDL_RWLock *rwlock) SDL_NO_THREAD_SAFETY_ANALYSIS // clang doesn't know about NULL mutexes
{
if (rwlock == NULL) {
return SDL_InvalidParamError("rwlock");
} else if (pthread_rwlock_unlock(&rwlock->id) != 0) {
return SDL_SetError("pthread_rwlock_unlock() failed");
if (rwlock) {
const int rc = pthread_rwlock_unlock(&rwlock->id);
SDL_assert(rc == 0); // assume we're in a lot of trouble if this assert fails.
}
return 0;
}