summaryrefslogtreecommitdiff
path: root/wasm2c/examples/threads
diff options
context:
space:
mode:
Diffstat (limited to 'wasm2c/examples/threads')
-rw-r--r--wasm2c/examples/threads/Makefile20
-rw-r--r--wasm2c/examples/threads/sample.wat6
-rw-r--r--wasm2c/examples/threads/threads.c105
3 files changed, 131 insertions, 0 deletions
diff --git a/wasm2c/examples/threads/Makefile b/wasm2c/examples/threads/Makefile
new file mode 100644
index 00000000..f6eb9998
--- /dev/null
+++ b/wasm2c/examples/threads/Makefile
@@ -0,0 +1,20 @@
+#SANITIZERS=-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all
+CFLAGS=-I../.. -g -O2 -Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-array-bounds -Wno-ignored-optimization-argument -Wno-tautological-constant-out-of-range-compare -Wno-infinite-recursion -fno-optimize-sibling-calls -frounding-math -fsignaling-nans ${SANITIZERS} -pthread
+LDFLAGS=${SANITIZERS} -pthread
+
+all: threads
+
+threads: threads.o sample.o ../../wasm-rt-impl.o ../../wasm-rt-exceptions-impl.o -lm
+
+clean:
+ rm -rf threads sample.wasm sample.c sample.h *.o ../../*.o
+
+sample.wasm: sample.wat ../../../bin/wat2wasm
+ ../../../bin/wat2wasm --debug-names $< -o $@
+
+sample.c: sample.wasm ../../../bin/wasm2c
+ ../../../bin/wasm2c $< -o $@
+
+threads.o: sample.c
+
+.PHONY: all clean
diff --git a/wasm2c/examples/threads/sample.wat b/wasm2c/examples/threads/sample.wat
new file mode 100644
index 00000000..f9680dff
--- /dev/null
+++ b/wasm2c/examples/threads/sample.wat
@@ -0,0 +1,6 @@
+;; Module for demonstrating multi-threaded runtime
+
+(func (export "multiplyby3") (param i32) (result i32) (i32.mul (local.get 0) (i32.const 3)))
+
+(func $stackoverflow (export "stackoverflow")
+ (call $stackoverflow))
diff --git a/wasm2c/examples/threads/threads.c b/wasm2c/examples/threads/threads.c
new file mode 100644
index 00000000..14587ed6
--- /dev/null
+++ b/wasm2c/examples/threads/threads.c
@@ -0,0 +1,105 @@
+#include <pthread.h>
+#include <stdio.h>
+
+#include "sample.h"
+#include "wasm-rt-exceptions.h"
+#include "wasm-rt-impl.h"
+
+#define NUM_THREADS 1024
+
+void* do_thread(void* arg);
+
+/**
+ * Example demonstrating use of the wasm2c runtime in multithreaded code.
+ *
+ * The program calls wasm_rt_init() on startup, and each new thread calls
+ * wasm_rt_init_thread() before instantiating a Wasm module. The sample
+ * module is designed to trap with stack exhaustion; this example tests
+ * that each thread can successfully catch the trap (in its own altstack)
+ * independently.
+ */
+
+int main(int argc, char** argv) {
+ pthread_t threads[NUM_THREADS];
+ int arguments[NUM_THREADS];
+
+ /* Initialize the Wasm runtime. */
+ wasm_rt_init();
+
+ /* Create and launch threads running the `do_thread` function. */
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ arguments[i] = i;
+ if (pthread_create(&threads[i], NULL, do_thread, &arguments[i])) {
+ perror("pthread_create");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Join each thread. */
+ for (int i = 0; i < NUM_THREADS; ++i) {
+ void* retval;
+ if (pthread_join(threads[i], &retval)) {
+ perror("pthread_join");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Verify returned value is as expected */
+ if ((retval != &arguments[i]) || (arguments[i] != 3 * i)) {
+ fprintf(stderr, "Unexpected return value from thread.\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /* Free the Wasm runtime's state. */
+ wasm_rt_free();
+
+ printf("%d/%d threads trapped successfully.\n", NUM_THREADS, NUM_THREADS);
+
+ return EXIT_SUCCESS;
+}
+
+void* do_thread(void* arg) {
+ int param;
+ memcpy(&param, arg, sizeof(int));
+
+ /* Initialize the per-thread context for the Wasm runtime (in
+ practice, this allocates and installs an alternate stack for
+ catching segfaults caused by stack exhaustion or out-of-bounds
+ memory access). */
+ wasm_rt_init_thread();
+
+ /* Instantiate the Wasm module. */
+ w2c_sample inst;
+ wasm2c_sample_instantiate(&inst);
+
+ /* Expect a stack-exhaustion trap. (N.B. in a pthreads-created stack, Linux's
+ segfault for stack overflow appears the same as one for memory OOB. This is
+ similar to the behavior of macOS when exhausting a non-pthreads stack. */
+ wasm_rt_trap_t code = wasm_rt_impl_try();
+ if (code != 0) {
+ if (code == WASM_RT_TRAP_OOB || code == WASM_RT_TRAP_EXHAUSTION) {
+ /* Trap arrived as expected. Now call the "real" function. */
+ int returnval = w2c_sample_multiplyby3(&inst, param);
+ memcpy(arg, &returnval, sizeof(int));
+
+ /* Free the module instance. */
+ wasm2c_sample_free(&inst);
+
+ /* Free the per-thread runtime context. */
+ wasm_rt_free_thread();
+
+ return arg;
+ } else {
+ fprintf(stderr, "Expected OOB or exhaustion trap but got %s\n",
+ wasm_rt_strerror(code));
+ return NULL;
+ }
+ }
+
+ /* Call the stack-overflow function. Expect a trap back to above. */
+ w2c_sample_stackoverflow(&inst);
+
+ /* If no trap... */
+ fprintf(stderr, "Expected trap but did not get one\n");
+ return NULL;
+}