1
0
Files
irix-657m-src/eoe/cmd/rfind/lib/heap.c
2022-09-29 17:59:04 +03:00

259 lines
7.6 KiB
C

#include <sys/param.h>
#include <sys/immu.h>
#include <sys/syssgi.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <strings.h>
#include "fsdump.h"
#include "pagesize.h"
#include <sys/resource.h>
#include <errno.h>
/*
* PtoD:
* converts Pointer to heap base (e.g. &mhnew.hp_inum) TO that heaps Descriptor (des_t *)
* Cheats: assumes that des_t is right after pun_t. See struct memory_heap layout.
*/
#define PtoD(hpp) ((des_t *)((pun_t *)(hpp) + 1))
/*
* Heap management routines:
* roundup -- rounds up the amount to allocate to a heap by 1 to 2 pages.
* init -- calloc space for estimated size of heap and setup heap struct
* reinit -- realloc space for a larger size heap
* finit -- initialize memory heap from mmap'd file
* alloc -- get space from within heap, adjust heap struct
* realloc -- grow item on heap, perhaps allocating new space, copying over
* shrink -- just moves top down to specified value - within current space.
* bsize -- return size in bytes of portion of heap alloc'd so far.
* btop -- return total number of bytes (alloc'd or not) on heap.
* nsize -- return size in number of allocated elements of heap.
* ntop -- return total number of elements (alloc'd or not) on heap.
*/
#include <pagesize.h>
static hpindex_t heaproundup (hpindex_t nel, uint64_t sz) {
uint64_t nbytes = nel * sz;
nbytes = ctob (btoc(nbytes) + 1);
return nbytes / sz;
}
void heapinit (void **hpp, hpindex_t top, uint64_t sz) {
des_t *dp = PtoD (hpp);
top = heaproundup (top, sz);
if ((*hpp = calloc (top, sz)) == NULL) {
printf ("heapinit: no memory : %lld of size %lld\n", top, sz);
error ("no memory");
}
dp->hd_elsz = sz;
dp->hd_next = 0;
dp->hd_top = top;
dp->hd_mflg = MALC;
}
static void heapreinit (void **hpp, hpindex_t oldtop, hpindex_t newtop) {
des_t *dp = PtoD (hpp);
uint64_t sz = dp->hd_elsz;
uint64_t nbytes;
void *oldhp;
newtop = heaproundup (newtop, sz);
nbytes = newtop * sz;
if (dp->hd_mflg == MALC) {
oldhp = *hpp;
if ((*hpp = realloc (*hpp, nbytes)) == NULL) {
printf ("heapreinit: realloc: no memory: size %lld\n", nbytes);
error ("no memory");
}
} else {
oldhp = *hpp;
if ((*hpp = calloc (newtop, sz)) == NULL) {
printf ("heapreinit: calloc: no memory: %lld %lld size %lld\n", oldtop, newtop, sz);
error ("no memory");
}
bcopy (oldhp, *hpp, oldtop*sz);
dp->hd_mflg = MALC;
}
if (newtop > dp->hd_top)
bzero ((char *)(*hpp) + sz * dp->hd_top, nbytes - sz * dp->hd_top);
dp->hd_top = newtop;
}
void heapfinit (
void **hpp, /* address of heap base */
char *mapaddr, /* base of mmap'd buffer == base of fsdump file */
uint64_t boff, /* base offset in buffer of this heap */
uint64_t toff, /* top offset (end) in buffer of this heap */
uint64_t elsz, /* size of each element in this heap */
uint64_t bsize /* number of bytes of alloc'd elements */
) {
des_t *dp = PtoD (hpp);
dp->hd_elsz = elsz;
dp->hd_next = bsize/elsz;
dp->hd_top = (toff - boff)/elsz;
dp->hd_mflg = MMAP;
*hpp = mapaddr + boff;
}
hpindex_t heapalloc (void **hpp, hpindex_t nel) {
des_t *dp = PtoD (hpp);
hpindex_t newndx;
newndx = dp->hd_next;
if (dp->hd_next + nel > dp->hd_top)
heapreinit (hpp, dp->hd_next, dp->hd_next + nel);
dp->hd_next += nel;
return newndx;
}
hpindex_t heaprealloc (void **hpp, hpindex_t oldndx, hpindex_t oldnel, hpindex_t incrnel) {
des_t *dp = PtoD (hpp);
hpindex_t newndx;
if (oldndx + oldnel == dp->hd_next) {
if (dp->hd_next + incrnel > dp->hd_top)
heapreinit (hpp, dp->hd_next, dp->hd_next + incrnel);
newndx = oldndx;
dp->hd_next += incrnel;
} else {
uint64_t sz = dp->hd_elsz;
void *oldbp;
void *newbp;
if (dp->hd_next + oldnel + incrnel > dp->hd_top)
heapreinit (hpp, dp->hd_next, dp->hd_next + oldnel + incrnel);
newndx = dp->hd_next;
dp->hd_next += oldnel + incrnel;
oldbp = (void *)(*(char **)hpp + sz * oldndx);
newbp = (void *)(*(char **)hpp + sz * newndx);
if (oldnel == 1 && sz == sizeof(uint64_t)) {
*(uint64_t *)newbp = *(uint64_t *)oldbp;
*(uint64_t *)oldbp = NULL;
} else if (oldnel != 0) {
bcopy (oldbp, newbp, sz*oldnel);
bzero (oldbp, sz*oldnel);
}
}
return newndx;
}
void heapshrink (void **hpp, hpindex_t nel) {
des_t *dp = PtoD (hpp);
dp->hd_next = dp->hd_top = nel;
return;
}
uint64_t heapbsize (void **hpp) { /* allocated heap byte size */
des_t *dp = PtoD (hpp);
return dp->hd_elsz * dp->hd_next;
}
hpindex_t heapnsize (void **hpp) { /* number allocated elements in heap */
des_t *dp = PtoD (hpp);
return dp->hd_next;
}
hpindex_t heapntop (void **hpp) { /* total number elements available */
des_t *dp = PtoD (hpp);
return dp->hd_top;
}
static void xheapreinit (void **hpp, hpindex_t oldtop, hpindex_t newtop) {
des_t *dp = PtoD (hpp);
uint64_t sz = dp->hd_elsz;
void *oldhp;
int fd;
newtop = heaproundup (newtop, sz);
if (dp->hd_mflg != MMPA) {
size_t heapgrowth;
oldhp = *hpp;
if ((fd = open ("/dev/zero", O_RDWR)) < 0) {
error ("cannot open temp file");
}
/* Hardcoded 4 Gbyte limit -- this code logic doesn't handle growing fenv twice.
* fsdump dumps core if fenv exceeds this limit (as it did July 98, on the file
* system bonnie.engr.sgi.com:/disks/patches, with older 300 Mb limit). It might
* be that limit can be set much higher than 4 Gb -- don't know. -- pj
*/
#if (_MIPS_SZLONG == 32)
heapgrowth = 300000000;
#else
heapgrowth = 0x100000000LL; /* 4 Gbyte */
#endif
*hpp = mmap ((void *)0, heapgrowth, (PROT_READ|PROT_WRITE),
MAP_PRIVATE|MAP_AUTOGROW|MAP_AUTORESRV, fd, 0);
if (*hpp == (char *)MAP_FAILED) {
/* See further PV Incident 754183 for explanation */
rlim_t vmemory;
extern int errno;
int mmap_errno = errno;
struct rlimit rl;
if (getrlimit (RLIMIT_VMEM, &rl) == 0)
vmemory = rl.rlim_cur;
else
vmemory = heapgrowth;
if (mmap_errno == ENOMEM && vmemory < heapgrowth) {
fprintf (stderr, "fsdump unable to mmap %lld bytes,\n",
(long long) heapgrowth);
fprintf (stderr, "\tbecause rlimit vmemory is only %lld bytes.\n",
(long long) vmemory);
error ("fsdump mmap autogrow #2 failed: ulimit vmemory set too low");
} else {
error("error in mmap autogrow #2");
}
}
bcopy (oldhp, *hpp, oldtop*sz);
dp->hd_mflg = MMPA;
}
dp->hd_top = newtop;
}
hpindex_t xheaprealloc (void **hpp, hpindex_t oldndx, hpindex_t oldnel, hpindex_t incrnel) {
des_t *dp = PtoD (hpp);
hpindex_t newndx;
if (oldndx + oldnel == dp->hd_next) {
if (dp->hd_next + incrnel > dp->hd_top)
xheapreinit (hpp, dp->hd_next, dp->hd_next + incrnel);
newndx = oldndx;
dp->hd_next += incrnel;
} else {
uint64_t sz = dp->hd_elsz;
void *oldbp;
void *newbp;
if (dp->hd_next + oldnel + incrnel > dp->hd_top) {
xheapreinit (hpp, dp->hd_next, dp->hd_next + oldnel + incrnel);
newbp = (void *)(*(char **)hpp + sz * (dp->hd_top - 1));
}
newndx = dp->hd_next;
dp->hd_next += oldnel + incrnel;
oldbp = (void *)(*(char **)hpp + sz * oldndx);
newbp = (void *)(*(char **)hpp + sz * newndx);
if (oldnel == 1 && sz == sizeof(uint64_t)) {
*(uint64_t *)newbp = *(uint64_t *)oldbp;
*(uint64_t *)oldbp = NULL;
} else if (oldnel != 0) {
bcopy (oldbp, newbp, sz*oldnel);
bzero (oldbp, sz*oldnel);
}
}
return newndx;
}