Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/libc/emscripten_mmap.c
6162 views
1
/*
2
* Copyright 2022 The Emscripten Authors. All rights reserved.
3
* Emscripten is available under two separate licenses, the MIT license and the
4
* University of Illinois/NCSA Open Source License. Both these licenses can be
5
* found in the LICENSE file.
6
*/
7
#include <assert.h>
8
#include <errno.h>
9
#include <malloc.h>
10
#include <stdbool.h>
11
#include <stdlib.h>
12
#include <string.h>
13
#include <sys/mman.h>
14
15
#include <emscripten/heap.h>
16
17
#include "emscripten_internal.h"
18
#include "lock.h"
19
#include "syscall.h"
20
21
struct map {
22
void* addr;
23
long length;
24
int allocated;
25
int fd;
26
int flags;
27
off_t offset;
28
int prot;
29
struct map* next;
30
} __attribute__((aligned (1)));
31
32
#define ALIGN_TO(value,alignment) (((value) + ((alignment) - 1)) & ~((alignment) - 1))
33
34
// Linked list of all mapping, guarded by a musl-style lock (LOCK/UNLOCK)
35
static volatile int lock[1];
36
static struct map* mappings;
37
38
static struct map* find_mapping(intptr_t addr, struct map** prev) {
39
struct map* map = mappings;
40
while (map) {
41
if (map->addr == (void*)addr) {
42
return map;
43
}
44
if (prev) {
45
*prev = map;
46
}
47
map = map->next;
48
}
49
return map;
50
}
51
52
int __syscall_munmap(intptr_t addr, size_t length) {
53
LOCK(lock);
54
struct map* prev = NULL;
55
struct map* map = find_mapping(addr, &prev);
56
if (!map || !length) {
57
UNLOCK(lock);
58
return -EINVAL;
59
}
60
61
// We don't support partial munmapping.
62
if (map->length != length) {
63
UNLOCK(lock);
64
return -EINVAL;
65
}
66
67
// Remove map from linked list
68
if (prev) {
69
prev->next = map->next;
70
} else {
71
mappings = map->next;
72
}
73
UNLOCK(lock);
74
75
if (!(map->flags & MAP_ANONYMOUS)) {
76
_munmap_js(addr, length, map->prot, map->flags, map->fd, map->offset);
77
}
78
79
// Release the memory.
80
if (map->allocated) {
81
emscripten_builtin_free(map->addr);
82
}
83
84
if (!(map->flags & MAP_ANONYMOUS)) {
85
emscripten_builtin_free(map);
86
}
87
88
// Success!
89
return 0;
90
}
91
92
int __syscall_msync(intptr_t addr, size_t len, int flags) {
93
LOCK(lock);
94
struct map* map = find_mapping(addr, NULL);
95
UNLOCK(lock);
96
if (!map) {
97
return -EINVAL;
98
}
99
if (map->flags & MAP_ANONYMOUS) {
100
return 0;
101
}
102
return _msync_js(addr, len, map->prot, map->flags, map->fd, map->offset);
103
}
104
105
intptr_t __syscall_mmap2(intptr_t addr, size_t len, int prot, int flags, int fd, off_t offset) {
106
if (addr != 0) {
107
// We don't currently support location hints for the address of the mapping
108
return -EINVAL;
109
}
110
111
offset *= SYSCALL_MMAP2_UNIT;
112
struct map* new_map;
113
114
// MAP_ANONYMOUS (aka MAP_ANON) isn't actually defined by POSIX spec,
115
// but it is widely used way to allocate memory pages on Linux, BSD and Mac.
116
// In this case fd argument is ignored.
117
if (flags & MAP_ANONYMOUS) {
118
size_t alloc_len = ALIGN_TO(len, 16);
119
// For anonymous maps, allocate that mapping at the end of the region.
120
void* ptr = emscripten_builtin_memalign(WASM_PAGE_SIZE, alloc_len + sizeof(struct map));
121
if (!ptr) {
122
return -ENOMEM;
123
}
124
memset(ptr, 0, alloc_len);
125
new_map = (struct map*)((char*)ptr + alloc_len);
126
new_map->addr = ptr;
127
new_map->fd = -1;
128
new_map->allocated = true;
129
} else {
130
new_map = emscripten_builtin_malloc(sizeof(struct map));
131
int rtn =
132
_mmap_js(len, prot, flags, fd, offset, &new_map->allocated, &new_map->addr);
133
if (rtn < 0) {
134
emscripten_builtin_free(new_map);
135
return rtn;
136
}
137
new_map->fd = fd;
138
}
139
140
new_map->length = len;
141
new_map->flags = flags;
142
new_map->offset = offset;
143
new_map->prot = prot;
144
145
LOCK(lock);
146
new_map->next = mappings;
147
mappings = new_map;
148
UNLOCK(lock);
149
150
return (long)new_map->addr;
151
}
152
153