1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Knowledge Ventures * 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 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 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 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 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 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 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