eccodes/src/grib_memory.c

394 lines
7.6 KiB
C

/*
* (C) Copyright 2005- 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