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