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 <pthread.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.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, 39 wasm_trap_t *trap); 40 41 const int N_THREADS = 10; 42 const int N_REPS = 3; 43 44 // A function to be called from Wasm code. 45 own wasm_trap_t *callback(const wasm_val_vec_t *args, wasm_val_vec_t *results) { 46 assert(args->data[0].kind == WASM_I32); 47 printf("> Thread %d running\n", args->data[0].of.i32); 48 return NULL; 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 = 70 wasm_functype_new_1_0(wasm_valtype_new_i32()); 71 own wasm_func_t *func = wasm_func_new(store, func_type, callback); 72 wasm_functype_delete(func_type); 73 74 wasm_val_t val = {.kind = WASM_I32, .of = {.i32 = (int32_t)args->id}}; 75 own wasm_globaltype_t *global_type = 76 wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST); 77 own wasm_global_t *global = wasm_global_new(store, global_type, &val); 78 wasm_globaltype_delete(global_type); 79 80 // Instantiate. 81 wasm_extern_t *imports[] = { 82 wasm_func_as_extern(func), 83 wasm_global_as_extern(global), 84 }; 85 wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports); 86 own wasm_instance_t *instance = 87 wasm_instance_new(store, module, &imports_vec, NULL); 88 if (!instance) { 89 printf("> Error instantiating module!\n"); 90 return NULL; 91 } 92 93 wasm_func_delete(func); 94 wasm_global_delete(global); 95 96 // Extract export. 97 own wasm_extern_vec_t exports; 98 wasm_instance_exports(instance, &exports); 99 if (exports.size == 0) { 100 printf("> Error accessing exports!\n"); 101 return NULL; 102 } 103 const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]); 104 if (run_func == NULL) { 105 printf("> Error accessing export!\n"); 106 return NULL; 107 } 108 109 wasm_instance_delete(instance); 110 111 // Call. 112 wasm_val_vec_t args_vec = WASM_EMPTY_VEC; 113 wasm_val_vec_t results_vec = WASM_EMPTY_VEC; 114 if (wasm_func_call(run_func, &args_vec, &results_vec)) { 115 printf("> Error calling function!\n"); 116 return NULL; 117 } 118 119 wasm_extern_vec_delete(&exports); 120 } 121 122 wasm_module_delete(module); 123 wasm_store_delete(store); 124 125 free(args_abs); 126 127 return NULL; 128 } 129 130 int main(int argc, const char *argv[]) { 131 // Initialize. 132 wasm_engine_t *engine = wasm_engine_new(); 133 134 // Load our input file to parse it next 135 FILE *file = fopen("examples/threads.wat", "r"); 136 if (!file) { 137 printf("> Error loading file!\n"); 138 return 1; 139 } 140 fseek(file, 0L, SEEK_END); 141 size_t file_size = ftell(file); 142 fseek(file, 0L, SEEK_SET); 143 wasm_byte_vec_t wat; 144 wasm_byte_vec_new_uninitialized(&wat, file_size); 145 if (fread(wat.data, file_size, 1, file) != 1) { 146 printf("> Error loading module!\n"); 147 return 1; 148 } 149 fclose(file); 150 151 // Parse the wat into the binary wasm format 152 wasm_byte_vec_t binary; 153 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary); 154 if (error != NULL) 155 exit_with_error("failed to parse wat", error, NULL); 156 wasm_byte_vec_delete(&wat); 157 158 // Compile and share. 159 own wasm_store_t *store = wasm_store_new(engine); 160 own wasm_module_t *module = wasm_module_new(store, &binary); 161 if (!module) { 162 printf("> Error compiling module!\n"); 163 return 1; 164 } 165 166 wasm_byte_vec_delete(&binary); 167 168 own wasm_shared_module_t *shared = wasm_module_share(module); 169 170 wasm_module_delete(module); 171 wasm_store_delete(store); 172 173 // Spawn threads. 174 pthread_t threads[N_THREADS]; 175 for (int i = 0; i < N_THREADS; i++) { 176 thread_args *args = malloc(sizeof(thread_args)); 177 args->id = i; 178 args->engine = engine; 179 args->module = shared; 180 printf("Initializing thread %d...\n", i); 181 182 // Guarantee at least 2MB of stack to allow running Cranelift in debug mode 183 // on CI. 184 pthread_attr_t attrs; 185 pthread_attr_init(&attrs); 186 pthread_attr_setstacksize(&attrs, 2 << 20); 187 pthread_create(&threads[i], &attrs, &run, args); 188 pthread_attr_destroy(&attrs); 189 } 190 191 for (int i = 0; i < N_THREADS; i++) { 192 printf("Waiting for thread: %d\n", i); 193 pthread_join(threads[i], NULL); 194 } 195 196 wasm_shared_module_delete(shared); 197 wasm_engine_delete(engine); 198 199 return 0; 200 } 201 202 static void exit_with_error(const char *message, wasmtime_error_t *error, 203 wasm_trap_t *trap) { 204 fprintf(stderr, "error: %s\n", message); 205 wasm_byte_vec_t error_message; 206 if (error != NULL) { 207 wasmtime_error_message(error, &error_message); 208 } else { 209 wasm_trap_message(trap, &error_message); 210 } 211 fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data); 212 wasm_byte_vec_delete(&error_message); 213 exit(1); 214 } 215 216 #else 217 // TODO implement example for Windows 218 int main(int argc, const char *argv[]) { return 0; } 219 #endif // _WIN32 220