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 target/release/libwasmtime.a \ 11 -lpthread -ldl -lm \ 12 -o threads 13 ./threads 14 15 Note that on Windows and macOS the command will be similar, but you'll need 16 to tweak the `-lpthread` and such annotations as well as the name of the 17 `libwasmtime.a` file on Windows. 18 19 You can also build using cmake: 20 21 mkdir build && cd build && cmake .. && cmake --build . --target wasmtime-threads 22 */ 23 24 #ifndef _WIN32 25 26 #include <inttypes.h> 27 #include <pthread.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <wasm.h> 33 #include <wasmtime.h> 34 35 #define own 36 37 static void exit_with_error(const char *message, wasmtime_error_t *error, 38 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 typedef struct { 51 wasm_engine_t *engine; 52 wasm_shared_module_t *module; 53 int id; 54 } thread_args; 55 56 void *run(void *args_abs) { 57 thread_args *args = (thread_args *)args_abs; 58 59 // Rereate store and module. 60 own wasm_store_t *store = wasm_store_new(args->engine); 61 own wasm_module_t *module = wasm_module_obtain(store, args->module); 62 63 // Run the example N times. 64 for (int i = 0; i < N_REPS; ++i) { 65 usleep(100000); 66 67 // Create imports. 68 own wasm_functype_t *func_type = 69 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), 82 wasm_global_as_extern(global), 83 }; 84 wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports); 85 own wasm_instance_t *instance = 86 wasm_instance_new(store, module, &imports_vec, NULL); 87 if (!instance) { 88 printf("> Error instantiating module!\n"); 89 return NULL; 90 } 91 92 wasm_func_delete(func); 93 wasm_global_delete(global); 94 95 // Extract export. 96 own wasm_extern_vec_t exports; 97 wasm_instance_exports(instance, &exports); 98 if (exports.size == 0) { 99 printf("> Error accessing exports!\n"); 100 return NULL; 101 } 102 const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]); 103 if (run_func == NULL) { 104 printf("> Error accessing export!\n"); 105 return NULL; 106 } 107 108 wasm_instance_delete(instance); 109 110 // Call. 111 wasm_val_vec_t args_vec = WASM_EMPTY_VEC; 112 wasm_val_vec_t results_vec = WASM_EMPTY_VEC; 113 if (wasm_func_call(run_func, &args_vec, &results_vec)) { 114 printf("> Error calling function!\n"); 115 return NULL; 116 } 117 118 wasm_extern_vec_delete(&exports); 119 } 120 121 wasm_module_delete(module); 122 wasm_store_delete(store); 123 124 free(args_abs); 125 126 return NULL; 127 } 128 129 int main(int argc, const char *argv[]) { 130 // Initialize. 131 wasm_engine_t *engine = wasm_engine_new(); 132 133 // Load our input file to parse it next 134 FILE *file = fopen("examples/threads.wat", "r"); 135 if (!file) { 136 printf("> Error loading file!\n"); 137 return 1; 138 } 139 fseek(file, 0L, SEEK_END); 140 size_t file_size = ftell(file); 141 fseek(file, 0L, SEEK_SET); 142 wasm_byte_vec_t wat; 143 wasm_byte_vec_new_uninitialized(&wat, file_size); 144 if (fread(wat.data, file_size, 1, file) != 1) { 145 printf("> Error loading module!\n"); 146 return 1; 147 } 148 fclose(file); 149 150 // Parse the wat into the binary wasm format 151 wasm_byte_vec_t binary; 152 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary); 153 if (error != NULL) 154 exit_with_error("failed to parse wat", error, NULL); 155 wasm_byte_vec_delete(&wat); 156 157 // Compile and share. 158 own wasm_store_t *store = wasm_store_new(engine); 159 own wasm_module_t *module = wasm_module_new(store, &binary); 160 if (!module) { 161 printf("> Error compiling module!\n"); 162 return 1; 163 } 164 165 wasm_byte_vec_delete(&binary); 166 167 own wasm_shared_module_t *shared = wasm_module_share(module); 168 169 wasm_module_delete(module); 170 wasm_store_delete(store); 171 172 // Spawn threads. 173 pthread_t threads[N_THREADS]; 174 for (int i = 0; i < N_THREADS; i++) { 175 thread_args *args = malloc(sizeof(thread_args)); 176 args->id = i; 177 args->engine = engine; 178 args->module = shared; 179 printf("Initializing thread %d...\n", i); 180 181 // Guarantee at least 2MB of stack to allow running Cranelift in debug mode 182 // on CI. 183 pthread_attr_t attrs; 184 pthread_attr_init(&attrs); 185 pthread_attr_setstacksize(&attrs, 2 << 20); 186 pthread_create(&threads[i], &attrs, &run, args); 187 pthread_attr_destroy(&attrs); 188 } 189 190 for (int i = 0; i < N_THREADS; i++) { 191 printf("Waiting for thread: %d\n", i); 192 pthread_join(threads[i], NULL); 193 } 194 195 wasm_shared_module_delete(shared); 196 wasm_engine_delete(engine); 197 198 return 0; 199 } 200 201 static void exit_with_error(const char *message, wasmtime_error_t *error, 202 wasm_trap_t *trap) { 203 fprintf(stderr, "error: %s\n", message); 204 wasm_byte_vec_t error_message; 205 if (error != NULL) { 206 wasmtime_error_message(error, &error_message); 207 } else { 208 wasm_trap_message(trap, &error_message); 209 } 210 fprintf(stderr, "%.*s\n", (int)error_message.size, error_message.data); 211 wasm_byte_vec_delete(&error_message); 212 exit(1); 213 } 214 215 #else 216 // TODO implement example for Windows 217 int main(int argc, const char *argv[]) { return 0; } 218 #endif // _WIN32 219