Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/examples/min-platform/embedding/wasmtime-platform.c
2450 views
1
#include <assert.h>
2
#include <errno.h>
3
#include <signal.h>
4
#include <string.h>
5
#include <sys/mman.h>
6
#include <sys/ucontext.h>
7
#include <unistd.h>
8
9
#include "wasmtime-platform.h"
10
11
#ifdef WASMTIME_VIRTUAL_MEMORY
12
13
static int wasmtime_to_mmap_prot_flags(uint32_t prot_flags) {
14
int flags = 0;
15
if (prot_flags & WASMTIME_PROT_READ)
16
flags |= PROT_READ;
17
if (prot_flags & WASMTIME_PROT_WRITE)
18
flags |= PROT_WRITE;
19
if (prot_flags & WASMTIME_PROT_EXEC)
20
flags |= PROT_EXEC;
21
return flags;
22
}
23
24
int wasmtime_mmap_new(uintptr_t size, uint32_t prot_flags, uint8_t **ret) {
25
void *rc = mmap(NULL, size, wasmtime_to_mmap_prot_flags(prot_flags),
26
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
27
if (rc == MAP_FAILED)
28
return errno;
29
*ret = rc;
30
return 0;
31
}
32
33
int wasmtime_mmap_remap(uint8_t *addr, uintptr_t size, uint32_t prot_flags) {
34
void *rc = mmap(addr, size, wasmtime_to_mmap_prot_flags(prot_flags),
35
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
36
if (rc == MAP_FAILED)
37
return errno;
38
return 0;
39
}
40
41
int wasmtime_munmap(uint8_t *ptr, uintptr_t size) {
42
int rc = munmap(ptr, size);
43
if (rc != 0)
44
return errno;
45
return 0;
46
}
47
48
int wasmtime_mprotect(uint8_t *ptr, uintptr_t size, uint32_t prot_flags) {
49
int rc = mprotect(ptr, size, wasmtime_to_mmap_prot_flags(prot_flags));
50
if (rc != 0)
51
return errno;
52
return 0;
53
}
54
55
uintptr_t wasmtime_page_size(void) { return sysconf(_SC_PAGESIZE); }
56
57
#endif // WASMTIME_VIRTUAL_MEMORY
58
59
#ifdef WASMTIME_NATIVE_SIGNALS
60
61
static wasmtime_trap_handler_t g_handler = NULL;
62
63
static void handle_signal(int signo, siginfo_t *info, void *context) {
64
assert(g_handler != NULL);
65
uintptr_t ip, fp;
66
#if defined(__aarch64__)
67
ucontext_t *cx = context;
68
ip = cx->uc_mcontext.pc;
69
fp = cx->uc_mcontext.regs[29];
70
#elif defined(__x86_64__)
71
ucontext_t *cx = context;
72
ip = cx->uc_mcontext.gregs[REG_RIP];
73
fp = cx->uc_mcontext.gregs[REG_RBP];
74
#else
75
#error "Unsupported platform"
76
#endif
77
78
bool has_faulting_addr = signo == SIGSEGV;
79
uintptr_t faulting_addr = 0;
80
if (has_faulting_addr)
81
faulting_addr = (uintptr_t)info->si_addr;
82
g_handler(ip, fp, has_faulting_addr, faulting_addr);
83
84
// If wasmtime didn't handle this trap then reset the handler to the default
85
// behavior which will probably abort the process.
86
signal(signo, SIG_DFL);
87
}
88
89
int wasmtime_init_traps(wasmtime_trap_handler_t handler) {
90
int rc;
91
g_handler = handler;
92
93
struct sigaction action;
94
memset(&action, 0, sizeof(action));
95
96
action.sa_sigaction = handle_signal;
97
action.sa_flags = SA_SIGINFO | SA_NODEFER;
98
sigemptyset(&action.sa_mask);
99
100
rc = sigaction(SIGILL, &action, NULL);
101
if (rc != 0)
102
return errno;
103
rc = sigaction(SIGSEGV, &action, NULL);
104
if (rc != 0)
105
return errno;
106
rc = sigaction(SIGFPE, &action, NULL);
107
if (rc != 0)
108
return errno;
109
return 0;
110
}
111
112
#endif // WASMTIME_NATIVE_SIGNALS
113
114
#ifdef WASMTIME_VIRTUAL_MEMORY
115
116
int wasmtime_memory_image_new(const uint8_t *ptr, uintptr_t len,
117
struct wasmtime_memory_image **ret) {
118
*ret = NULL;
119
return 0;
120
}
121
122
int wasmtime_memory_image_map_at(struct wasmtime_memory_image *image,
123
uint8_t *addr, uintptr_t len) {
124
abort();
125
}
126
127
void wasmtime_memory_image_free(struct wasmtime_memory_image *image) {
128
abort();
129
}
130
131
#endif // WASMTIME_VIRTUAL_MEMORY
132
133
#ifdef WASMTIME_CUSTOM_SYNC
134
135
// Multi-threaded TLS using pthread
136
#include <pthread.h>
137
138
static pthread_key_t wasmtime_tls_key;
139
static pthread_once_t wasmtime_tls_key_once = PTHREAD_ONCE_INIT;
140
141
static void make_tls_key(void) { pthread_key_create(&wasmtime_tls_key, NULL); }
142
143
uint8_t *wasmtime_tls_get(void) {
144
pthread_once(&wasmtime_tls_key_once, make_tls_key);
145
return (uint8_t *)pthread_getspecific(wasmtime_tls_key);
146
}
147
148
void wasmtime_tls_set(uint8_t *val) {
149
pthread_once(&wasmtime_tls_key_once, make_tls_key);
150
pthread_setspecific(wasmtime_tls_key, val);
151
}
152
153
#else
154
155
// Single-threaded TLS using a static variable
156
static uint8_t *WASMTIME_TLS = NULL;
157
158
uint8_t *wasmtime_tls_get(void) { return WASMTIME_TLS; }
159
160
void wasmtime_tls_set(uint8_t *val) { WASMTIME_TLS = val; }
161
162
#endif
163
164
#ifdef WASMTIME_CUSTOM_SYNC
165
166
#include <stdlib.h>
167
168
void wasmtime_sync_lock_free(uintptr_t *lock) {
169
if (*lock != 0) {
170
pthread_mutex_t *mutex = (pthread_mutex_t *)*lock;
171
pthread_mutex_destroy(mutex);
172
free(mutex);
173
*lock = 0;
174
}
175
}
176
177
static pthread_mutex_t *mutex_lazy_init(uintptr_t *lock) {
178
pthread_mutex_t *mutex = (pthread_mutex_t *)*lock;
179
if (mutex == NULL) {
180
pthread_mutex_t *new_mutex = malloc(sizeof(pthread_mutex_t));
181
if (new_mutex == NULL) {
182
abort();
183
}
184
pthread_mutex_init(new_mutex, NULL);
185
186
// Atomically set lock only if it's still NULL
187
if (!__sync_bool_compare_and_swap(lock, 0, (uintptr_t)new_mutex)) {
188
pthread_mutex_destroy(new_mutex);
189
free(new_mutex);
190
}
191
mutex = (pthread_mutex_t *)*lock;
192
}
193
return mutex;
194
}
195
196
void wasmtime_sync_lock_acquire(uintptr_t *lock) {
197
pthread_mutex_t *mutex = mutex_lazy_init(lock);
198
pthread_mutex_lock(mutex);
199
}
200
201
void wasmtime_sync_lock_release(uintptr_t *lock) {
202
pthread_mutex_t *mutex = mutex_lazy_init(lock);
203
pthread_mutex_unlock(mutex);
204
}
205
206
void wasmtime_sync_rwlock_free(uintptr_t *lock) {
207
if (*lock != 0) {
208
pthread_rwlock_t *rwlock = (pthread_rwlock_t *)*lock;
209
pthread_rwlock_destroy(rwlock);
210
free(rwlock);
211
*lock = 0;
212
}
213
}
214
215
static pthread_rwlock_t *rwlock_lazy_init(uintptr_t *lock) {
216
pthread_rwlock_t *rwlock = (pthread_rwlock_t *)*lock;
217
if (rwlock == NULL) {
218
pthread_rwlock_t *new_rwlock = malloc(sizeof(pthread_rwlock_t));
219
if (new_rwlock == NULL) {
220
abort();
221
}
222
pthread_rwlock_init(new_rwlock, NULL);
223
224
// Atomically set lock only if it's still NULL
225
if (!__sync_bool_compare_and_swap(lock, 0, (uintptr_t)new_rwlock)) {
226
// Another thread won the race, discard our allocation
227
pthread_rwlock_destroy(new_rwlock);
228
free(new_rwlock);
229
}
230
rwlock = (pthread_rwlock_t *)*lock;
231
}
232
return rwlock;
233
}
234
235
void wasmtime_sync_rwlock_read(uintptr_t *lock) {
236
pthread_rwlock_t *rwlock = rwlock_lazy_init(lock);
237
pthread_rwlock_rdlock(rwlock);
238
}
239
240
void wasmtime_sync_rwlock_read_release(uintptr_t *lock) {
241
pthread_rwlock_t *rwlock = rwlock_lazy_init(lock);
242
pthread_rwlock_unlock(rwlock);
243
}
244
245
void wasmtime_sync_rwlock_write(uintptr_t *lock) {
246
pthread_rwlock_t *rwlock = rwlock_lazy_init(lock);
247
pthread_rwlock_wrlock(rwlock);
248
}
249
250
void wasmtime_sync_rwlock_write_release(uintptr_t *lock) {
251
pthread_rwlock_t *rwlock = rwlock_lazy_init(lock);
252
pthread_rwlock_unlock(rwlock);
253
}
254
255
#endif // WASMTIME_CUSTOM_SYNC
256
257