mirror of https://github.com/ecmwf/eccodes.git
398 lines
7.1 KiB
C
398 lines
7.1 KiB
C
/*
|
|
* Copyright 2005-2016 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
|