14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.Chin@Sun.COM * by AT&T Intellectual Property *
84887Schin * *
94887Schin * A copy of the License is available at *
104887Schin * http://www.opensource.org/licenses/cpl1.0.txt *
114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
124887Schin * *
134887Schin * Information and Software Systems Research *
144887Schin * AT&T Research *
154887Schin * Florham Park NJ *
164887Schin * *
174887Schin * Glenn Fowler <gsf@research.att.com> *
184887Schin * David Korn <dgk@research.att.com> *
194887Schin * Phong Vo <kpv@research.att.com> *
204887Schin * *
214887Schin ***********************************************************************/
224887Schin #if defined(_UWIN) && defined(_BLD_ast)
234887Schin
_STUB_vmmopen()244887Schin void _STUB_vmmopen(){}
254887Schin
264887Schin #else
274887Schin
284887Schin #include "vmhdr.h"
294887Schin
304887Schin #if _sys_stat
314887Schin #include <sys/stat.h>
324887Schin #endif
334887Schin #include <fcntl.h>
344887Schin
354887Schin #ifdef S_IRUSR
364887Schin #define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
374887Schin #else
384887Schin #define CREAT_MODE 0644
394887Schin #endif
404887Schin
414887Schin #if _lib_mmap
424887Schin #include <sys/mman.h>
434887Schin #else
444887Schin #define mmap(a,b,c,d,e,f) MAP_FAILED
454887Schin #define munmap(a,b) MAP_FAILED
464887Schin #endif
474887Schin
484887Schin /* Create a region to allocate based on mmap()
494887Schin **
504887Schin ** Written by Kiem-Phong Vo (kpv@research.att.com)
514887Schin */
524887Schin
534887Schin #ifndef MAP_FAILED
544887Schin #define MAP_FAILED (void*)(-1)
554887Schin #endif
564887Schin
574887Schin #define MM_MAGIC (('V'<<24) | ('M'<<16) | ('A'<<8) | ('P'))
584887Schin #define MM_ROUND (64*1024)
594887Schin #define MM_START ROUND(sizeof(Mmvm_t),ALIGN)
604887Schin
614887Schin typedef struct _user_s
624887Schin { struct _user_s* next; /* link list */
634887Schin int key; /* identifying key */
644887Schin Void_t* data; /* data to be returned */
654887Schin } User_t;
664887Schin
674887Schin typedef struct _mmvm_s
684887Schin {
694887Schin Vmulong_t magic; /* magic bytes */
704887Schin Void_t* base; /* base of the map */
714887Schin size_t size; /* current size */
724887Schin size_t busy; /* amount in use */
734887Schin size_t round; /* amount to round to */
744887Schin User_t* user; /* some user data */
754887Schin } Mmvm_t;
764887Schin
774887Schin typedef struct _mmvmdisc_s
784887Schin {
794887Schin Vmdisc_t disc; /* Vmalloc discipline */
804887Schin int fd; /* file descriptor */
814887Schin Mmvm_t* mm; /* mmap data */
824887Schin } Mmvmdisc_t;
834887Schin
844887Schin #if __STD_C
mmvminit(char * file,Void_t * addr,size_t round,Mmvm_t * mm)854887Schin static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm)
864887Schin #else
874887Schin static int mmvminit(file, addr, round, mm)
884887Schin char* file; /* file to map data from */
894887Schin Void_t* addr; /* desired starting address */
904887Schin size_t round; /* amount to round requests */
914887Schin Mmvm_t* mm; /* to return some mapped info */
924887Schin #endif
934887Schin {
944887Schin int fd;
954887Schin off_t size;
964887Schin Void_t *base;
974887Schin Mmvm_t *hdr;
984887Schin
994887Schin base = NIL(Void_t*);
1004887Schin if((fd = open(file, O_RDWR, CREAT_MODE)) >= 0)
1014887Schin { if((size = lseek(fd, (off_t)0, 2)) < 0)
1024887Schin goto done;
1034887Schin else if(size == 0)
1044887Schin goto new_f;
1054887Schin
1064887Schin /* read the header */
1074887Schin if(lseek(fd, (off_t)0, 0) != (off_t)0)
1084887Schin goto done;
1094887Schin if(read(fd, mm, sizeof(Mmvm_t)) != sizeof(Mmvm_t))
1104887Schin goto done;
1114887Schin if(mm->magic != MM_MAGIC || !mm->base ||
1124887Schin (off_t)mm->size != size || mm->busy > mm->size )
1134887Schin goto done;
1144887Schin base = (Void_t*)mmap(mm->base, mm->size, PROT_READ|PROT_WRITE,
1154887Schin MAP_FIXED|MAP_SHARED, fd, (off_t)0 );
1164887Schin if(base == (Void_t*)MAP_FAILED)
1174887Schin base = NIL(Void_t*);
1184887Schin }
1194887Schin else
1204887Schin { if((fd = open(file, O_RDWR|O_CREAT, CREAT_MODE)) < 0)
1214887Schin goto done;
1224887Schin
1234887Schin new_f: /* create an initial set of data */
1244887Schin size = round;
1254887Schin if(lseek(fd, size-1, 0) != (size-1) || write(fd, "", 1) != 1 )
1264887Schin goto done;
1274887Schin
1284887Schin base = (Void_t*)mmap(addr, (size_t)size, PROT_READ|PROT_WRITE,
1294887Schin (addr ? MAP_FIXED : 0)|MAP_SHARED, fd, (off_t)0 );
1304887Schin if(base == (Void_t*)MAP_FAILED)
1314887Schin base = NIL(Void_t*);
1324887Schin if(!base)
1334887Schin goto done;
1344887Schin
1354887Schin /* write magic number */
1364887Schin hdr = (Mmvm_t*)base;
1374887Schin hdr->magic = MM_MAGIC;
1384887Schin hdr->base = base;
1394887Schin hdr->size = size;
1404887Schin hdr->busy = MM_START;
1414887Schin hdr->round = round;
1424887Schin hdr->user = NIL(User_t*);
1434887Schin memcpy(mm, hdr, sizeof(Mmvm_t));
1444887Schin }
1454887Schin
1464887Schin done:
1474887Schin if(!base)
1484887Schin { if(fd >= 0)
1494887Schin close(fd);
1504887Schin fd = -1;
1514887Schin }
1524887Schin
1534887Schin return fd;
1544887Schin }
1554887Schin
1564887Schin
1574887Schin #if __STD_C
mmvmmemory(Vmalloc_t * vm,Void_t * caddr,size_t csize,size_t nsize,Vmdisc_t * disc)1584887Schin static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr,
1594887Schin size_t csize, size_t nsize, Vmdisc_t* disc)
1604887Schin #else
1614887Schin static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc)
1624887Schin Vmalloc_t* vm;
1634887Schin Void_t* caddr;
1644887Schin size_t csize;
1654887Schin size_t nsize;
1664887Schin Vmdisc_t* disc;
1674887Schin #endif
1684887Schin {
1694887Schin Mmvmdisc_t *mmdc = (Mmvmdisc_t*)disc;
1704887Schin
1714887Schin if(mmdc->fd < 0 || !mmdc->mm)
1724887Schin return NIL(Void_t*);
1734887Schin
1744887Schin #define MMADDR(b) ((Void_t*)(((Vmuchar_t*)b) + MM_START) )
1754887Schin if(caddr && caddr != MMADDR(mmdc->mm->base) )
1764887Schin return NIL(Void_t*);
1774887Schin if(nsize < csize)
1784887Schin return NIL(Void_t*);
1794887Schin
1804887Schin if(nsize > mmdc->mm->size-MM_START)
1814887Schin { /* base and size of new map */
1824887Schin caddr = mmdc->mm->base;
1834887Schin csize = MM_START + nsize +
1844887Schin ((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0);
1854887Schin csize = ROUND(csize, disc->round);
1864887Schin
1874887Schin /* make room for new space */
1884887Schin if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) ||
1894887Schin write(mmdc->fd, "", 1) != 1 )
1904887Schin return NIL(Void_t*);
1914887Schin
1924887Schin /* remap the space */
1934887Schin (void)munmap(caddr, mmdc->mm->size);
1944887Schin caddr = (Void_t*)mmap(caddr, csize, PROT_READ|PROT_WRITE,
1954887Schin MAP_FIXED|MAP_SHARED, mmdc->fd, (off_t)0 );
1964887Schin if(caddr == (Void_t*)MAP_FAILED)
1974887Schin caddr = NIL(Void_t*);
1984887Schin if(caddr)
1994887Schin mmdc->mm->size = csize;
2004887Schin else /* bad problem */
2014887Schin { close(mmdc->fd);
2024887Schin mmdc->fd = -1;
2034887Schin mmdc->mm = NIL(Mmvm_t*);
2044887Schin return NIL(Void_t*);
2054887Schin }
2064887Schin }
2074887Schin
2084887Schin mmdc->mm->busy = nsize+MM_START;
2094887Schin return (Void_t*)(((Vmuchar_t*)mmdc->mm->base) + MM_START);
2104887Schin }
2114887Schin
2124887Schin
2134887Schin #if __STD_C
mmvmexcept(Vmalloc_t * vm,int type,Void_t * data,Vmdisc_t * disc)2144887Schin static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc)
2154887Schin #else
2164887Schin static int mmvmexcept(vm, type, data, disc)
2174887Schin Vmalloc_t* vm;
2184887Schin int type;
2194887Schin Void_t* data;
2204887Schin Vmdisc_t* disc;
2214887Schin #endif
2224887Schin {
2234887Schin Mmvmdisc_t *mmdc = (Mmvmdisc_t*)disc;
2244887Schin Vmuchar_t *base;
2254887Schin
2264887Schin if(type == VM_OPEN)
2274887Schin { if(mmdc->mm->busy > MM_START)
2284887Schin { base = ((Vmuchar_t*)mmdc->mm->base) + MM_START;
2294887Schin *((Void_t**)data) = (Void_t*)base;
2304887Schin return 1;
2314887Schin }
2324887Schin else return 0;
2334887Schin }
2344887Schin else if(type == VM_CLOSE)
2354887Schin { (void)munmap(mmdc->mm->base, mmdc->mm->size);
2364887Schin (void)close(mmdc->fd);
2374887Schin vmfree(Vmheap, mmdc);
2384887Schin return 1; /* freeing of mapped data is already done */
2394887Schin }
2404887Schin else return 0;
2414887Schin }
2424887Schin
2434887Schin
2444887Schin #if __STD_C
vmmopen(char * file,Void_t * base,size_t round)2454887Schin Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round)
2464887Schin #else
2474887Schin Vmalloc_t* vmmopen(file, base, round)
2484887Schin char* file; /* file mapping data from */
2494887Schin Void_t* base; /* desired starting address */
2504887Schin size_t round; /* amount to round requests */
2514887Schin #endif
2524887Schin {
2534887Schin Vmalloc_t *vm;
2544887Schin Mmvmdisc_t *mmdc;
2554887Schin Mmvm_t mm;
2564887Schin int fd;
2574887Schin
2584887Schin if(!file)
2594887Schin return NIL(Vmalloc_t*);
2604887Schin
2614887Schin /* set the amount to round up to on each memory request */
2624887Schin GETPAGESIZE(_Vmpagesize);
2634887Schin if(round < MM_ROUND)
2644887Schin round = MM_ROUND;
2654887Schin round = ROUND(round, _Vmpagesize);
2664887Schin
2674887Schin if((fd = mmvminit(file, base, round, &mm)) < 0)
2684887Schin return NIL(Vmalloc_t*);
2694887Schin
2704887Schin if(!(mmdc = (Mmvmdisc_t*)vmalloc(Vmheap, sizeof(Mmvmdisc_t))) )
2714887Schin { close(fd);
2724887Schin return NIL(Vmalloc_t*);
2734887Schin }
2744887Schin
2754887Schin mmdc->disc.memoryf = mmvmmemory;
2764887Schin mmdc->disc.exceptf = mmvmexcept;
2774887Schin mmdc->disc.round = mm.round;
2784887Schin mmdc->fd = fd;
2794887Schin mmdc->mm = (Mmvm_t*)mm.base;
2804887Schin
2814887Schin if(!(vm = vmopen(&mmdc->disc, Vmbest, VM_TRUST)) )
2824887Schin { mmvmexcept(NIL(Vmalloc_t*), VM_CLOSE, NIL(Void_t*), &mmdc->disc);
2834887Schin return NIL(Vmalloc_t*);
2844887Schin }
2854887Schin
2864887Schin return vm;
2874887Schin }
2884887Schin
2894887Schin
2904887Schin #if __STD_C
vmmset(Vmalloc_t * vm,int key,Void_t * data,int set)2914887Schin Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set)
2924887Schin #else
2934887Schin Void_t* vmmset(vm, data, key, set)
2944887Schin Vmalloc_t* vm; /* a region based on vmmmopen */
2954887Schin int key; /* key of data to be set */
2964887Schin Void_t* data; /* data to be set */
2974887Schin int set; /* 1 for setting, 0 for getting */
2984887Schin #endif
2994887Schin {
3004887Schin User_t *u;
3014887Schin Mmvm_t *mmvm = ((Mmvmdisc_t*)vm->disc)->mm;
3024887Schin
3034887Schin for(u = mmvm->user; u; u = u->next)
3044887Schin if(u->key == key)
3054887Schin break;
3064887Schin if(!set)
3074887Schin return u ? u->data : NIL(Void_t*);
3084887Schin else if(u)
3094887Schin { Void_t* old = u->data;
3104887Schin u->data = data;
3114887Schin return old;
3124887Schin }
3134887Schin else if(!(u = (User_t*)vmalloc(vm, sizeof(User_t))) )
3144887Schin return NIL(Void_t*);
3154887Schin else
3164887Schin { u->data = data;
3174887Schin u->key = key;
3184887Schin u->next = mmvm->user;
3194887Schin mmvm->user = u;
3204887Schin return data;
3214887Schin }
3224887Schin }
3234887Schin
3244887Schin #endif
325