Hi Philippe, While working on mmap-alloc.c, I found that Emscripten does not support partial unmapping of memory regions [1]. This limitation prevents correct implementation of qemu_ram_mmap and qemu_ram_munmap, which rely on partial unmap behavior.
[1] https://github.com/emscripten-core/emscripten/blob/d4a74336f23214bf3304d9eb0d03966786b30a36/system/lib/libc/emscripten_mmap.c#L61 As a workaround, I'm considering excluding mmap-alloc.c from the Emscripten build. Instead, for Emscripten build, we can modify qemu_anon_ram_alloc (in oslib-posix.c) to use qemu_memalign in place of qemu_ram_mmap, and disable memory backends that rely on mmap, such as memory-backend-file and memory-backend-shm. I plan to include this fix in the next version of the patch series. I'm happy to hear any suggestions if there is a better way to address this limitation. The change in oslib-posix.c will look like this: diff --git a/util/oslib-posix.c b/util/oslib-posix.c index a697c602c6..8eb0e53458 100644 --- a/util/oslib-posix.c +++ b/util/oslib-posix.c @@ -58,6 +58,7 @@ #include <lwp.h> #endif +#include "qemu/memalign.h" #include "qemu/mmap-alloc.h" #define MAX_MEM_PREALLOC_THREAD_COUNT 16 @@ -210,11 +211,21 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared, const uint32_t qemu_map_flags = (shared ? QEMU_MAP_SHARED : 0) | (noreserve ? QEMU_MAP_NORESERVE : 0); size_t align = QEMU_VMALLOC_ALIGN; +#ifndef EMSCRIPTEN void *ptr = qemu_ram_mmap(-1, size, align, qemu_map_flags, 0); if (ptr == MAP_FAILED) { return NULL; } +#else + /* + * qemu_ram_mmap is not implemented for Emscripten. Use qemu_memalign + * for the anonymous allocation. noreserve is ignored as there is no swap + * space on Emscripten, and shared is ignored as there is no other + * processes on Emscripten. + */ + void *ptr = qemu_memalign(align, size); +#endif if (alignment) { *alignment = align; @@ -227,7 +238,16 @@ void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment, bool shared, void qemu_anon_ram_free(void *ptr, size_t size) { trace_qemu_anon_ram_free(ptr, size); +#ifndef EMSCRIPTEN qemu_ram_munmap(-1, ptr, size); +#else + /* + * qemu_ram_munmap is not implemented for Emscripten and qemu_memalign + * was used for the allocation. Use the corresponding freeing function + * here. + */ + qemu_vfree(ptr); +#endif } void qemu_socket_set_block(int fd) @@ -588,7 +608,15 @@ bool qemu_prealloc_mem(int fd, char *area, size_t sz, int max_threads, { static gsize initialized; int ret; +#ifndef EMSCRIPTEN size_t hpagesize = qemu_fd_getpagesize(fd); +#else + /* + * mmap-alloc.c is excluded from Emscripten build, so qemu_fd_getpagesize + * is unavailable. Fallback to the lower level implementation. + */ + size_t hpagesize = qemu_real_host_page_size(); +#endif size_t numpages = DIV_ROUND_UP(sz, hpagesize); bool use_madv_populate_write; struct sigaction act;