aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/vmso.c
diff options
context:
space:
mode:
authorNick Barnes2001-10-31 14:40:56 +0000
committerNick Barnes2001-10-31 14:40:56 +0000
commit7acfca905d76140f4cc0b09c9a12de237de364cd (patch)
tree3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/vmso.c
parentb7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff)
downloademacs-7acfca905d76140f4cc0b09c9a12de237de364cd.tar.gz
emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.zip
Branch imports for masters.
Copied from Perforce Change: 23678 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/vmso.c')
-rw-r--r--mps/code/vmso.c306
1 files changed, 306 insertions, 0 deletions
diff --git a/mps/code/vmso.c b/mps/code/vmso.c
new file mode 100644
index 00000000000..4bc1122721c
--- /dev/null
+++ b/mps/code/vmso.c
@@ -0,0 +1,306 @@
1/* impl.c.vmso: VIRTUAL MEMORY MAPPING FOR SOLARIS 2.x
2 *
3 * $HopeName: MMsrc!vmso.c(trunk.14) $
4 * Copyright (C) 1998 Harlequin Group plc. All rights reserved.
5 *
6 * DESIGN
7 *
8 * .design: design.mps.vmso
9 *
10 * PURPOSE
11 *
12 * .purpose: This is the implementation of the virtual memory mapping
13 * interface (vm.h) for Solaris 2.x. It allows arenas (typically
14 * arenavm is the only client of the interface) to reserve virtual
15 * address space and to map ranges with RAM and unmap memory.
16 *
17 * ASSUMPTIONS
18 *
19 * .assume.not-last: The implementation of VMCreate assumes that mmap()
20 * will not choose a region which contains the last page in the address
21 * space, so that the limit of the mapped area is representable.
22 * (VMCheck checks limit != 0 which is a roundabout way of checking
23 * this.)
24 *
25 * .assume.mmap.err: EAGAIN is the only error we really expect to get
26 * from mmap when committing and ENOMEM when reserving. The others are
27 * either caused by invalid params or features we don't use. See
28 * mmap(2) for details.
29 *
30 * TRANSGRESSIONS
31 *
32 * .fildes.name: VMStruct has two fields whose names violate our naming
33 * conventions. They are called none_fd and zero_fd to emphasize that
34 * they are file descriptors and this fact is not reflected in their
35 * type (we can't change their type as that is restricted by the
36 * interface provided by Solaris).
37 */
38
39#include "mpm.h"
40
41#ifndef MPS_OS_SO
42#error "vmso.c is Solaris 2.x specific, but MPS_OS_SO is not set"
43#endif
44
45/* Open sesame magic */
46#define _POSIX_SOURCE
47
48#include <sys/types.h>
49#include <sys/mman.h>
50#include <fcntl.h>
51#include <errno.h>
52#include <sys/errno.h>
53/* unistd for _SC_PAGESIZE */
54#include <unistd.h>
55
56SRCID(vmso, "$HopeName: MMsrc!vmso.c(trunk.14) $");
57
58
59/* Fix up unprototyped system calls. */
60
61extern int close(int fd);
62extern int munmap(caddr_t addr, size_t len);
63
64
65/* VMStruct -- virtual memory structure */
66
67#define VMSig ((Sig)0x519B3999) /* SIGnature VM */
68
69/* The names of zero_fd and none_fd are transgressions, see .fildes.name */
70typedef struct VMStruct {
71 Sig sig; /* design.mps.sig */
72 int zero_fd; /* fildes for mmap */
73 int none_fd; /* fildes for mmap */
74 Align align; /* page size */
75 Addr base, limit; /* boundaries of reserved space */
76 Size reserved; /* total reserved address space */
77 Size mapped; /* total mapped memory */
78} VMStruct;
79
80
81Align VMAlign(VM vm)
82{
83 return vm->align;
84}
85
86
87Bool VMCheck(VM vm)
88{
89 CHECKS(VM, vm);
90 CHECKL(vm->zero_fd >= 0);
91 CHECKL(vm->none_fd >= 0);
92 CHECKL(vm->zero_fd != vm->none_fd);
93 CHECKL(vm->base != 0);
94 CHECKL(vm->limit != 0);
95 CHECKL(vm->base < vm->limit);
96 CHECKL(vm->mapped <= vm->reserved);
97 CHECKL(SizeIsP2(vm->align));
98 CHECKL(AddrIsAligned(vm->base, vm->align));
99 CHECKL(AddrIsAligned(vm->limit, vm->align));
100 return TRUE;
101}
102
103
104Res VMCreate(VM *vmReturn, Size size)
105{
106 caddr_t addr;
107 Align align;
108 int zero_fd;
109 int none_fd;
110 VM vm;
111 long pagesize;
112 Res res;
113
114 AVER(vmReturn != NULL);
115
116 /* Find out the page size from the OS */
117 pagesize = sysconf(_SC_PAGESIZE);
118 /* check the actual returned pagesize will fit in an object of */
119 /* type Align. */
120 AVER(pagesize > 0);
121 AVER((unsigned long)pagesize <= (unsigned long)(Align)-1);
122 /* Note implicit conversion from "long" to "Align". */
123 align = pagesize;
124 AVER(SizeIsP2(align));
125 size = SizeAlignUp(size, align);
126 if((size == 0) || (size > (Size)(size_t)-1))
127 return ResRESOURCE;
128
129 zero_fd = open("/dev/zero", O_RDONLY);
130 if(zero_fd == -1)
131 return ResFAIL;
132 none_fd = open("/etc/passwd", O_RDONLY);
133 if(none_fd == -1) {
134 res = ResFAIL;
135 goto failNoneOpen;
136 }
137
138 /* Map in a page to store the descriptor on. */
139 addr = mmap((caddr_t)0, (size_t)SizeAlignUp(sizeof(VMStruct), align),
140 PROT_READ | PROT_WRITE, MAP_PRIVATE,
141 zero_fd, (off_t)0);
142 if(addr == MAP_FAILED) {
143 AVER(errno == EAGAIN); /* .assume.mmap.err */
144 res = ResMEMORY;
145 goto failVMMap;
146 }
147 vm = (VM)addr;
148
149 vm->zero_fd = zero_fd;
150 vm->none_fd = none_fd;
151 vm->align = align;
152
153 /* .map.reserve: See .assume.not-last. */
154 addr = mmap((caddr_t)0, (size_t)size, PROT_NONE, MAP_SHARED,
155 none_fd, (off_t)0);
156 if(addr == MAP_FAILED) {
157 AVER(errno == ENOMEM); /* .assume.mmap.err */
158 res = (errno == ENOMEM) ? ResRESOURCE : ResFAIL;
159 goto failReserve;
160 }
161
162 vm->base = (Addr)addr;
163 vm->limit = AddrAdd(vm->base, size);
164 vm->reserved = size;
165 vm->mapped = (Size)0;
166
167 vm->sig = VMSig;
168
169 AVERT(VM, vm);
170
171 EVENT_PAA(VMCreate, vm, vm->base, vm->limit);
172
173 *vmReturn = vm;
174 return ResOK;
175
176failReserve:
177 (void)munmap((caddr_t)vm, (size_t)SizeAlignUp(sizeof(VMStruct), align));
178failVMMap:
179 (void)close(none_fd); /* see .close.fail */
180failNoneOpen:
181 (void)close(zero_fd);
182 return res;
183}
184
185
186void VMDestroy(VM vm)
187{
188 int r;
189 int zero_fd, none_fd;
190
191 AVERT(VM, vm);
192 AVER(vm->mapped == (Size)0);
193
194 /* This appears to be pretty pointless, since the descriptor */
195 /* page is about to vanish completely. However, munmap might fail */
196 /* for some reason, and this would ensure that it was still */
197 /* discovered if sigs were being checked. */
198 vm->sig = SigInvalid;
199
200 zero_fd = vm->zero_fd; none_fd = vm->none_fd;
201 r = munmap((caddr_t)vm->base, (size_t)AddrOffset(vm->base, vm->limit));
202 AVER(r == 0);
203 r = munmap((caddr_t)vm,
204 (size_t)SizeAlignUp(sizeof(VMStruct), vm->align));
205 AVER(r == 0);
206 /* .close.fail: We ignore failure from close() as there's very */
207 /* little we can do anyway. */
208 (void)close(zero_fd);
209 (void)close(none_fd);
210
211 EVENT_P(VMDestroy, vm);
212}
213
214
215Addr VMBase(VM vm)
216{
217 AVERT(VM, vm);
218 return vm->base;
219}
220
221Addr VMLimit(VM vm)
222{
223 AVERT(VM, vm);
224 return vm->limit;
225}
226
227
228Size VMReserved(VM vm)
229{
230 AVERT(VM, vm);
231 return vm->reserved;
232}
233
234Size VMMapped(VM vm)
235{
236 AVERT(VM, vm);
237 return vm->mapped;
238}
239
240
241Res VMMap(VM vm, Addr base, Addr limit)
242{
243 Size size;
244 caddr_t addr;
245
246 AVERT(VM, vm);
247 AVER(base < limit);
248 AVER(base >= vm->base);
249 AVER(limit <= vm->limit);
250 AVER(AddrIsAligned(base, vm->align));
251 AVER(AddrIsAligned(limit, vm->align));
252
253 /* Map /dev/zero onto the area with a copy-on-write policy. This */
254 /* effectively populates the area with zeroed memory. */
255
256 size = AddrOffset(base, limit);
257 /* Check it won't lose any bits. */
258 AVER(size <= (Size)(size_t)-1);
259
260 addr = mmap((caddr_t)base, (size_t)size,
261 PROT_READ | PROT_WRITE | PROT_EXEC,
262 MAP_PRIVATE | MAP_FIXED,
263 vm->zero_fd, (off_t)0);
264 if(addr == MAP_FAILED) {
265 AVER(errno == EAGAIN); /* .assume.mmap.err */
266 return ResMEMORY;
267 }
268 AVER(addr == (caddr_t)base);
269
270 vm->mapped += size;
271
272 EVENT_PAA(VMMap, vm, base, limit);
273 return ResOK;
274}
275
276
277void VMUnmap(VM vm, Addr base, Addr limit)
278{
279 Size size;
280 caddr_t addr;
281
282 AVERT(VM, vm);
283 AVER(base < limit);
284 AVER(base >= vm->base);
285 AVER(limit <= vm->limit);
286 AVER(AddrIsAligned(base, vm->align));
287 AVER(AddrIsAligned(limit, vm->align));
288
289 /* Map /etc/passwd onto the area, allowing no access. This */
290 /* effectively depopulates the area from memory, but keeps */
291 /* it "busy" as far as the OS is concerned, so that it will not */
292 /* be re-used by other calls to mmap which do not specify */
293 /* MAP_FIXED. The offset is specified to mmap so that */
294 /* the OS merges this mapping with .map.reserve. */
295 size = AddrOffset(base, limit);
296 /* Check it won't lose any bits. */
297 AVER(size <= (Size)(size_t)-1);
298 addr = mmap((caddr_t)base, (size_t)size,
299 PROT_NONE, MAP_SHARED | MAP_FIXED,
300 vm->none_fd, (off_t)AddrOffset(vm->base, base));
301 AVER(addr == (caddr_t)base);
302
303 vm->mapped -= size;
304
305 EVENT_PAA(VMUnmap, vm, base, limit);
306}