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