xref: /wasmtime-44.0.1/examples/threads.c (revision adff9d9d)
12ba3025eSTheGreatRambler /*
22ba3025eSTheGreatRambler Example of instantiating of the WebAssembly module and invoking its exported
32ba3025eSTheGreatRambler function in a separate thread.
42ba3025eSTheGreatRambler 
557ba95e9SMasashi Yoshimura You can build using cmake:
62ba3025eSTheGreatRambler 
72ba3025eSTheGreatRambler mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-threads
82ba3025eSTheGreatRambler */
92ba3025eSTheGreatRambler 
1015c68f2cSYury Delendik #ifndef _WIN32
1115c68f2cSYury Delendik 
1215c68f2cSYury Delendik #include <inttypes.h>
13f8fee938STyler Rockwood #include <pthread.h>
1415c68f2cSYury Delendik #include <stdio.h>
1515c68f2cSYury Delendik #include <stdlib.h>
1615c68f2cSYury Delendik #include <string.h>
1715c68f2cSYury Delendik #include <unistd.h>
1815c68f2cSYury Delendik #include <wasm.h>
1915c68f2cSYury Delendik #include <wasmtime.h>
2015c68f2cSYury Delendik 
2115c68f2cSYury Delendik #define own
2215c68f2cSYury Delendik 
23f8fee938STyler Rockwood static void exit_with_error(const char *message, wasmtime_error_t *error,
24f8fee938STyler Rockwood                             wasm_trap_t *trap);
2515c68f2cSYury Delendik 
2615c68f2cSYury Delendik const int N_THREADS = 10;
2715c68f2cSYury Delendik const int N_REPS = 3;
2815c68f2cSYury Delendik 
2957ba95e9SMasashi Yoshimura #if defined(__linux__)
3057ba95e9SMasashi Yoshimura #define _GNU_SOURCE
3157ba95e9SMasashi Yoshimura #include <sys/syscall.h>
get_thread_id()3257ba95e9SMasashi Yoshimura uint64_t get_thread_id() { return (uint64_t)syscall(SYS_gettid); }
3357ba95e9SMasashi Yoshimura 
3457ba95e9SMasashi Yoshimura #elif defined(__APPLE__)
3557ba95e9SMasashi Yoshimura #include <pthread.h>
get_thread_id()3657ba95e9SMasashi Yoshimura uint64_t get_thread_id() {
3757ba95e9SMasashi Yoshimura   uint64_t tid;
3857ba95e9SMasashi Yoshimura   pthread_threadid_np(NULL, &tid);
3957ba95e9SMasashi Yoshimura   return tid;
4057ba95e9SMasashi Yoshimura }
4157ba95e9SMasashi Yoshimura 
4257ba95e9SMasashi Yoshimura #endif
4357ba95e9SMasashi Yoshimura 
4415c68f2cSYury Delendik // A function to be called from Wasm code.
callback(const wasm_val_vec_t * args,wasm_val_vec_t * results)45f94db655SPeter Huene own wasm_trap_t *callback(const wasm_val_vec_t *args, wasm_val_vec_t *results) {
46*adff9d9dSAlex Crichton   (void)args;
47*adff9d9dSAlex Crichton   (void)results;
4857ba95e9SMasashi Yoshimura   printf("> Thread %lu running\n", (uint64_t)get_thread_id());
4915c68f2cSYury Delendik   return NULL;
5015c68f2cSYury Delendik }
5115c68f2cSYury Delendik 
5215c68f2cSYury Delendik typedef struct {
5315c68f2cSYury Delendik   wasm_engine_t *engine;
5415c68f2cSYury Delendik   wasm_shared_module_t *module;
5515c68f2cSYury Delendik   int id;
5615c68f2cSYury Delendik } thread_args;
5715c68f2cSYury Delendik 
run(void * args_abs)5815c68f2cSYury Delendik void *run(void *args_abs) {
5915c68f2cSYury Delendik   thread_args *args = (thread_args *)args_abs;
6015c68f2cSYury Delendik 
6115c68f2cSYury Delendik   // Rereate store and module.
6215c68f2cSYury Delendik   own wasm_store_t *store = wasm_store_new(args->engine);
6315c68f2cSYury Delendik   own wasm_module_t *module = wasm_module_obtain(store, args->module);
6415c68f2cSYury Delendik 
6515c68f2cSYury Delendik   // Run the example N times.
6615c68f2cSYury Delendik   for (int i = 0; i < N_REPS; ++i) {
6715c68f2cSYury Delendik     usleep(100000);
6815c68f2cSYury Delendik 
6915c68f2cSYury Delendik     // Create imports.
7057ba95e9SMasashi Yoshimura     own wasm_functype_t *func_type = wasm_functype_new_0_0();
7115c68f2cSYury Delendik     own wasm_func_t *func = wasm_func_new(store, func_type, callback);
7215c68f2cSYury Delendik     wasm_functype_delete(func_type);
7315c68f2cSYury Delendik 
7415c68f2cSYury Delendik     // Instantiate.
75f94db655SPeter Huene     wasm_extern_t *imports[] = {
76f8fee938STyler Rockwood         wasm_func_as_extern(func),
7715c68f2cSYury Delendik     };
78f94db655SPeter Huene     wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
7915c68f2cSYury Delendik     own wasm_instance_t *instance =
80f94db655SPeter Huene         wasm_instance_new(store, module, &imports_vec, NULL);
8115c68f2cSYury Delendik     if (!instance) {
8215c68f2cSYury Delendik       printf("> Error instantiating module!\n");
8315c68f2cSYury Delendik       return NULL;
8415c68f2cSYury Delendik     }
8515c68f2cSYury Delendik 
8615c68f2cSYury Delendik     wasm_func_delete(func);
8715c68f2cSYury Delendik 
8815c68f2cSYury Delendik     // Extract export.
8915c68f2cSYury Delendik     own wasm_extern_vec_t exports;
9015c68f2cSYury Delendik     wasm_instance_exports(instance, &exports);
9115c68f2cSYury Delendik     if (exports.size == 0) {
9215c68f2cSYury Delendik       printf("> Error accessing exports!\n");
9315c68f2cSYury Delendik       return NULL;
9415c68f2cSYury Delendik     }
9515c68f2cSYury Delendik     const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]);
9615c68f2cSYury Delendik     if (run_func == NULL) {
9715c68f2cSYury Delendik       printf("> Error accessing export!\n");
9815c68f2cSYury Delendik       return NULL;
9915c68f2cSYury Delendik     }
10015c68f2cSYury Delendik 
10115c68f2cSYury Delendik     wasm_instance_delete(instance);
10215c68f2cSYury Delendik 
10315c68f2cSYury Delendik     // Call.
104f94db655SPeter Huene     wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
105f94db655SPeter Huene     wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
106f94db655SPeter Huene     if (wasm_func_call(run_func, &args_vec, &results_vec)) {
10715c68f2cSYury Delendik       printf("> Error calling function!\n");
10815c68f2cSYury Delendik       return NULL;
10915c68f2cSYury Delendik     }
11015c68f2cSYury Delendik 
11115c68f2cSYury Delendik     wasm_extern_vec_delete(&exports);
11215c68f2cSYury Delendik   }
11315c68f2cSYury Delendik 
11415c68f2cSYury Delendik   wasm_module_delete(module);
11515c68f2cSYury Delendik   wasm_store_delete(store);
11615c68f2cSYury Delendik 
11715c68f2cSYury Delendik   free(args_abs);
11815c68f2cSYury Delendik 
11915c68f2cSYury Delendik   return NULL;
12015c68f2cSYury Delendik }
12115c68f2cSYury Delendik 
main()122*adff9d9dSAlex Crichton int main() {
12315c68f2cSYury Delendik   // Initialize.
12415c68f2cSYury Delendik   wasm_engine_t *engine = wasm_engine_new();
12515c68f2cSYury Delendik 
12615c68f2cSYury Delendik   // Load our input file to parse it next
12715c68f2cSYury Delendik   FILE *file = fopen("examples/threads.wat", "r");
12815c68f2cSYury Delendik   if (!file) {
12915c68f2cSYury Delendik     printf("> Error loading file!\n");
13015c68f2cSYury Delendik     return 1;
13115c68f2cSYury Delendik   }
13215c68f2cSYury Delendik   fseek(file, 0L, SEEK_END);
13315c68f2cSYury Delendik   size_t file_size = ftell(file);
13415c68f2cSYury Delendik   fseek(file, 0L, SEEK_SET);
13515c68f2cSYury Delendik   wasm_byte_vec_t wat;
13615c68f2cSYury Delendik   wasm_byte_vec_new_uninitialized(&wat, file_size);
13715c68f2cSYury Delendik   if (fread(wat.data, file_size, 1, file) != 1) {
13815c68f2cSYury Delendik     printf("> Error loading module!\n");
13915c68f2cSYury Delendik     return 1;
14015c68f2cSYury Delendik   }
14115c68f2cSYury Delendik   fclose(file);
14215c68f2cSYury Delendik 
14315c68f2cSYury Delendik   // Parse the wat into the binary wasm format
14415c68f2cSYury Delendik   wasm_byte_vec_t binary;
1457a1b7cdfSAlex Crichton   wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
14615c68f2cSYury Delendik   if (error != NULL)
14715c68f2cSYury Delendik     exit_with_error("failed to parse wat", error, NULL);
14815c68f2cSYury Delendik   wasm_byte_vec_delete(&wat);
14915c68f2cSYury Delendik 
15015c68f2cSYury Delendik   // Compile and share.
15115c68f2cSYury Delendik   own wasm_store_t *store = wasm_store_new(engine);
15215c68f2cSYury Delendik   own wasm_module_t *module = wasm_module_new(store, &binary);
15315c68f2cSYury Delendik   if (!module) {
15415c68f2cSYury Delendik     printf("> Error compiling module!\n");
15515c68f2cSYury Delendik     return 1;
15615c68f2cSYury Delendik   }
15715c68f2cSYury Delendik 
15815c68f2cSYury Delendik   wasm_byte_vec_delete(&binary);
15915c68f2cSYury Delendik 
16015c68f2cSYury Delendik   own wasm_shared_module_t *shared = wasm_module_share(module);
16115c68f2cSYury Delendik 
16215c68f2cSYury Delendik   wasm_module_delete(module);
16315c68f2cSYury Delendik   wasm_store_delete(store);
16415c68f2cSYury Delendik 
16515c68f2cSYury Delendik   // Spawn threads.
16615c68f2cSYury Delendik   pthread_t threads[N_THREADS];
16715c68f2cSYury Delendik   for (int i = 0; i < N_THREADS; i++) {
16815c68f2cSYury Delendik     thread_args *args = malloc(sizeof(thread_args));
16915c68f2cSYury Delendik     args->engine = engine;
17015c68f2cSYury Delendik     args->module = shared;
17115c68f2cSYury Delendik     printf("Initializing thread %d...\n", i);
17221c065e3SAlex Crichton 
17321c065e3SAlex Crichton     // Guarantee at least 2MB of stack to allow running Cranelift in debug mode
17421c065e3SAlex Crichton     // on CI.
17521c065e3SAlex Crichton     pthread_attr_t attrs;
17621c065e3SAlex Crichton     pthread_attr_init(&attrs);
17721c065e3SAlex Crichton     pthread_attr_setstacksize(&attrs, 2 << 20);
17821c065e3SAlex Crichton     pthread_create(&threads[i], &attrs, &run, args);
17921c065e3SAlex Crichton     pthread_attr_destroy(&attrs);
18015c68f2cSYury Delendik   }
18115c68f2cSYury Delendik 
18215c68f2cSYury Delendik   for (int i = 0; i < N_THREADS; i++) {
18315c68f2cSYury Delendik     printf("Waiting for thread: %d\n", i);
18415c68f2cSYury Delendik     pthread_join(threads[i], NULL);
18515c68f2cSYury Delendik   }
18615c68f2cSYury Delendik 
18715c68f2cSYury Delendik   wasm_shared_module_delete(shared);
18815c68f2cSYury Delendik   wasm_engine_delete(engine);
18915c68f2cSYury Delendik 
19015c68f2cSYury Delendik   return 0;
19115c68f2cSYury Delendik }
19215c68f2cSYury Delendik 
exit_with_error(const char * message,wasmtime_error_t * error,wasm_trap_t * trap)193f8fee938STyler Rockwood static void exit_with_error(const char *message, wasmtime_error_t *error,
194f8fee938STyler Rockwood                             wasm_trap_t *trap) {
19515c68f2cSYury Delendik   fprintf(stderr, "error: %s\n", message);
19615c68f2cSYury Delendik   wasm_byte_vec_t error_message;
19715c68f2cSYury Delendik   if (error != NULL) {
19815c68f2cSYury Delendik     wasmtime_error_message(error, &error_message);
19915c68f2cSYury Delendik   } else {
20015c68f2cSYury Delendik     wasm_trap_message(trap, &error_message);
20115c68f2cSYury Delendik   }
20215c68f2cSYury Delendik   fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data);
20315c68f2cSYury Delendik   wasm_byte_vec_delete(&error_message);
20415c68f2cSYury Delendik   exit(1);
20515c68f2cSYury Delendik }
20615c68f2cSYury Delendik 
20715c68f2cSYury Delendik #else
20815c68f2cSYury Delendik // TODO implement example for Windows
main(int argc,const char * argv[])209f8fee938STyler Rockwood int main(int argc, const char *argv[]) { return 0; }
21015c68f2cSYury Delendik #endif // _WIN32
211