specks.c 6.14 KiB
#define _XOPEN_SOURCE 500 /* for UNIX98 pthread mutexes */
#include <errno.h>
#include "specks.h"
#include "shmem.h"
/* only safe if lock held */
static struct specklist **specks_timespecksptr( struct stuff *, int dataset, int timestep );
#ifdef HAVE_PTHREAD_H
void specks_lock_init( struct stuff *st )
{
static pthread_mutexattr_t ma;
pthread_mutexattr_init( &ma );
pthread_mutexattr_settype( &ma, PTHREAD_MUTEX_ERRORCHECK );
pthread_mutex_init( &st->smut, &ma );
pthread_mutexattr_destroy( &ma );
}
void specks_lock( struct stuff *st )
{
int e = pthread_mutex_lock( &st->smut );
if(e != 0) {
fprintf(stderr, "specks_lock(%p): %s\n", st, strerror(e));
}
}
void specks_unlock( struct stuff *st )
{
int e = pthread_mutex_unlock( &st->smut );
if(e != 0) {
fprintf(stderr, "specks_unlock(%p): %s\n", st, strerror(e));
}
}
#else /* no pthreads */
void specks_lock_init( struct stuff *st ) {}
void specks_lock( struct stuff *st ) {}
void specks_unlock( struct stuff *st ) {}
#endif
struct specklist *specks_timespecks( struct stuff *st, int dataset, int timestep )
{
struct specklist *sl;
specks_lock( st );
sl = (timestep >= 0 && timestep < st->ntimes &&
dataset >= 0 && dataset < st->ndata)
? st->anima[dataset][timestep] : NULL;
specks_unlock( st );
return sl;
}
void specks_insertspecks( struct stuff *st, int dataset, int timestep, struct specklist *sl )
{
struct specklist **slp;
if(dataset < 0 || timestep < 0)
return;
specks_ensuretime( st, dataset, timestep );
specks_lock( st );
slp = &st->anima[dataset][timestep];
sl->next = *slp;
*slp = sl;
specks_unlock( st );
}
static void specks_freenow( struct specklist **slp )
{
struct specklist *sl, **sprev;
int any = 0;
for(sprev = slp; (sl = *sprev) != NULL; ) {
*sprev = sl->next;
if(sl->specks != NULL)
Free(sl->specks);
Free(sl);
}
}
static int specks_freeoldscrap( struct specklist **slp, int maxage )
{
struct specklist *sl, **sprev;
int any = 0;
for(sprev = slp; (sl = *sprev) != NULL && sl->used <= maxage; ) {
if(sl->used <= maxage) {
*sprev = sl->freelink;
if(sl->specks != NULL)
Free(sl->specks);
Free(sl);
any++;
} else {
/* too recent - might still be in use */
sprev = &sl->freelink;
}
}
return any;
}
void specks_discard( struct stuff *st, struct specklist **slp )
{
struct specklist *sl, *slnext;
for(sl = *slp; sl != NULL; sl = slnext) {
slnext = sl->next;
sl->freelink = st->scrap;
st->scrap = sl;
}
*slp = NULL;
}
int specks_purge( void *vst, int nbytes, void *aarena )
{
struct stuff *st = (struct stuff *)vst;
int oldused = st->used;
int oldtime = -1, oldds = -1;
int t, ds;
struct specklist *sl;
#ifdef sgi
static int first = 1;
struct mallinfo mi;
mi = amallinfo( aarena );
if(first) {
first = 0;
msg("Purging %dKbyte shmem arena (currently %dK used in %d blks, %dK free)\n",
mi.arena>>10, mi.uordblks>>10, mi.ordblks, mi.fordblks>>10);
}
#endif
/* Free any known scrap first */
#define OLD_ENOUGH 4
if(specks_freeoldscrap( &st->scrap, st->used - OLD_ENOUGH ) > 0)
return 1;
for(t = 0; t < st->ntimes; t++) {
if(t == st->curtime) continue;
for(ds = 0; ds < st->ndata; ds++) {
sl = st->anima[ds][t];
if(sl != NULL && sl != st->sl && sl->used < oldused) {
oldused = st->used;
oldtime = t;
oldds = ds;
}
}
}
if(oldtime >= 0) {
specks_discard( st, &st->anima[oldds][oldtime] );
specks_freeoldscrap( &st->scrap, oldtime );
return 1; /* We freed something, so try allocating again */
} else {
msg("Ran out of shmem, couldn't find anything more to purge\n");
#ifdef sgi
msg("%dKbyte shmem arena (currently %dK used in %d blks, %dK free)\n",
mi.arena>>10, mi.uordblks>>10, mi.ordblks, mi.fordblks>>10);
#endif
return 0; /* No progress made -- give up */
}
}
static struct specklist **specks_scraptail( struct stuff *st )
{
struct specklist **slp = &st->scrap;
while(*slp)
slp = &(*slp)->freelink;
return slp;
}
void specks_clearspecks( struct stuff *st, int dataset, int timestep )
{
struct specklist **slp;
if(st->anima == NULL || st->anima[dataset] == NULL)
return;
specks_lock(st);
slp = &st->anima[dataset][timestep];
if(*slp == st->frame_sl) {
/* in use -- add to purge-list */
specks_discard( st, slp );
} else {
specks_freenow( slp );
}
specks_unlock(st);
}
void specks_ensuretime( struct stuff *st, int dataset, int timestep )
{
int d, needroom;
struct specklist **na, **nan;
void **ndf;
char **nfn;
struct mesh **nmesh;
if(timestep < st->ntimes)
return;
specks_lock( st );
if((timestep >= st->ntimes || dataset >= st->ndata)) {
needroom = st->timeroom;
if(timestep >= st->timeroom)
needroom = 2*timestep + 15;
for(d = 0; d < st->ndata || (dataset < MAXFILES && d <= dataset); d++) {
if(needroom == st->timeroom && d < st->ndata)
continue;
na = NewN( struct specklist *, needroom );
nan = NewN( struct specklist *, needroom );
ndf = NewN( void *, needroom );
nfn = NewN( char *, needroom );
nmesh = NewN( struct mesh *, needroom );
memset(na, 0, needroom * sizeof(*na));
memset(nan, 0, needroom * sizeof(*nan));
memset(ndf, 0, needroom * sizeof(*ndf));
memset(nfn, 0, needroom * sizeof(*nfn));
memset(nmesh, 0, needroom * sizeof(*nmesh));
if(d < st->ndata && st->anima[d])
memcpy( na, st->anima[d], st->ntimes * sizeof(*na) );
if(d < st->ndata && st->annot[d])
memcpy( nan, st->annot[d], st->ntimes * sizeof(*nan) );
if(d < st->ndata && st->datafile[d])
memcpy( ndf, st->datafile[d], st->ntimes * sizeof(*ndf) );
if(d < st->ndata && st->fname[d])
memcpy( nfn, st->fname[d], st->ntimes * sizeof(*nfn) );
if(d < st->ndata && st->meshes[d])
memcpy( nmesh, st->meshes[d], st->ntimes * sizeof(*nfn) );
/* Don't free old pointers, just in case they're in use. */
st->anima[d] = na;
st->annot[d] = nan;
st->datafile[d] = ndf;
st->fname[d] = nfn;
st->meshes[d] = nmesh;
}
st->timeroom = needroom;
if(timestep >= st->ntimes)
st->ntimes = timestep + 1;
if(dataset >= st->ndata && dataset < MAXFILES)
st->ndata = dataset + 1;
}
specks_unlock( st );
}