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_vec_t* args, wasm_val_vec_t* results) { 21 assert(args->data[0].kind == WASM_I32); 22 printf("> Thread %d running\n", args->data[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 wasm_extern_t* imports[] = { 57 wasm_func_as_extern(func), wasm_global_as_extern(global), 58 }; 59 wasm_extern_vec_t imports_vec = WASM_ARRAY_VEC(imports); 60 own wasm_instance_t* instance = 61 wasm_instance_new(store, module, &imports_vec, NULL); 62 if (!instance) { 63 printf("> Error instantiating module!\n"); 64 return NULL; 65 } 66 67 wasm_func_delete(func); 68 wasm_global_delete(global); 69 70 // Extract export. 71 own wasm_extern_vec_t exports; 72 wasm_instance_exports(instance, &exports); 73 if (exports.size == 0) { 74 printf("> Error accessing exports!\n"); 75 return NULL; 76 } 77 const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]); 78 if (run_func == NULL) { 79 printf("> Error accessing export!\n"); 80 return NULL; 81 } 82 83 wasm_instance_delete(instance); 84 85 // Call. 86 wasm_val_vec_t args_vec = WASM_EMPTY_VEC; 87 wasm_val_vec_t results_vec = WASM_EMPTY_VEC; 88 if (wasm_func_call(run_func, &args_vec, &results_vec)) { 89 printf("> Error calling function!\n"); 90 return NULL; 91 } 92 93 wasm_extern_vec_delete(&exports); 94 } 95 96 wasm_module_delete(module); 97 wasm_store_delete(store); 98 99 free(args_abs); 100 101 return NULL; 102 } 103 104 int main(int argc, const char *argv[]) { 105 // Initialize. 106 wasm_engine_t* engine = wasm_engine_new(); 107 108 // Load our input file to parse it next 109 FILE* file = fopen("examples/threads.wat", "r"); 110 if (!file) { 111 printf("> Error loading file!\n"); 112 return 1; 113 } 114 fseek(file, 0L, SEEK_END); 115 size_t file_size = ftell(file); 116 fseek(file, 0L, SEEK_SET); 117 wasm_byte_vec_t wat; 118 wasm_byte_vec_new_uninitialized(&wat, file_size); 119 if (fread(wat.data, file_size, 1, file) != 1) { 120 printf("> Error loading module!\n"); 121 return 1; 122 } 123 fclose(file); 124 125 // Parse the wat into the binary wasm format 126 wasm_byte_vec_t binary; 127 wasmtime_error_t *error = wasmtime_wat2wasm(wat.data, wat.size, &binary); 128 if (error != NULL) 129 exit_with_error("failed to parse wat", error, NULL); 130 wasm_byte_vec_delete(&wat); 131 132 // Compile and share. 133 own wasm_store_t* store = wasm_store_new(engine); 134 own wasm_module_t* module = wasm_module_new(store, &binary); 135 if (!module) { 136 printf("> Error compiling module!\n"); 137 return 1; 138 } 139 140 wasm_byte_vec_delete(&binary); 141 142 own wasm_shared_module_t* shared = wasm_module_share(module); 143 144 wasm_module_delete(module); 145 wasm_store_delete(store); 146 147 // Spawn threads. 148 pthread_t threads[N_THREADS]; 149 for (int i = 0; i < N_THREADS; i++) { 150 thread_args* args = malloc(sizeof(thread_args)); 151 args->id = i; 152 args->engine = engine; 153 args->module = shared; 154 printf("Initializing thread %d...\n", i); 155 pthread_create(&threads[i], NULL, &run, args); 156 } 157 158 for (int i = 0; i < N_THREADS; i++) { 159 printf("Waiting for thread: %d\n", i); 160 pthread_join(threads[i], NULL); 161 } 162 163 wasm_shared_module_delete(shared); 164 wasm_engine_delete(engine); 165 166 return 0; 167 } 168 169 static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) { 170 fprintf(stderr, "error: %s\n", message); 171 wasm_byte_vec_t error_message; 172 if (error != NULL) { 173 wasmtime_error_message(error, &error_message); 174 } else { 175 wasm_trap_message(trap, &error_message); 176 } 177 fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data); 178 wasm_byte_vec_delete(&error_message); 179 exit(1); 180 } 181 182 #else 183 // TODO implement example for Windows 184 int main(int argc, const char *argv[]) { 185 return 0; 186 } 187 #endif // _WIN32 188