#if defined(_UWIN) && defined(_BLD_ast)
void _STUB_vmmopen(){}
#else
#include "vmhdr.h"
#if _sys_stat
#include <sys/stat.h>
#endif
#include <fcntl.h>
#ifdef S_IRUSR
#define CREAT_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
#else
#define CREAT_MODE 0644
#endif
#if _lib_mmap
#include <sys/mman.h>
#else
#define mmap(a,b,c,d,e,f) MAP_FAILED
#define munmap(a,b) MAP_FAILED
#endif
#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;
int key;
Void_t* data;
} User_t;
typedef struct _mmvm_s
{
Vmulong_t magic;
Void_t* base;
size_t size;
size_t busy;
size_t round;
User_t* user;
} Mmvm_t;
typedef struct _mmvmdisc_s
{
Vmdisc_t disc;
int fd;
Mmvm_t* mm;
} 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;
Void_t* addr;
size_t round;
Mmvm_t* mm;
#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;
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:
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;
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)
{
caddr = mmdc->mm->base;
csize = MM_START + nsize +
((nsize % disc->round) < (disc->round/2) ? disc->round/2 : 0);
csize = ROUND(csize, disc->round);
if(lseek(mmdc->fd, (off_t)(csize-1), 0) != (off_t)(csize-1) ||
write(mmdc->fd, "", 1) != 1 )
return NIL(Void_t*);
(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
{ 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;
}
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;
Void_t* base;
size_t round;
#endif
{
Vmalloc_t *vm;
Mmvmdisc_t *mmdc;
Mmvm_t mm;
int fd;
if(!file)
return NIL(Vmalloc_t*);
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;
int key;
Void_t* data;
int set;
#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