Skip to content

Commit c092f47

Browse files
committed
Enable file locking in musl stdio
This is second attempt at landing a version of d5d5f69 The first time we tried it #13837 we ran into issues with test_pthread_exit_process deadlocking which I tracked down to an issue with `system/lib/libc/musl/src/thread/__wait.c` where it was blocking the main thread forever rather then looping and calling `emscripten_main_thread_process_queued_calls`. Includes a version of #14481 so that should land before this does. Fixes: #13194
1 parent 565fb36 commit c092f47

13 files changed

+121
-7
lines changed

src/postamble.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -440,9 +440,6 @@ function exit(status, implicit) {
440440
}
441441
#endif // ASSERTIONS
442442
} else {
443-
#if USE_PTHREADS
444-
PThread.terminateAllThreads();
445-
#endif
446443
exitRuntime();
447444
}
448445

src/preamble.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ function exitRuntime() {
414414
#if EXIT_RUNTIME
415415
callRuntimeCallbacks(__ATEXIT__);
416416
<<< ATEXITS >>>
417+
#endif
418+
#if USE_PTHREADS
419+
PThread.terminateAllThreads();
417420
#endif
418421
runtimeExited = true;
419422
}

system/lib/libc/musl/src/thread/__wait.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
#ifdef __EMSCRIPTEN__
22
#include <math.h>
3+
#include <emscripten/threading.h>
34
#endif
45

56
#include "pthread_impl.h"
67

8+
#ifdef __EMSCRIPTEN__
79
int _pthread_isduecanceled(struct pthread *pthread_ptr);
10+
#endif
811

912
void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
1013
{
@@ -18,7 +21,7 @@ void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
1821
#ifdef __EMSCRIPTEN__
1922
int is_main_thread = emscripten_is_main_runtime_thread();
2023
while (*addr==val) {
21-
if (pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) {
24+
if (is_main_thread || pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) {
2225
// Must wait in slices in case this thread is cancelled in between.
2326
int e;
2427
do {

system/lib/pthread/pthread_create.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#define _GNU_SOURCE
99
#include "pthread_impl.h"
10+
#include "stdio_impl.h"
1011
#include "assert.h"
1112
#include <pthread.h>
1213
#include <stdbool.h>
@@ -53,6 +54,15 @@ void __do_cleanup_pop(struct __ptcb *cb) {
5354
__pthread_self()->cancelbuf = cb->__next;
5455
}
5556

57+
static FILE *volatile dummy_file = 0;
58+
weak_alias(dummy_file, __stdin_used);
59+
weak_alias(dummy_file, __stdout_used);
60+
weak_alias(dummy_file, __stderr_used);
61+
62+
static void init_file_lock(FILE *f) {
63+
if (f && f->lock<0) f->lock = 0;
64+
}
65+
5666
int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attrp, void *(*entry)(void *), void *restrict arg) {
5767
// Note on LSAN: lsan intercepts/wraps calls to pthread_create so any
5868
// allocation we we do here should be considered leaks.
@@ -61,6 +71,17 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
6171
return EINVAL;
6272
}
6373

74+
pthread_t self = __pthread_self();
75+
if (!libc.threaded) {
76+
for (FILE *f=*__ofl_lock(); f; f=f->next)
77+
init_file_lock(f);
78+
__ofl_unlock();
79+
init_file_lock(__stdin_used);
80+
init_file_lock(__stdout_used);
81+
init_file_lock(__stderr_used);
82+
libc.threaded = 1;
83+
}
84+
6485
// Allocate thread block (pthread_t structure).
6586
struct pthread *new = malloc(sizeof(struct pthread));
6687
// zero-initialize thread structure.

tests/core/test_stdio_locking.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Regression test for stdio locking. If file locking is not enabled the
3+
* threads will race to write the file output buffer and we will see lines
4+
* that are longer or shorter then 100 characters. When locking is
5+
* working/enabled each 100 charactor line will be printed seperately.
6+
*
7+
* See:
8+
* musl/src/stdio/__lockfile.c
9+
* musl/src/stdio/fwrite.c
10+
*/
11+
#include <assert.h>
12+
#include <pthread.h>
13+
#include <stdio.h>
14+
#include <string.h>
15+
#include <stdlib.h>
16+
17+
pthread_t thread[2];
18+
19+
char *char_repeat(int n, char c) {
20+
char *dest = malloc(n + 1);
21+
memset(dest, c, n);
22+
dest[n] = '\0';
23+
return dest;
24+
}
25+
26+
void *thread_main(void *arg) {
27+
char *msg = char_repeat(100, 'a');
28+
for (int i = 0; i < 10; ++i)
29+
printf("%s\n", msg);
30+
free(msg);
31+
return 0;
32+
}
33+
34+
int main() {
35+
printf("in main\n");
36+
void *thread_rtn;
37+
int rc;
38+
39+
rc = pthread_create(&thread[0], NULL, thread_main, NULL);
40+
assert(rc == 0);
41+
42+
rc = pthread_create(&thread[1], NULL, thread_main, NULL);
43+
assert(rc == 0);
44+
45+
rc = pthread_join(thread[0], &thread_rtn);
46+
assert(rc == 0);
47+
assert(thread_rtn == 0);
48+
49+
rc = pthread_join(thread[1], &thread_rtn);
50+
assert(rc == 0);
51+
assert(thread_rtn == 0);
52+
53+
printf("main done\n");
54+
return 0;
55+
}

tests/core/test_stdio_locking.out

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
in main
2+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
3+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
4+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
5+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
6+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
7+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
8+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
9+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
10+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
11+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
12+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
13+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
15+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
16+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
17+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
18+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
19+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
20+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
21+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
22+
main done

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.exports

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ M
1414
N
1515
O
1616
P
17-
v
17+
Q
1818
w
1919
x
2020
y

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.funcs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
$GetQueue
22
$__emscripten_init_main_thread
3+
$__emscripten_stdout_seek
34
$__errno_location
45
$__pthread_mutex_lock
56
$__pthread_mutex_trylock
67
$__pthread_mutex_unlock
78
$__pthread_self_internal
89
$__pthread_setcancelstate
10+
$__stdio_write
11+
$__wasi_syscall_ret
912
$__wasm_call_ctors
1013
$__wasm_init_memory
1114
$_do_call
@@ -34,9 +37,11 @@ $emscripten_sync_run_in_main_thread
3437
$emscripten_sync_run_in_main_thread
3538
$emscripten_tls_init
3639
$free_tls
40+
$init_file_lock
3741
$init_mparams
3842
$main
3943
$memset
44+
$pthread_mutexattr_destroy
4045
$sbrk
4146
$stackAlloc
4247
$stackRestore

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ a.r
1919
a.s
2020
a.t
2121
a.u
22+
a.v

tests/other/metadce/minimal_main_Oz_USE_PTHREADS_PROXY_TO_PTHREAD.sent

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ r
1919
s
2020
t
2121
u
22+
v
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16368
1+
16977

tests/test_core.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8399,6 +8399,12 @@ def test_emscripten_futexes(self):
83998399
self.set_setting('USE_PTHREADS')
84008400
self.do_run_in_out_file_test('core/pthread/emscripten_futexes.c')
84018401

8402+
@node_pthreads
8403+
def test_stdio_locking(self):
8404+
self.set_setting('PTHREAD_POOL_SIZE', '2')
8405+
self.set_setting('EXIT_RUNTIME')
8406+
self.do_run_in_out_file_test('core', 'test_stdio_locking.c')
8407+
84028408
@needs_dylink
84038409
@node_pthreads
84048410
def test_pthread_dylink_basics(self):

tools/system_libs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ class CompilerRTLibrary(Library):
12991299
force_object_files = True
13001300

13011301

1302-
class libc_rt_wasm(OptimizedAggressivelyForSizeLibrary, AsanInstrumentedLibrary, CompilerRTLibrary, MuslInternalLibrary):
1302+
class libc_rt_wasm(OptimizedAggressivelyForSizeLibrary, AsanInstrumentedLibrary, CompilerRTLibrary, MuslInternalLibrary, MTLibrary):
13031303
name = 'libc_rt_wasm'
13041304

13051305
def get_files(self):

0 commit comments

Comments
 (0)