Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions system/lib/libc/emscripten_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
* for `tools/gen_sig_info.py` to work. This file contains declarations for
* functions that are not declared in any other public or private header.
*/
#ifndef __EMSCRIPTEN_INTERNAL_H__
#define __EMSCRIPTEN_INTERNAL_H__

#include <emscripten/em_macros.h>
#include <emscripten/proxying.h>
Expand Down Expand Up @@ -148,3 +150,5 @@ int _poll_js(void* fds, int nfds, int timeout, void* ctx, void* arg);
#ifdef __cplusplus
}
#endif

#endif /* __EMSCRIPTEN_INTERNAL_H__ */
9 changes: 9 additions & 0 deletions system/lib/libc/musl/src/internal/pthread_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,4 +275,13 @@ extern hidden unsigned __default_guardsize;

#define __ATTRP_C11_THREAD ((void*)(uintptr_t)-1)

#ifdef __EMSCRIPTEN_SHARED_MEMORY__
pid_t gettid(void);
// Unlike `__pthread_self()->tid, `gettid` works under both wasm workers and
// pthreads.
#define CURRENT_THREAD_ID gettid()
#else
#define CURRENT_THREAD_ID __pthread_self()->tid
#endif

#endif
2 changes: 1 addition & 1 deletion system/lib/libc/musl/src/internal/stdio_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#define UNGET 8

#if defined(__EMSCRIPTEN__) && !defined(_REENTRANT)
#if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_SHARED_MEMORY__)
#define FFINALLOCK(f)
#define FLOCK(f)
#define FUNLOCK(f)
Expand Down
13 changes: 9 additions & 4 deletions system/lib/libc/musl/src/linux/gettid.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
#include <unistd.h>
#include "pthread_impl.h"

#ifdef __EMSCRIPTEN_WASM_WORKERS__
#include <emscripten/wasm_worker.h>
#elif defined(__EMSCRIPTEN_PTHREADS__)
#ifdef __EMSCRIPTEN__
weak int emscripten_wasm_worker_self_id();
#endif

Expand All @@ -16,7 +14,14 @@ pid_t gettid(void)
{
#ifdef __EMSCRIPTEN_WASM_WORKERS__
// Offset the worker ID by 1 so we never return 0 from this function.
return emscripten_wasm_worker_self_id() + 1;
// Strangly we cannot assume the existence of emscripten_wasm_worker_self_id
// here because libc-ww is also used for `-sSHARED_MEMORY` builds (without
// libwasm_workers linked in.
if (emscripten_wasm_worker_self_id) {
return emscripten_wasm_worker_self_id() + 1;
} else {
return 42;
}
#else
#if defined(__EMSCRIPTEN_PTHREADS__)
// The pthread-variant of libc can also be used alongside wasm workers.
Expand Down
6 changes: 3 additions & 3 deletions system/lib/libc/musl/src/stdio/__lockfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

int __lockfile(FILE *f)
{
#if defined(__EMSCRIPTEN_PTHREADS__)
int owner = f->lock, tid = __pthread_self()->tid;
#ifdef __EMSCRIPTEN_SHARED_MEMORY__
int owner = f->lock, tid = CURRENT_THREAD_ID;
if ((owner & ~MAYBE_WAITERS) == tid)
return 0;
owner = a_cas(&f->lock, 0, tid);
Expand All @@ -20,7 +20,7 @@ int __lockfile(FILE *f)

void __unlockfile(FILE *f)
{
#if defined(__EMSCRIPTEN_PTHREADS__)
#ifdef __EMSCRIPTEN_SHARED_MEMORY__
if (a_swap(&f->lock, 0) & MAYBE_WAITERS)
__wake(&f->lock, 1, 1);
#endif
Expand Down
2 changes: 1 addition & 1 deletion system/lib/libc/musl/src/stdio/getc.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ static int locking_getc(FILE *f)
static inline int do_getc(FILE *f)
{
int l = f->lock;
if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
if (l < 0 || l && (l & ~MAYBE_WAITERS) == CURRENT_THREAD_ID)
return getc_unlocked(f);
return locking_getc(f);
}
2 changes: 1 addition & 1 deletion system/lib/libc/musl/src/stdio/putc.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ static int locking_putc(int c, FILE *f)
static inline int do_putc(int c, FILE *f)
{
int l = f->lock;
if (l < 0 || l && (l & ~MAYBE_WAITERS) == __pthread_self()->tid)
if (l < 0 || l && (l & ~MAYBE_WAITERS) == CURRENT_THREAD_ID)
return putc_unlocked(c, f);
return locking_putc(c, f);
}
44 changes: 42 additions & 2 deletions system/lib/wasm_worker/library_wasm_worker.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
* Copyright 2022 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/

// libc files are compiled as -std=c99 which doesn't normally declare
// max_align_t.
#if __STDC_VERSION__ < 201112L
#define __NEED_max_align_t
#endif

#include "libc.h"
#include "stdio_impl.h"
#include "emscripten_internal.h"

#include <assert.h>
#include <emscripten/wasm_worker.h>
#include <emscripten/threading.h>
Expand All @@ -7,8 +24,6 @@
#include <malloc.h>
#include <sys/param.h> // For MAX()

#include "emscripten_internal.h"

#ifndef __EMSCRIPTEN_WASM_WORKERS__
#error __EMSCRIPTEN_WASM_WORKERS__ should be defined when building this file!
#endif
Expand All @@ -33,6 +48,15 @@ static void emscripten_wasm_worker_main_thread_initialize() {
*sbrk_ptr += ROUND_UP(__builtin_wasm_tls_size(), SBRK_ALIGN);
}

static FILE *volatile dummy_file = 0;
weak_alias(dummy_file, __stdin_used);
weak_alias(dummy_file, __stdout_used);
weak_alias(dummy_file, __stderr_used);

static void init_file_lock(FILE *f) {
if (f && f->lock<0) f->lock = 0;
}

emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress, size_t stackPlusTLSSize) {
assert(stackPlusTLSAddress != 0);
assert((uintptr_t)stackPlusTLSAddress % STACK_ALIGN == 0);
Expand Down Expand Up @@ -61,6 +85,22 @@ emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress
stackPlusTLSAddress = (void*)tlsBase;
stackPlusTLSSize -= padding;
}

if (!libc.threaded) {
for (FILE *f=*__ofl_lock(); f; f=f->next) {
init_file_lock(f);
}
__ofl_unlock();
init_file_lock(__stdin_used);
init_file_lock(__stdout_used);
init_file_lock(__stderr_used);
libc.threaded = 1;
}

// Unlike with ptheads, wasm workers never really exit and so this counter
// only going one way here.
if (!libc.threads_minus_1++) libc.need_locks = 1;

return _emscripten_create_wasm_worker(stackPlusTLSAddress, stackPlusTLSSize);
}

Expand Down
89 changes: 47 additions & 42 deletions test/codesize/hello_wasm_worker_wasm.expected.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,80 @@
var c = Module, d = "em-ww" == globalThis.name, e, f, y, z, l, A, t;
var c = Module, d = "em-ww" == globalThis.name, e = !!globalThis.WorkerGlobalScope, f, g, C, r, D, n, E, w;

d && (onmessage = a => {
onmessage = null;
e = a = a.data;
f = a.l;
g();
c ||= {};
c.wasm = a.j;
f = a = a.data;
g = a.o;
h();
a.j = a.l = 0;
c ||= {};
c.wasm = a.m;
k();
a.m = a.o = 0;
});

function g() {}
function h() {}

d || (f = c.mem || new WebAssembly.Memory({
d || (g = c.mem || new WebAssembly.Memory({
initial: 256,
maximum: 256,
shared: !0
}), g());
}), h());

var k = [], n = a => {
var l = [], p = a => {
a = a.data;
let b = a._wsc;
b && l.get(b)(...a.x);
}, p = a => {
k.push(a);
}, q = {}, r = 1, u = (a, b) => {
let m = q[r] = new Worker(c.js, {
b && n.get(b)(...a.x);
}, q = a => {
l.push(a);
}, t = () => {
r(0, !e, !d, e && 1);
}, u = {}, v = 1, x = (a, b) => {
let m = u[v] = new Worker(c.js, {
name: "em-ww"
});
m.postMessage({
s: r,
j: t,
l: f,
m: a,
o: b
v: v,
m: w,
o: g,
s: a,
u: b
});
m.onmessage = n;
return r++;
}, v = () => !1, w = (a, b) => {
q[a].postMessage({
m.onmessage = p;
return v++;
}, y = () => performance.now(), z = () => !1, A = (a, b) => {
u[a].postMessage({
_wsc: b,
x: []
});
};

d && (q[0] = globalThis, addEventListener("message", p));
d && (u[0] = globalThis, addEventListener("message", q));

function x() {
function B() {
console.log("Hello from wasm worker!");
}

function h() {
A = {
b: u,
c: v,
d: w,
e: x,
a: f
function k() {
E = {
e: t,
c: x,
b: y,
d: z,
f: A,
g: B,
a: g
};
WebAssembly.instantiate(c.wasm, {
a: A
a: E
}).then((a => {
var b = (a.instance || a).exports;
t = a.module || c.wasm;
y = b.g;
z = b.i;
l = b.h;
d ? (z(e.s, e.m, e.o), removeEventListener("message", p), k = k.forEach(n), addEventListener("message", n)) : b.f();
d || y();
w = a.module || c.wasm;
C = b.i;
r = b.k;
D = b.l;
n = b.j;
d ? (D(f.v, f.s, f.u), removeEventListener("message", q), l = l.forEach(p), addEventListener("message", p)) : b.h();
d || C();
}));
}

d || h();
d || k();
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.html": 515,
"a.html.gz": 355,
"a.js": 859,
"a.js.gz": 545,
"a.wasm": 1847,
"a.wasm.gz": 1071,
"total": 3221,
"total_gz": 1971
"a.js": 956,
"a.js.gz": 605,
"a.wasm": 2744,
"a.wasm.gz": 1530,
"total": 4215,
"total_gz": 2490
}
38 changes: 33 additions & 5 deletions test/core/test_stdio_locking.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
#include <string.h>
#include <stdlib.h>

pthread_t thread[2];
#ifdef __EMSCRIPTEN_WASM_WORKERS__
#include <emscripten/eventloop.h>
#include <emscripten/wasm_worker.h>
#endif

char *char_repeat(int n, char c) {
char *dest = malloc(n + 1);
Expand All @@ -23,16 +26,41 @@ char *char_repeat(int n, char c) {
return dest;
}

void *thread_main(void *arg) {
void thread_func() {
char *msg = char_repeat(100, 'a');
for (int i = 0; i < 10; ++i)
printf("%s\n", msg);
for (int i = 0; i < 10; ++i) {
printf("%s\n", msg);
}
free(msg);
}

#if defined(__EMSCRIPTEN_PTHREADS__)
void *thread_main(void *arg) {
thread_func();
return 0;
}
#endif

#if defined(__EMSCRIPTEN_WASM_WORKERS__)
void terminate_worker(void* userData) {
emscripten_terminate_all_wasm_workers();
printf("main done\n");
}
#endif

int main() {
printf("in main\n");
#ifdef __EMSCRIPTEN_WASM_WORKERS__
emscripten_wasm_worker_t worker[2];
worker[0] = emscripten_malloc_wasm_worker(/*stack size: */ 1024);
worker[1] = emscripten_malloc_wasm_worker(/*stack size: */ 1024);
emscripten_wasm_worker_post_function_v(worker[0], thread_func);
emscripten_wasm_worker_post_function_v(worker[1], thread_func);

// Terminate both workers after a small delay
emscripten_set_timeout(terminate_worker, 1000, 0);
#else
pthread_t thread[2];
void *thread_rtn;
int rc;

Expand All @@ -49,7 +77,7 @@ int main() {
rc = pthread_join(thread[1], &thread_rtn);
assert(rc == 0);
assert(thread_rtn == 0);

printf("main done\n");
#endif
return 0;
}
1 change: 1 addition & 0 deletions test/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
# picked from here, but you can force them to be, using something like
# randombrowser10 (which runs 10 random tests from 'browser').
misc_test_modes = [
'codesize',
'other',
'jslib',
'browser',
Expand Down
Loading
Loading