diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 227136d81fdfc..dc0d72ef31498 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -17,6 +19,8 @@ #include #include +#include "lock.h" + /* * WASI support code. These are compiled with the program, and call out * using wasi APIs, which can be provided either by a wasi VM or by our @@ -59,15 +63,73 @@ int clock_getres(clockid_t clk_id, struct timespec *tp) { // mmap support is nonexistent. TODO: emulate simple mmaps using // stdio + malloc, which is slow but may help some things? -long __map_file(int x, int y) { - return -ENOSYS; +const unsigned char * __map_file(const char *pathname, size_t *size) { + errno = ENOSYS; + return NULL; } -long __syscall_munmap(int x, int y) { - return -ENOSYS; +struct map { + void* addr; + long length; + struct map* next; +} __attribute__((aligned (1))); + +static volatile int lock[1]; +static struct map* mappings; + +long __syscall_munmap(long addr, long length) { + LOCK(lock); + struct map* map = mappings; + struct map* prev = NULL; + while (map) { + if (map->addr == (void*)addr) { + // We don't support partial munmapping. + if (map->length != length) { + map = NULL; + break; + } + if (prev) { + prev->next = map->next; + } else { + mappings = map->next; + } + break; + } + prev = map; + map = map->next; + } + UNLOCK(lock); + + if (map) { + // Release the memory. + free(map->addr); + // Success! + return 0; + } + + errno = EINVAL; + return -1; } long __syscall_mmap2(long addr, long len, long prot, long flags, long fd, long off) { + // MAP_ANONYMOUS (aka MAP_ANON) isn't actually defined by POSIX spec, + // but it is widely used way to allocate memory pages on Linux, BSD and Mac. + // In this case fd argument is ignored. + if (flags & MAP_ANONYMOUS) { + void* ptr = memalign(WASM_PAGE_SIZE, len + sizeof(struct map)); + if (!ptr) { + return -ENOMEM; + } + memset(ptr, 0, len); + struct map* new_map = (struct map*)((char*)ptr + len); + new_map->addr = ptr; + new_map->length = len; + LOCK(lock); + new_map->next = mappings; + mappings = new_map; + UNLOCK(lock); + return (long)ptr; + } return -ENOSYS; } diff --git a/tests/core/test_mmap.c b/tests/core/test_mmap.c index e091892537e70..aac00310ff479 100644 --- a/tests/core/test_mmap.c +++ b/tests/core/test_mmap.c @@ -17,12 +17,17 @@ int main(int argc, char* argv[]) { assert(getpagesize() == 65536); assert(sysconf(_SC_PAGESIZE) == 65536); + int* maps[10]; for (int i = 0; i < 10; i++) { int* map = (int*)mmap(0, 5000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); assert(map != MAP_FAILED); assert(((long)map) % 65536 == 0); // aligned - assert(munmap(map, 5000) == 0); + maps[i] = map; + } + + for (int i = 0; i < 10; i++) { + assert(munmap(maps[i], 5000) == 0); } const int NUM_BYTES = 8 * 1024 * 1024; @@ -44,6 +49,6 @@ int main(int argc, char* argv[]) { assert(munmap(map, NUM_BYTES) == 0); - printf("hello,world"); + printf("hello,world\n"); return 0; } diff --git a/tests/test_core.py b/tests/test_core.py index ec24f1aa49a9c..66cdd58e52eac 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6061,13 +6061,12 @@ def test_static_variable(self): def test_fakestat(self): self.do_core_test('test_fakestat.c') + @also_with_standalone_wasm() def test_mmap(self): # ASan needs more memory, but that is set up separately if '-fsanitize=address' not in self.emcc_args: self.set_setting('INITIAL_MEMORY', '128mb') - # needs to flush stdio streams - self.set_setting('EXIT_RUNTIME') self.do_core_test('test_mmap.c') def test_mmap_file(self):