1/*********************************************************************** 2* * 3* This software is part of the ast package * 4* Copyright (c) 1985-2011 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 24void _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 61typedef 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 67typedef 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 77typedef 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 85static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm) 86#else 87static int mmvminit(file, addr, round, mm) 88char* file; /* file to map data from */ 89Void_t* addr; /* desired starting address */ 90size_t round; /* amount to round requests */ 91Mmvm_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 = (off_t)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 146done: 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 158static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr, 159 size_t csize, size_t nsize, Vmdisc_t* disc) 160#else 161static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc) 162Vmalloc_t* vm; 163Void_t* caddr; 164size_t csize; 165size_t nsize; 166Vmdisc_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 214static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc) 215#else 216static int mmvmexcept(vm, type, data, disc) 217Vmalloc_t* vm; 218int type; 219Void_t* data; 220Vmdisc_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 245Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round) 246#else 247Vmalloc_t* vmmopen(file, base, round) 248char* file; /* file mapping data from */ 249Void_t* base; /* desired starting address */ 250size_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 291Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set) 292#else 293Void_t* vmmset(vm, data, key, set) 294Vmalloc_t* vm; /* a region based on vmmmopen */ 295int key; /* key of data to be set */ 296Void_t* data; /* data to be set */ 297int 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