Skip to content

Commit 38c09e3

Browse files
authored
Fix single-threaded recursive mutex locking (#777)
I have found this tiny mistake while investigating why pthread_mutex_lock return EDEADLK for recursive mutexes in single-threaded runtimes.
1 parent 4d9cd9d commit 38c09e3

4 files changed

Lines changed: 50 additions & 2 deletions

File tree

libc-top-half/musl/src/thread/single-threaded/pthread_mutex_lock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ int __pthread_mutex_lock(pthread_mutex_t *m)
88
1 - recursive
99
2 - errorcheck
1010
*/
11-
if (m->_m_type&3 != PTHREAD_MUTEX_RECURSIVE) {
11+
if ((m->_m_type & 3) != PTHREAD_MUTEX_RECURSIVE) {
1212
if (m->_m_count) return EDEADLK;
1313
m->_m_count = 1;
1414
} else {

libc-top-half/musl/src/thread/single-threaded/pthread_mutex_trylock.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ int __pthread_mutex_trylock(pthread_mutex_t *m)
88
1 - recursive
99
2 - errorcheck
1010
*/
11-
if (m->_m_type&3 != PTHREAD_MUTEX_RECURSIVE) {
11+
if ((m->_m_type & 3) != PTHREAD_MUTEX_RECURSIVE) {
1212
if (m->_m_count) return EBUSY;
1313
m->_m_count = 1;
1414
} else {

test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ if (CMAKE_C_COMPILER_VERSION VERSION_GREATER 20.0)
341341
set_tests_properties(setjmp.wasm PROPERTIES LABELS v8fail)
342342
endif()
343343

344+
# This test works for single-threaded targets too
345+
add_wasilibc_test(pthread_recursive_mutex.c)
346+
344347
if (TARGET_TRIPLE MATCHES "-threads")
345348
add_wasilibc_test(busywait.c)
346349
add_wasilibc_test(pthread_cond_busywait.c)

test/src/pthread_recursive_mutex.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include "test.h"
2+
#include <pthread.h>
3+
#include <stdlib.h>
4+
5+
#define TEST(c, i) \
6+
do { \
7+
int ret = c; \
8+
if (ret != 0) \
9+
t_error("%s failed (i = %d, returned %d)\n", #c, i, ret); \
10+
} while (0)
11+
12+
int ITERS = 4;
13+
14+
int main(void) {
15+
pthread_mutex_t recursive_mutex;
16+
pthread_mutexattr_t attr;
17+
18+
// Create a recursive mutex
19+
pthread_mutexattr_init(&attr);
20+
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
21+
pthread_mutex_init(&recursive_mutex, &attr);
22+
pthread_mutexattr_destroy(&attr);
23+
24+
// Lock the mutex ITERS times
25+
// Deadlock can't occur since all locks are held on the same thread
26+
for (int i = 0; i < ITERS; i++) {
27+
TEST(pthread_mutex_lock(&recursive_mutex), i);
28+
}
29+
// Unlock the mutex ITERS times
30+
for (int i = 0; i < ITERS; i++) {
31+
TEST(pthread_mutex_unlock(&recursive_mutex), i);
32+
}
33+
34+
// Lock the mutex ITERS times without blocking
35+
for (int i = 0; i < ITERS; i++) {
36+
TEST(pthread_mutex_trylock(&recursive_mutex), i);
37+
}
38+
// Unlock the mutex ITERS times again
39+
for (int i = 0; i < ITERS; i++) {
40+
TEST(pthread_mutex_unlock(&recursive_mutex), i);
41+
}
42+
43+
pthread_mutex_destroy(&recursive_mutex);
44+
return t_status;
45+
}

0 commit comments

Comments
 (0)