Skip to content

Commit c206579

Browse files
committed
Initialize robust_list head for pthread_t structure. Fixes a crash with locking recursive mutexes, #5038. Clean up unused mutex control field for old Emscripten specific mutex implementation (removed from use since d86e9b3)
1 parent 4e85fbf commit c206579

File tree

7 files changed

+10
-135
lines changed

7 files changed

+10
-135
lines changed

src/library_pthread.js

+4
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,10 @@ var LibraryPThread = {
579579
// structure is 'alive'.
580580
{{{ makeSetValue('threadInfoStruct', C_STRUCTS.pthread.self, 'threadInfoStruct', 'i32') }}};
581581

582+
// pthread struct robust_list head should point to itself.
583+
var headPtr = threadInfoStruct + {{{ C_STRUCTS.pthread.robust_list }}};
584+
{{{ makeSetValue('headPtr', 0, 'headPtr', 'i32') }}};
585+
582586
var threadParams = {
583587
stackBase: stackBase,
584588
stackSize: stackSize,

src/struct_info.compiled.json

+1-1
Large diffs are not rendered by default.

src/struct_info.json

+1
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,7 @@
14841484
"stack",
14851485
"stack_size",
14861486
"attr",
1487+
"robust_list",
14871488
"tid",
14881489
"pid",
14891490
"canceldisable",

system/lib/libc/musl/arch/emscripten/bits/alltypes.h

-6
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,7 @@ typedef struct { union { int __i[10]; volatile int __vi[10]; unsigned __s[10]; }
9494
#endif
9595

9696
#if defined(__NEED_pthread_mutex_t) && !defined(__DEFINED_pthread_mutex_t)
97-
#ifdef __EMSCRIPTEN__
98-
// For mutex implementation in Emscripten, need to use an extra eighth control field
99-
// to hold a temporary futex wait & wake location, designated as mutex->_m_addr.
100-
typedef struct { union { int __i[8]; volatile int __vi[8]; volatile void *__p[8]; } __u; } pthread_mutex_t;
101-
#else
10297
typedef struct { union { int __i[7]; volatile int __vi[7]; volatile void *__p[7]; } __u; } pthread_mutex_t;
103-
#endif
10498
typedef pthread_mutex_t mtx_t;
10599
#define __DEFINED_pthread_mutex_t
106100
#endif

system/lib/libc/musl/src/internal/pthread_impl.h

-3
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,6 @@ struct __timer {
8484
#define _m_prev __u.__p[3]
8585
#define _m_next __u.__p[4]
8686
#define _m_count __u.__i[5]
87-
#ifdef __EMSCRIPTEN__
88-
#define _m_addr __u.__i[7]
89-
#endif
9087
#define _c_shared __u.__p[0]
9188
#define _c_seq __u.__vi[2]
9289
#define _c_waiters __u.__vi[3]

system/lib/pthread/library_pthread.c

-124
Original file line numberDiff line numberDiff line change
@@ -70,130 +70,6 @@ double _pthread_msecs_until(const struct timespec *restrict at)
7070
return msecs;
7171
}
7272

73-
#if 0
74-
int pthread_mutex_lock(pthread_mutex_t *mutex)
75-
{
76-
if (!mutex) return EINVAL;
77-
assert(pthread_self() != 0);
78-
assert(pthread_self()->tid != 0);
79-
80-
if (mutex->_m_lock == pthread_self()->tid) {
81-
if ((mutex->_m_type&3) == PTHREAD_MUTEX_RECURSIVE) {
82-
if ((unsigned)mutex->_m_count >= INT_MAX) return EAGAIN;
83-
++mutex->_m_count;
84-
return 0;
85-
} else if ((mutex->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK) {
86-
return EDEADLK;
87-
}
88-
}
89-
90-
int threadCancelType = _pthread_getcanceltype();
91-
92-
int c = emscripten_atomic_cas_u32(&mutex->_m_addr, 0, 1);
93-
if (c != 0) {
94-
do {
95-
if (c == 2 || emscripten_atomic_cas_u32(&mutex->_m_addr, 1, 2) != 0) {
96-
double msecs = INFINITY;
97-
if (threadCancelType == PTHREAD_CANCEL_ASYNCHRONOUS) {
98-
// Sleep in small slices so that we can test cancellation to honor PTHREAD_CANCEL_ASYNCHRONOUS.
99-
__pthread_testcancel();
100-
msecs = 100;
101-
}
102-
emscripten_futex_wait(&mutex->_m_addr, 2, msecs);
103-
}
104-
} while((c = emscripten_atomic_cas_u32(&mutex->_m_addr, 0, 2)));
105-
}
106-
107-
__pthread_mutex_locked(mutex);
108-
return 0;
109-
}
110-
111-
int pthread_mutex_unlock(pthread_mutex_t *mutex)
112-
{
113-
if (!mutex) return EINVAL;
114-
assert(pthread_self() != 0);
115-
116-
if (mutex->_m_type != PTHREAD_MUTEX_NORMAL) {
117-
if (mutex->_m_lock != pthread_self()->tid) return EPERM;
118-
if ((mutex->_m_type&3) == PTHREAD_MUTEX_RECURSIVE && mutex->_m_count) {
119-
--mutex->_m_count;
120-
return 0;
121-
}
122-
}
123-
124-
mutex->_m_lock = 0;
125-
if (emscripten_atomic_sub_u32((uint32_t*)&mutex->_m_addr, 1) != 1)
126-
{
127-
emscripten_atomic_store_u32((uint32_t*)&mutex->_m_addr, 0);
128-
emscripten_futex_wake((uint32_t*)&mutex->_m_addr, 1);
129-
}
130-
return 0;
131-
}
132-
133-
int pthread_mutex_trylock(pthread_mutex_t *mutex)
134-
{
135-
if (!mutex) return EINVAL;
136-
if (mutex->_m_lock == pthread_self()->tid) {
137-
if ((mutex->_m_type&3) == PTHREAD_MUTEX_RECURSIVE) {
138-
if ((unsigned)mutex->_m_count >= INT_MAX) return EAGAIN;
139-
++mutex->_m_count;
140-
return 0;
141-
} else if ((mutex->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK) {
142-
return EDEADLK;
143-
}
144-
}
145-
146-
if (emscripten_atomic_cas_u32(&mutex->_m_addr, 0, 1) == 0) {
147-
__pthread_mutex_locked(mutex);
148-
return 0;
149-
}
150-
else
151-
return EBUSY;
152-
}
153-
154-
int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict at)
155-
{
156-
if (!mutex || !at) return EINVAL;
157-
if (mutex->_m_lock == pthread_self()->tid) {
158-
if ((mutex->_m_type&3) == PTHREAD_MUTEX_RECURSIVE) {
159-
if ((unsigned)mutex->_m_count >= INT_MAX) return EAGAIN;
160-
++mutex->_m_count;
161-
return 0;
162-
} else if ((mutex->_m_type&3) == PTHREAD_MUTEX_ERRORCHECK) {
163-
return EDEADLK;
164-
}
165-
}
166-
167-
int threadCancelType = _pthread_getcanceltype();
168-
int c = emscripten_atomic_cas_u32(&mutex->_m_addr, 0, 1);
169-
if (c != 0) {
170-
do {
171-
if (c == 2 || emscripten_atomic_cas_u32(&mutex->_m_addr, 1, 2) != 0)
172-
{
173-
if (at->tv_nsec < 0 || at->tv_nsec >= 1000000000) return EINVAL;
174-
double msecs = _pthread_msecs_until(at);
175-
if (msecs <= 0) return ETIMEDOUT;
176-
177-
// Sleep in small slices if thread type is PTHREAD_CANCEL_ASYNCHRONOUS
178-
// so that we can honor PTHREAD_CANCEL_ASYNCHRONOUS requests.
179-
if (threadCancelType == PTHREAD_CANCEL_ASYNCHRONOUS) {
180-
__pthread_testcancel();
181-
if (msecs > 100) msecs = 100;
182-
}
183-
int ret = emscripten_futex_wait(&mutex->_m_addr, 2, msecs);
184-
if (ret == 0) break;
185-
else if (threadCancelType != PTHREAD_CANCEL_ASYNCHRONOUS || _pthread_msecs_until(at) <= 0) {
186-
return ETIMEDOUT;
187-
}
188-
}
189-
} while((c = emscripten_atomic_cas_u32(&mutex->_m_addr, 0, 2)));
190-
}
191-
192-
__pthread_mutex_locked(mutex);
193-
return 0;
194-
}
195-
#endif
196-
19773
int sched_get_priority_max(int policy)
19874
{
19975
// Web workers do not actually support prioritizing threads,

tests/pthread/test_pthread_mutex.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ void WaitToJoin()
9090

9191
int main()
9292
{
93-
pthread_mutex_init(&lock, NULL);
93+
pthread_mutexattr_t attr;
94+
pthread_mutexattr_init(&attr);
95+
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
96+
pthread_mutex_init(&lock, &attr);
9497

9598
if (emscripten_has_threading_support()) {
9699
// Create new threads in parallel.

0 commit comments

Comments
 (0)