1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
23
_STUB_vmmopen()24 void _STUB_vmmopen(){}
25
26 #else
27
28 #include "vmhdr.h"
29
30 #if _sys_stat
31 #include <sys/stat.h>
32 #endif
33 #include <fcntl.h>
34
35 #ifdef S_IRUSR
36 #define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
37 #else
38 #define CREAT_MODE 0644
39 #endif
40
41 #if _lib_mmap
42 #include <sys/mman.h>
43 #else
44 #define mmap(a,b,c,d,e,f) MAP_FAILED
45 #define munmap(a,b) MAP_FAILED
46 #endif
47
48 /* Create a region to allocate based on mmap()
49 **
50 ** Written by Kiem-Phong Vo (kpv@research.att.com)
51 */
52
53 #ifndef MAP_FAILED
54 #define MAP_FAILED (void*)(-1)
55 #endif
56
57 #define MM_MAGIC (('V'<<24) | ('M'<<16) | ('A'<<8) | ('P'))
58 #define MM_ROUND (64*1024)
59 #define MM_START ROUND(sizeof(Mmvm_t),ALIGN)
60
61 typedef struct _user_s
62 { struct _user_s* next; /* link list */
63 int key; /* identifying key */
64 Void_t* data; /* data to be returned */
65 } User_t;
66
67 typedef struct _mmvm_s
68 {
69 Vmulong_t magic; /* magic bytes */
70 Void_t* base; /* base of the map */
71 size_t size; /* current size */
72 size_t busy; /* amount in use */
73 size_t round; /* amount to round to */
74 User_t* user; /* some user data */
75 } Mmvm_t;
76
77 typedef struct _mmvmdisc_s
78 {
79 Vmdisc_t disc; /* Vmalloc discipline */
80 int fd; /* file descriptor */
81 Mmvm_t* mm; /* mmap data */
82 } Mmvmdisc_t;
83
84 #if __STD_C
mmvminit(char * file,Void_t * addr,size_t round,Mmvm_t * mm)85 static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm)
86 #else
87 static int mmvminit(file, addr, round, mm)
88 char* file; /* file to map data from */
89 Void_t* addr; /* desired starting address */
90 size_t round; /* amount to round requests */
91 Mmvm_t* mm; /* to return some mapped info */
92 #endif
93 {
94 int fd;
95 off_t size;
96 Void_t *base;
97 Mmvm_t *hdr;
98
99 base = NIL(Void_t*);
100 if((fd = open(file, O_RDWR, CREAT_MODE)) >= 0)
101 { if((size = lseek(fd, (off_t)0, 2)) < 0)
102 goto done;
103 else if(size == 0)
104 goto new_f;
105
106 /* read the header */
107 if(lseek(fd, (off_t)0, 0) != (off_t)0)
108 goto done;
109 if(read(fd, mm, sizeof(Mmvm_t)) != sizeof(Mmvm_t))
110 goto done;
111 if(mm->magic != MM_MAGIC || !mm->base ||
112 (off_t)mm->size != size || mm->busy > mm->size )
113 goto done;
114 base = (Void_t*)mmap(mm->base, mm->size, PROT_READ|PROT_WRITE,
115 MAP_FIXED|MAP_SHARED, fd, (off_t)0 );
116 if(base == (Void_t*)MAP_FAILED)
117 base = NIL(Void_t*);
118 }
119 else
120 { if((fd = open(file, O_RDWR|O_CREAT, CREAT_MODE)) < 0)
121 goto done;
122
123 new_f: /* create an initial set of data */
124 size = round;
125 if(lseek(fd, size-1, 0) != (size-1) || write(fd, "", 1) != 1 )
126 goto done;
127
128 base = (Void_t*)mmap(addr, (size_t)size, PROT_READ|PROT_WRITE,
129 (addr ? MAP_FIXED : 0)|MAP_SHARED, fd, (off_t)0 );
130 if(base == (Void_t*)MAP_FAILED)
131 base = NIL(Void_t*);
132 if(!base)
133 goto done;
134
135 /* write magic number */
136 hdr = (Mmvm_t*)base;
137 hdr->magic = MM_MAGIC;
138 hdr->base = base;
139 hdr->size = size;
140 hdr->busy = MM_START;
141 hdr->round = round;
142 hdr->user = NIL(User_t*);
143 memcpy(mm, hdr, sizeof(Mmvm_t));
144 }
145
146 done:
147 if(!base)
148 { if(fd >= 0)
149 close(fd);
150 fd = -1;
151 }
152
153 return fd;
154 }
155
156
157 #if __STD_C
mmvmmemory(Vmalloc_t * vm,Void_t * caddr,size_t csize,size_t nsize,Vmdisc_t * disc)158 static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr,
159 size_t csize, size_t nsize, Vmdisc_t* disc)
160 #else
161 static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc)
162 Vmalloc_t* vm;
163 Void_t* caddr;
164 size_t csize;
165 size_t nsize;
166 Vmdisc_t* disc;
167 #endif
168 {
169 Mmvmdisc_t *mmdc = (Mmvmdisc_t*)disc;
170
171 if(mmdc->fd < 0 || !mmdc->mm)
172 return NIL(Void_t*);
173
174 #define MMADDR(b) ((Void_t*)(((Vmuchar_t*)b) + MM_START) )
175 if(caddr && caddr != MMADDR(mmdc->mm->base) )
176 return NIL(Void_t*);
177 if(nsize < csize)
178 return NIL(Void_t*);
179
180 if(nsize > mmdc->mm->size-MM_START)
181 { /* base and size of new map */
182 caddr = mmdc->mm->base;
183 csize = MM_START + nsize +
184 ((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0);
185 csize = ROUND(csize, disc->round);
186
187 /* make room for new space */
188 if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) ||
189 write(mmdc->fd, "", 1) != 1 )
190 return NIL(Void_t*);
191
192 /* remap the space */
193 (void)munmap(caddr, mmdc->mm->size);
194 caddr = (Void_t*)mmap(caddr, csize, PROT_READ|PROT_WRITE,
195 MAP_FIXED|MAP_SHARED, mmdc->fd, (off_t)0 );
196 if(caddr == (Void_t*)MAP_FAILED)
197 caddr = NIL(Void_t*);
198 if(caddr)
199 mmdc->mm->size = csize;
200 else /* bad problem */
201 { close(mmdc->fd);
202 mmdc->fd = -1;
203 mmdc->mm = NIL(Mmvm_t*);
204 return NIL(Void_t*);
205 }
206 }
207
208 mmdc->mm->busy = nsize+MM_START;
209 return (Void_t*)(((Vmuchar_t*)mmdc->mm->base) + MM_START);
210 }
211
212
213 #if __STD_C
mmvmexcept(Vmalloc_t * vm,int type,Void_t * data,Vmdisc_t * disc)214 static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
215 #else
216 static int mmvmexcept(vm, type, data, disc)
217 Vmalloc_t* vm;
218 int type;
219 Void_t* data;
220 Vmdisc_t* disc;
221 #endif
222 {
223 Mmvmdisc_t *mmdc = (Mmvmdisc_t*)disc;
224 Vmuchar_t *base;
225
226 if(type == VM_OPEN)
227 { if(mmdc->mm->busy > MM_START)
228 { base = ((Vmuchar_t*)mmdc->mm->base) + MM_START;
229 *((Void_t**)data) = (Void_t*)base;
230 return 1;
231 }
232 else return 0;
233 }
234 else if(type == VM_CLOSE)
235 { (void)munmap(mmdc->mm->base, mmdc->mm->size);
236 (void)close(mmdc->fd);
237 vmfree(Vmheap, mmdc);
238 return 1; /* freeing of mapped data is already done */
239 }
240 else return 0;
241 }
242
243
244 #if __STD_C
vmmopen(char * file,Void_t * base,size_t round)245 Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round)
246 #else
247 Vmalloc_t* vmmopen(file, base, round)
248 char* file; /* file mapping data from */
249 Void_t* base; /* desired starting address */
250 size_t round; /* amount to round requests */
251 #endif
252 {
253 Vmalloc_t *vm;
254 Mmvmdisc_t *mmdc;
255 Mmvm_t mm;
256 int fd;
257
258 if(!file)
259 return NIL(Vmalloc_t*);
260
261 /* set the amount to round up to on each memory request */
262 GETPAGESIZE(_Vmpagesize);
263 if(round < MM_ROUND)
264 round = MM_ROUND;
265 round = ROUND(round, _Vmpagesize);
266
267 if((fd = mmvminit(file, base, round, &mm)) < 0)
268 return NIL(Vmalloc_t*);
269
270 if(!(mmdc = (Mmvmdisc_t*)vmalloc(Vmheap, sizeof(Mmvmdisc_t))) )
271 { close(fd);
272 return NIL(Vmalloc_t*);
273 }
274
275 mmdc->disc.memoryf = mmvmmemory;
276 mmdc->disc.exceptf = mmvmexcept;
277 mmdc->disc.round = mm.round;
278 mmdc->fd = fd;
279 mmdc->mm = (Mmvm_t*)mm.base;
280
281 if(!(vm = vmopen(&mmdc->disc, Vmbest, VM_TRUST)) )
282 { mmvmexcept(NIL(Vmalloc_t*), VM_CLOSE, NIL(Void_t*), &mmdc->disc);
283 return NIL(Vmalloc_t*);
284 }
285
286 return vm;
287 }
288
289
290 #if __STD_C
vmmset(Vmalloc_t * vm,int key,Void_t * data,int set)291 Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set)
292 #else
293 Void_t* vmmset(vm, data, key, set)
294 Vmalloc_t* vm; /* a region based on vmmmopen */
295 int key; /* key of data to be set */
296 Void_t* data; /* data to be set */
297 int set; /* 1 for setting, 0 for getting */
298 #endif
299 {
300 User_t *u;
301 Mmvm_t *mmvm = ((Mmvmdisc_t*)vm->disc)->mm;
302
303 for(u = mmvm->user; u; u = u->next)
304 if(u->key == key)
305 break;
306 if(!set)
307 return u ? u->data : NIL(Void_t*);
308 else if(u)
309 { Void_t* old = u->data;
310 u->data = data;
311 return old;
312 }
313 else if(!(u = (User_t*)vmalloc(vm, sizeof(User_t))) )
314 return NIL(Void_t*);
315 else
316 { u->data = data;
317 u->key = key;
318 u->next = mmvm->user;
319 mmvm->user = u;
320 return data;
321 }
322 }
323
324 #endif
325