/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1985-2008 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * David Korn * * Phong Vo * * * ***********************************************************************/ #if defined(_UWIN) && defined(_BLD_ast) void _STUB_vmmopen(){} #else #include "vmhdr.h" #if _sys_stat #include #endif #include #ifdef S_IRUSR #define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) #else #define CREAT_MODE 0644 #endif #if _lib_mmap #include #else #define mmap(a,b,c,d,e,f) MAP_FAILED #define munmap(a,b) MAP_FAILED #endif /* Create a region to allocate based on mmap() ** ** Written by Kiem-Phong Vo (kpv@research.att.com) */ #ifndef MAP_FAILED #define MAP_FAILED (void*)(-1) #endif #define MM_MAGIC (('V'<<24) | ('M'<<16) | ('A'<<8) | ('P')) #define MM_ROUND (64*1024) #define MM_START ROUND(sizeof(Mmvm_t),ALIGN) typedef struct _user_s { struct _user_s* next; /* link list */ int key; /* identifying key */ Void_t* data; /* data to be returned */ } User_t; typedef struct _mmvm_s { Vmulong_t magic; /* magic bytes */ Void_t* base; /* base of the map */ size_t size; /* current size */ size_t busy; /* amount in use */ size_t round; /* amount to round to */ User_t* user; /* some user data */ } Mmvm_t; typedef struct _mmvmdisc_s { Vmdisc_t disc; /* Vmalloc discipline */ int fd; /* file descriptor */ Mmvm_t* mm; /* mmap data */ } Mmvmdisc_t; #if __STD_C static int mmvminit(char* file, Void_t* addr, size_t round, Mmvm_t* mm) #else static int mmvminit(file, addr, round, mm) char* file; /* file to map data from */ Void_t* addr; /* desired starting address */ size_t round; /* amount to round requests */ Mmvm_t* mm; /* to return some mapped info */ #endif { int fd; off_t size; Void_t *base; Mmvm_t *hdr; base = NIL(Void_t*); if((fd = open(file, O_RDWR, CREAT_MODE)) >= 0) { if((size = lseek(fd, (off_t)0, 2)) < 0) goto done; else if(size == 0) goto new_f; /* read the header */ if(lseek(fd, (off_t)0, 0) != (off_t)0) goto done; if(read(fd, mm, sizeof(Mmvm_t)) != sizeof(Mmvm_t)) goto done; if(mm->magic != MM_MAGIC || !mm->base || (off_t)mm->size != size || mm->busy > mm->size ) goto done; base = (Void_t*)mmap(mm->base, mm->size, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, fd, (off_t)0 ); if(base == (Void_t*)MAP_FAILED) base = NIL(Void_t*); } else { if((fd = open(file, O_RDWR|O_CREAT, CREAT_MODE)) < 0) goto done; new_f: /* create an initial set of data */ size = round; if(lseek(fd, size-1, 0) != (size-1) || write(fd, "", 1) != 1 ) goto done; base = (Void_t*)mmap(addr, (size_t)size, PROT_READ|PROT_WRITE, (addr ? MAP_FIXED : 0)|MAP_SHARED, fd, (off_t)0 ); if(base == (Void_t*)MAP_FAILED) base = NIL(Void_t*); if(!base) goto done; /* write magic number */ hdr = (Mmvm_t*)base; hdr->magic = MM_MAGIC; hdr->base = base; hdr->size = size; hdr->busy = MM_START; hdr->round = round; hdr->user = NIL(User_t*); memcpy(mm, hdr, sizeof(Mmvm_t)); } done: if(!base) { if(fd >= 0) close(fd); fd = -1; } return fd; } #if __STD_C static Void_t* mmvmmemory(Vmalloc_t* vm, Void_t* caddr, size_t csize, size_t nsize, Vmdisc_t* disc) #else static Void_t* mmvmmemory(vm, caddr, csize, nsize, disc) Vmalloc_t* vm; Void_t* caddr; size_t csize; size_t nsize; Vmdisc_t* disc; #endif { Mmvmdisc_t *mmdc = (Mmvmdisc_t*)disc; if(mmdc->fd < 0 || !mmdc->mm) return NIL(Void_t*); #define MMADDR(b) ((Void_t*)(((Vmuchar_t*)b) + MM_START) ) if(caddr && caddr != MMADDR(mmdc->mm->base) ) return NIL(Void_t*); if(nsize < csize) return NIL(Void_t*); if(nsize > mmdc->mm->size-MM_START) { /* base and size of new map */ caddr = mmdc->mm->base; csize = MM_START + nsize + ((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0); csize = ROUND(csize, disc->round); /* make room for new space */ if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) || write(mmdc->fd, "", 1) != 1 ) return NIL(Void_t*); /* remap the space */ (void)munmap(caddr, mmdc->mm->size); caddr = (Void_t*)mmap(caddr, csize, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, mmdc->fd, (off_t)0 ); if(caddr == (Void_t*)MAP_FAILED) caddr = NIL(Void_t*); if(caddr) mmdc->mm->size = csize; else /* bad problem */ { close(mmdc->fd); mmdc->fd = -1; mmdc->mm = NIL(Mmvm_t*); return NIL(Void_t*); } } mmdc->mm->busy = nsize+MM_START; return (Void_t*)(((Vmuchar_t*)mmdc->mm->base) + MM_START); } #if __STD_C static int mmvmexcept(Vmalloc_t* vm, int type, Void_t* data, Vmdisc_t* disc) #else static int mmvmexcept(vm, type, data, disc) Vmalloc_t* vm; int type; Void_t* data; Vmdisc_t* disc; #endif { Mmvmdisc_t *mmdc = (Mmvmdisc_t*)disc; Vmuchar_t *base; if(type == VM_OPEN) { if(mmdc->mm->busy > MM_START) { base = ((Vmuchar_t*)mmdc->mm->base) + MM_START; *((Void_t**)data) = (Void_t*)base; return 1; } else return 0; } else if(type == VM_CLOSE) { (void)munmap(mmdc->mm->base, mmdc->mm->size); (void)close(mmdc->fd); vmfree(Vmheap, mmdc); return 1; /* freeing of mapped data is already done */ } else return 0; } #if __STD_C Vmalloc_t* vmmopen(char* file, Void_t* base, size_t round) #else Vmalloc_t* vmmopen(file, base, round) char* file; /* file mapping data from */ Void_t* base; /* desired starting address */ size_t round; /* amount to round requests */ #endif { Vmalloc_t *vm; Mmvmdisc_t *mmdc; Mmvm_t mm; int fd; if(!file) return NIL(Vmalloc_t*); /* set the amount to round up to on each memory request */ GETPAGESIZE(_Vmpagesize); if(round < MM_ROUND) round = MM_ROUND; round = ROUND(round, _Vmpagesize); if((fd = mmvminit(file, base, round, &mm)) < 0) return NIL(Vmalloc_t*); if(!(mmdc = (Mmvmdisc_t*)vmalloc(Vmheap, sizeof(Mmvmdisc_t))) ) { close(fd); return NIL(Vmalloc_t*); } mmdc->disc.memoryf = mmvmmemory; mmdc->disc.exceptf = mmvmexcept; mmdc->disc.round = mm.round; mmdc->fd = fd; mmdc->mm = (Mmvm_t*)mm.base; if(!(vm = vmopen(&mmdc->disc, Vmbest, VM_TRUST)) ) { mmvmexcept(NIL(Vmalloc_t*), VM_CLOSE, NIL(Void_t*), &mmdc->disc); return NIL(Vmalloc_t*); } return vm; } #if __STD_C Void_t* vmmset(Vmalloc_t* vm, int key, Void_t* data, int set) #else Void_t* vmmset(vm, data, key, set) Vmalloc_t* vm; /* a region based on vmmmopen */ int key; /* key of data to be set */ Void_t* data; /* data to be set */ int set; /* 1 for setting, 0 for getting */ #endif { User_t *u; Mmvm_t *mmvm = ((Mmvmdisc_t*)vm->disc)->mm; for(u = mmvm->user; u; u = u->next) if(u->key == key) break; if(!set) return u ? u->data : NIL(Void_t*); else if(u) { Void_t* old = u->data; u->data = data; return old; } else if(!(u = (User_t*)vmalloc(vm, sizeof(User_t))) ) return NIL(Void_t*); else { u->data = data; u->key = key; u->next = mmvm->user; mmvm->user = u; return data; } } #endif