xref: /wasmtime-44.0.1/examples/threads.c (revision b1f7ff3b)
1 /*
2 Example of instantiating of the WebAssembly module and invoking its exported
3 function in a separate thread.
4 
5 You can compile and run this example on Linux with:
6 
7    cargo build --release -p wasmtime-c-api
8    cc examples/threads.c \
9        -I crates/c-api/include \
10        -I crates/c-api/wasm-c-api/include \
11        target/release/libwasmtime.a \
12        -lpthread -ldl -lm \
13        -o threads
14    ./threads
15 
16 Note that on Windows and macOS the command will be similar, but you'll need
17 to tweak the `-lpthread` and such annotations as well as the name of the
18 `libwasmtime.a` file on Windows.
19 
20 You can also build using cmake:
21 
22 mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-threads
23 */
24 
25 #ifndef _WIN32
26 
27 #include <inttypes.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <pthread.h>
32 #include <unistd.h>
33 #include <wasm.h>
34 #include <wasmtime.h>
35 
36 #define own
37 
38 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
39 
40 const int N_THREADS = 10;
41 const int N_REPS = 3;
42 
43 // A function to be called from Wasm code.
44 own wasm_trap_t* callback(const wasm_val_vec_t* args, wasm_val_vec_t* results) {
45   assert(args->data[0].kind == WASM_I32);
46   printf("> Thread %d running\n", args->data[0].of.i32);
47   return NULL;
48 }
49 
50 
51 typedef struct {
52   wasm_engine_t* engine;
53   wasm_shared_module_t* module;
54   int id;
55 } thread_args;
56 
57 void* run(void* args_abs) {
58   thread_args* args = (thread_args*)args_abs;
59 
60   // Rereate store and module.
61   own wasm_store_t* store = wasm_store_new(args->engine);
62   own wasm_module_t* module = wasm_module_obtain(store, args->module);
63 
64   // Run the example N times.
65   for (int i = 0; i < N_REPS; ++i) {
66     usleep(100000);
67 
68     // Create imports.
69     own wasm_functype_t* func_type = wasm_functype_new_1_0(wasm_valtype_new_i32());
70     own wasm_func_t* func = wasm_func_new(store, func_type, callback);
71     wasm_functype_delete(func_type);
72 
73     wasm_val_t val = {.kind = WASM_I32, .of = {.i32 = (int32_t)args->id}};
74     own wasm_globaltype_t* global_type =
75       wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST);
76     own wasm_global_t* global = wasm_global_new(store, global_type, &val);
77     wasm_globaltype_delete(global_type);
78 
79     // Instantiate.
80     wasm_extern_t* imports[] = {
81       wasm_func_as_extern(func), wasm_global_as_extern(global),
82     };
83     wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports);
84     own wasm_instance_t* instance =
85       wasm_instance_new(store, module, &imports_vec, NULL);
86     if (!instance) {
87       printf("> Error instantiating module!\n");
88       return NULL;
89     }
90 
91     wasm_func_delete(func);
92     wasm_global_delete(global);
93 
94     // Extract export.
95     own wasm_extern_vec_t exports;
96     wasm_instance_exports(instance, &exports);
97     if (exports.size == 0) {
98       printf("> Error accessing exports!\n");
99       return NULL;
100     }
101     const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]);
102     if (run_func == NULL) {
103       printf("> Error accessing export!\n");
104       return NULL;
105     }
106 
107     wasm_instance_delete(instance);
108 
109     // Call.
110     wasm_val_vec_t args_vec = WASM_EMPTY_VEC;
111     wasm_val_vec_t results_vec = WASM_EMPTY_VEC;
112     if (wasm_func_call(run_func, &args_vec, &results_vec)) {
113       printf("> Error calling function!\n");
114       return NULL;
115     }
116 
117     wasm_extern_vec_delete(&exports);
118   }
119 
120   wasm_module_delete(module);
121   wasm_store_delete(store);
122 
123   free(args_abs);
124 
125   return NULL;
126 }
127 
128 int main(int argc, const char *argv[]) {
129   // Initialize.
130   wasm_engine_t* engine = wasm_engine_new();
131 
132   // Load our input file to parse it next
133   FILE* file = fopen("examples/threads.wat", "r");
134   if (!file) {
135     printf("> Error loading file!\n");
136     return 1;
137   }
138   fseek(file, 0L, SEEK_END);
139   size_t file_size = ftell(file);
140   fseek(file, 0L, SEEK_SET);
141   wasm_byte_vec_t wat;
142   wasm_byte_vec_new_uninitialized(&wat, file_size);
143   if (fread(wat.data, file_size, 1, file) != 1) {
144     printf("> Error loading module!\n");
145     return 1;
146   }
147   fclose(file);
148 
149   // Parse the wat into the binary wasm format
150   wasm_byte_vec_t binary;
151   wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary);
152   if (error != NULL)
153     exit_with_error("failed to parse wat", error, NULL);
154   wasm_byte_vec_delete(&wat);
155 
156   // Compile and share.
157   own wasm_store_t* store = wasm_store_new(engine);
158   own wasm_module_t* module = wasm_module_new(store, &binary);
159   if (!module) {
160     printf("> Error compiling module!\n");
161     return 1;
162   }
163 
164   wasm_byte_vec_delete(&binary);
165 
166   own wasm_shared_module_t* shared = wasm_module_share(module);
167 
168   wasm_module_delete(module);
169   wasm_store_delete(store);
170 
171   // Spawn threads.
172   pthread_t threads[N_THREADS];
173   for (int i = 0; i < N_THREADS; i++) {
174     thread_args* args = malloc(sizeof(thread_args));
175     args->id = i;
176     args->engine = engine;
177     args->module = shared;
178     printf("Initializing thread %d...\n", i);
179     pthread_create(&threads[i], NULL, &run, args);
180   }
181 
182   for (int i = 0; i < N_THREADS; i++) {
183     printf("Waiting for thread: %d\n", i);
184     pthread_join(threads[i], NULL);
185   }
186 
187   wasm_shared_module_delete(shared);
188   wasm_engine_delete(engine);
189 
190   return 0;
191 }
192 
193 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) {
194   fprintf(stderr, "error: %s\n", message);
195   wasm_byte_vec_t error_message;
196   if (error != NULL) {
197     wasmtime_error_message(error, &error_message);
198   } else {
199     wasm_trap_message(trap, &error_message);
200   }
201   fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data);
202   wasm_byte_vec_delete(&error_message);
203   exit(1);
204 }
205 
206 #else
207 // TODO implement example for Windows
208 int main(int argc, const char *argv[]) {
209   return 0;
210 }
211 #endif // _WIN32
212