eccodes/src/grib_memory.c

398 lines
7.1 KiB
C

/*
* Copyright 2005-2018 ECMWF.
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
* virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
*/
#include "grib_api_internal.h"
/* #define CHECK_FOR_LEAKS */
#if MANAGE_MEM
#if GRIB_PTHREADS
static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static void init() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&mutex,&attr);
pthread_mutexattr_destroy(&attr);
}
#elif GRIB_OMP_THREADS
static int once = 0;
static omp_nest_lock_t mutex;
static void init()
{
GRIB_OMP_CRITICAL(lock_grib_memory_c)
{
if (once == 0)
{
omp_init_nest_lock(&mutex);
once = 1;
}
}
}
#endif
union align {
double d;
int n;
void * p;
long l;
};
#define WORD sizeof(union align)
static size_t page_size = 0;
typedef struct {
int pages; /* Number of pages to allocate */
int clear; /* clear newly allocated memory */
int first; /* Allocate in first only */
void *priv;
} mempool;
typedef struct memblk {
struct memblk *next;
long cnt;
size_t left;
size_t size;
char buffer[WORD];
} memblk;
static memblk *reserve = NULL;
/*
typedef struct memprocs {
struct memprocs *next;
memproc proc;
void *data;
} memprocs;
static memprocs *mprocs = NULL;
*/
#define HEADER_SIZE (sizeof(memblk) - WORD)
static mempool _transient_mem = {
10,
0,
1,
};
static mempool *transient_mem = &_transient_mem;
static mempool _permanent_mem = {
10,
0,
1,
};
static mempool *permanent_mem = &_permanent_mem;
static void *fast_new(size_t s,mempool *pool)
{
char *p;
memblk *m;
GRIB_MUTEX_INIT_ONCE(&once,&init)
GRIB_MUTEX_LOCK(&mutex)
m = (memblk*)pool->priv;
/* align */
s = ((s+WORD-1)/WORD)*WORD;
if(pool->first)
{
if(m && (m->left < s))
m = NULL;
}
while(m && (m->left < s))
m = m->next;
if(m == NULL)
{
memblk *p;
size_t size;
if(!page_size) page_size = getpagesize();
size = page_size*pool->pages;
if(s > size - HEADER_SIZE)
{
/* marslog(LOG_WARN,"Object of %d bytes is too big for grib_fast_new",s); */
/* marslog(LOG_WARN,"Block size if %d bytes", size - HEADER_SIZE); */
size = ((s + HEADER_SIZE + (page_size-1)) / page_size) * page_size;
}
p = (memblk*)(pool->clear?calloc(size,1):malloc(size));
if(!p) {
GRIB_MUTEX_UNLOCK(&mutex)
return NULL;
}
p->next = (memblk*)pool->priv;
p->cnt = 0;
p->size = p->left = size-HEADER_SIZE;
m = p;
pool->priv = (void*)p;
}
p = &m->buffer[m->size - m->left];
m->left -= s;
m->cnt++;
GRIB_MUTEX_UNLOCK(&mutex)
return p;
}
static void fast_delete(void *p,mempool *pool)
{
memblk *m ;
memblk *n = NULL;
GRIB_MUTEX_INIT_ONCE(&once,&init)
GRIB_MUTEX_LOCK(&mutex)
m = (memblk*)pool->priv;
while(m)
{
if( ((char*)p >= (char*)&m->buffer[0]) &&
((char*)p < (char*)&m->buffer[m->size]))
{
m->cnt--;
if(m->cnt == 0)
{
if(n) n->next = m->next;
else pool->priv = (void*)m->next;
free((void*)m);
}
GRIB_MUTEX_UNLOCK(&mutex)
return;
}
n = m;
m = m->next;
}
Assert(1==0);
}
static void *fast_realloc(void *p,size_t s,mempool *pool)
{
void *q;
/* I'll come back here later... */
if((q = fast_new(s,pool)) == NULL) return NULL;
memcpy(q,p,s);
fast_delete(p,pool);
return q;
}
#if 0
/*
void fast_memory_info(const char *title,mempool *pool)
{
memblk *m = (memblk*)pool->priv;
int count = 0;
int size = 0;
while(m)
{
count++;
size += m->size;
m = m->next;
}
marslog(LOG_INFO,"%s : %sbytes %d blocks",
title,
bytename(size),count);
}
void memory_info()
{
memblk *r = reserve;
long size = 0;
while(r)
{
marslog(LOG_INFO,"Large buffer: %sbytes %s",
bytename(r->size),r->cnt?"in use":"free");
size += r->size;
r = r->next;
}
marslog(LOG_INFO,"Total large : %sbytes",bytename(size));
fast_memory_info("Transient memory",transient_mem);
fast_memory_info("Permanent memory",permanent_mem);
}
*/
#endif
void *grib_transient_malloc(const grib_context* c,size_t s)
{
return fast_new(s,transient_mem);
}
void *grib_transient_realloc(const grib_context* c,void *p,size_t s)
{
return fast_realloc(p,s,transient_mem);
}
void grib_transient_free(const grib_context* c,void* p)
{
fast_delete(p,transient_mem);
}
void *grib_permanent_malloc(const grib_context* c,size_t s)
{
return fast_new(s,permanent_mem);
}
void *grib_permanent_realloc(const grib_context* c,void *p,size_t s)
{
return fast_realloc(p,s,permanent_mem);
}
void grib_permanent_free(const grib_context* c,void* p)
{
fast_delete(p,permanent_mem);
}
void *grib_buffer_malloc(const grib_context* c,size_t s)
{
memblk *r;
GRIB_MUTEX_INIT_ONCE(&once,&init)
GRIB_MUTEX_LOCK(&mutex)
s = ((s+WORD-1)/WORD)*WORD;
r = reserve;
while(r)
{
if(r->cnt == 0 && r->size == s)
break;
r = r->next;
}
if(r)
{
/* marslog(LOG_DBUG,"Reusing %ld bytes %d",s,r->size); */
}
else
{
size_t size = s + HEADER_SIZE;
/* marslog(LOG_DBUG,"Allocating %d (%d)bytes",s,size); */
r = (memblk*)malloc(size);
if(!r) return NULL;
r->next = reserve;
reserve = r;
}
r->size = s;
r->cnt = 1;
GRIB_MUTEX_UNLOCK(&mutex)
return &r->buffer[0];
}
void grib_buffer_free(const grib_context* c,void *p)
{
memblk *r;
memblk *s;
GRIB_MUTEX_INIT_ONCE(&once,&init)
GRIB_MUTEX_LOCK(&mutex)
r = (memblk*)(((char*)p) - HEADER_SIZE);
s = reserve;
while(s && (s!=r)) s = s->next;
if(s == NULL)
; /* marslog(LOG_WARN,"release_mem: invalid pointer"); */
else
{
s->cnt = 0;
}
GRIB_MUTEX_UNLOCK(&mutex)
}
void *grib_buffer_realloc(const grib_context* c,void *p,size_t s)
{
memblk *r = (memblk*)(((char*)p) - HEADER_SIZE);
void * n = grib_buffer_malloc(c,s);
memcpy(n,p,r->size < s? r->size:s);
grib_buffer_free(c,p);
return n;
}
/*
int purge_mem(void)
{
memblk *p = reserve;
memblk *q = NULL;
while(p)
{
if(p->cnt == 0)
{
if(q) q->next = p->next;
else reserve = p->next;
free(p);
return 1;
}
q = p;
p = p->next;
}
return 0;
}
void install_memory_proc(memproc proc,void *data)
{
memprocs *p = NEW_CLEAR(memprocs);
p->proc = proc;
p->data = data;
p->next = mprocs;
mprocs = p;
}
void remove_memory_proc(memproc proc,void *data)
{
memprocs *p = mprocs;
memprocs *q = NULL;
while(p)
{
if(p->proc == proc && p->data == data)
{
if(q) q->next = p->next; else mprocs = p->next;
FREE(p);
return;
}
q = p;
p = p->next;
}
marslog(LOG_WARN,"remove_memory_proc: cannot find proc");
}
*/
#endif