diff options
Diffstat (limited to 'sys/src/cmd/upas/fs/seg.c')
-rw-r--r-- | sys/src/cmd/upas/fs/seg.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/sys/src/cmd/upas/fs/seg.c b/sys/src/cmd/upas/fs/seg.c new file mode 100644 index 000000000..394b66ad3 --- /dev/null +++ b/sys/src/cmd/upas/fs/seg.c @@ -0,0 +1,164 @@ +#include "common.h" +#include <libsec.h> +#include "dat.h" + +/* + * unnatural acts with virtual memory + */ + +typedef struct{ + int ref; + char *va; + long sz; +}S; + +static S s[15]; /* 386 only gives 4 */ +static int nstab = nelem(s); +static long ssem = 1; +//static ulong thresh = 10*1024*1024; +static ulong thresh = 1024; + +void* +segmalloc(ulong sz) +{ + int i, j; + void *va; + + if(sz < thresh) + return emalloc(sz); + semacquire(&ssem, 1); + for(i = 0; i < nstab; i++) + if(s[i].ref == 0) + goto found; +notfound: + /* errstr not informative; assume we hit seg limit */ + for(j = nstab - 1; j >= i; j--) + if(s[j].ref) + break; + nstab = j; + semrelease(&ssem, 1); + return emalloc(sz); +found: + /* + * the system doesn't leave any room for expansion + */ + va = segattach(SG_CEXEC, "memory", 0, sz + sz/10 + 4096); + if(va == 0) + goto notfound; + s[i].ref++; + s[i].va = va; + s[i].sz = sz; + semrelease(&ssem, 1); + memset(va, 0, sz); + return va; +} + +void +segmfree(void *va) +{ + char *a; + int i; + + a = va; + for(i = 0; i < nstab; i++) + if(s[i].va == a) + goto found; + free(va); + return; +found: + semacquire(&ssem, 1); + s[i].ref--; + s[i].va = 0; + s[i].sz = 0; + semrelease(&ssem, 1); +} + +void* +segreallocfixup(int i, ulong sz) +{ + char buf[ERRMAX]; + void *va, *ova; + + rerrstr(buf, sizeof buf); + if(strstr(buf, "segments overlap") == 0) + sysfatal("segibrk: %r"); + va = segattach(SG_CEXEC, "memory", 0, sz); + if(va == 0) + sysfatal("segattach: %r"); + ova = s[i].va; +fprint(2, "fix memcpy(%p, %p, %lud)\n", va, ova, s[i].sz); + memcpy(va, ova, s[i].sz); + s[i].va = va; + s[i].sz = sz; + segdetach(ova); + return va; +} + +void* +segrealloc(void *va, ulong sz) +{ + char *a; + int i; + ulong sz0; + +fprint(2, "segrealloc %p %lud\n", va, sz); + if(va == 0) + return segmalloc(sz); + a = va; + for(i = 0; i < nstab; i++) + if(s[i].va == a) + goto found; + if(sz >= thresh) + if(a = segmalloc(sz)){ + sz0 = msize(va); + memcpy(a, va, sz0); +fprint(2, "memset(%p, 0, %lud)\n", a + sz0, sz - sz0); + memset(a + sz0, 0, sz - sz0); + return a; + } + return realloc(va, sz); +found: + sz0 = s[i].sz; +fprint(2, "segbrk(%p, %p)\n", s[i].va, s[i].va + sz); + va = segbrk(s[i].va, s[i].va + sz); + if(va == (void*)-1 || va < end) + return segreallocfixup(i, sz); + a = va; + if(sz > sz0) +{ +fprint(2, "memset(%p, 0, %lud)\n", a + sz0, sz - sz0); + memset(a + sz0, 0, sz - sz0); +} + s[i].va = va; + s[i].sz = sz; + return va; +} + +void* +emalloc(ulong n) +{ + void *p; +fprint(2, "emalloc %lud\n", n); + p = mallocz(n, 1); + if(!p) + sysfatal("malloc %lud: %r", n); + setmalloctag(p, getcallerpc(&n)); + return p; +} + +void +main(void) +{ + char *p; + int i; + ulong sz; + + p = 0; + for(i = 0; i < 6; i++){ + sz = i*512; + p = segrealloc(p, sz); + memset(p, 0, sz); + } + segmfree(p); + exits(""); +} |