Path: blob/main/system/lib/libc/emscripten_mmap.c
6162 views
/*1* Copyright 2022 The Emscripten Authors. All rights reserved.2* Emscripten is available under two separate licenses, the MIT license and the3* University of Illinois/NCSA Open Source License. Both these licenses can be4* found in the LICENSE file.5*/6#include <assert.h>7#include <errno.h>8#include <malloc.h>9#include <stdbool.h>10#include <stdlib.h>11#include <string.h>12#include <sys/mman.h>1314#include <emscripten/heap.h>1516#include "emscripten_internal.h"17#include "lock.h"18#include "syscall.h"1920struct map {21void* addr;22long length;23int allocated;24int fd;25int flags;26off_t offset;27int prot;28struct map* next;29} __attribute__((aligned (1)));3031#define ALIGN_TO(value,alignment) (((value) + ((alignment) - 1)) & ~((alignment) - 1))3233// Linked list of all mapping, guarded by a musl-style lock (LOCK/UNLOCK)34static volatile int lock[1];35static struct map* mappings;3637static struct map* find_mapping(intptr_t addr, struct map** prev) {38struct map* map = mappings;39while (map) {40if (map->addr == (void*)addr) {41return map;42}43if (prev) {44*prev = map;45}46map = map->next;47}48return map;49}5051int __syscall_munmap(intptr_t addr, size_t length) {52LOCK(lock);53struct map* prev = NULL;54struct map* map = find_mapping(addr, &prev);55if (!map || !length) {56UNLOCK(lock);57return -EINVAL;58}5960// We don't support partial munmapping.61if (map->length != length) {62UNLOCK(lock);63return -EINVAL;64}6566// Remove map from linked list67if (prev) {68prev->next = map->next;69} else {70mappings = map->next;71}72UNLOCK(lock);7374if (!(map->flags & MAP_ANONYMOUS)) {75_munmap_js(addr, length, map->prot, map->flags, map->fd, map->offset);76}7778// Release the memory.79if (map->allocated) {80emscripten_builtin_free(map->addr);81}8283if (!(map->flags & MAP_ANONYMOUS)) {84emscripten_builtin_free(map);85}8687// Success!88return 0;89}9091int __syscall_msync(intptr_t addr, size_t len, int flags) {92LOCK(lock);93struct map* map = find_mapping(addr, NULL);94UNLOCK(lock);95if (!map) {96return -EINVAL;97}98if (map->flags & MAP_ANONYMOUS) {99return 0;100}101return _msync_js(addr, len, map->prot, map->flags, map->fd, map->offset);102}103104intptr_t __syscall_mmap2(intptr_t addr, size_t len, int prot, int flags, int fd, off_t offset) {105if (addr != 0) {106// We don't currently support location hints for the address of the mapping107return -EINVAL;108}109110offset *= SYSCALL_MMAP2_UNIT;111struct map* new_map;112113// MAP_ANONYMOUS (aka MAP_ANON) isn't actually defined by POSIX spec,114// but it is widely used way to allocate memory pages on Linux, BSD and Mac.115// In this case fd argument is ignored.116if (flags & MAP_ANONYMOUS) {117size_t alloc_len = ALIGN_TO(len, 16);118// For anonymous maps, allocate that mapping at the end of the region.119void* ptr = emscripten_builtin_memalign(WASM_PAGE_SIZE, alloc_len + sizeof(struct map));120if (!ptr) {121return -ENOMEM;122}123memset(ptr, 0, alloc_len);124new_map = (struct map*)((char*)ptr + alloc_len);125new_map->addr = ptr;126new_map->fd = -1;127new_map->allocated = true;128} else {129new_map = emscripten_builtin_malloc(sizeof(struct map));130int rtn =131_mmap_js(len, prot, flags, fd, offset, &new_map->allocated, &new_map->addr);132if (rtn < 0) {133emscripten_builtin_free(new_map);134return rtn;135}136new_map->fd = fd;137}138139new_map->length = len;140new_map->flags = flags;141new_map->offset = offset;142new_map->prot = prot;143144LOCK(lock);145new_map->next = mappings;146mappings = new_map;147UNLOCK(lock);148149return (long)new_map->addr;150}151152153