175 lines
2.8 KiB
C
175 lines
2.8 KiB
C
/* src/interfaces/ecpg/ecpglib/memory.c */
|
|
|
|
#define POSTGRES_ECPG_INTERNAL
|
|
#include "postgres_fe.h"
|
|
|
|
#include "ecpg-pthread-win32.h"
|
|
#include "ecpgerrno.h"
|
|
#include "ecpglib.h"
|
|
#include "ecpglib_extern.h"
|
|
#include "ecpgtype.h"
|
|
|
|
void
|
|
ecpg_free(void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
char *
|
|
ecpg_alloc(long size, int lineno)
|
|
{
|
|
char *new = (char *) calloc(1L, size);
|
|
|
|
if (!new)
|
|
{
|
|
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
return new;
|
|
}
|
|
|
|
char *
|
|
ecpg_realloc(void *ptr, long size, int lineno)
|
|
{
|
|
char *new = (char *) realloc(ptr, size);
|
|
|
|
if (!new)
|
|
{
|
|
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
return new;
|
|
}
|
|
|
|
char *
|
|
ecpg_strdup(const char *string, int lineno)
|
|
{
|
|
char *new;
|
|
|
|
if (string == NULL)
|
|
return NULL;
|
|
|
|
new = strdup(string);
|
|
if (!new)
|
|
{
|
|
ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
return new;
|
|
}
|
|
|
|
/* keep a list of memory we allocated for the user */
|
|
struct auto_mem
|
|
{
|
|
void *pointer;
|
|
struct auto_mem *next;
|
|
};
|
|
|
|
#ifdef ENABLE_THREAD_SAFETY
|
|
static pthread_key_t auto_mem_key;
|
|
static pthread_once_t auto_mem_once = PTHREAD_ONCE_INIT;
|
|
|
|
static void
|
|
auto_mem_destructor(void *arg)
|
|
{
|
|
(void) arg; /* keep the compiler quiet */
|
|
ECPGfree_auto_mem();
|
|
}
|
|
|
|
static void
|
|
auto_mem_key_init(void)
|
|
{
|
|
pthread_key_create(&auto_mem_key, auto_mem_destructor);
|
|
}
|
|
|
|
static struct auto_mem *
|
|
get_auto_allocs(void)
|
|
{
|
|
pthread_once(&auto_mem_once, auto_mem_key_init);
|
|
return (struct auto_mem *) pthread_getspecific(auto_mem_key);
|
|
}
|
|
|
|
static void
|
|
set_auto_allocs(struct auto_mem *am)
|
|
{
|
|
pthread_setspecific(auto_mem_key, am);
|
|
}
|
|
#else
|
|
static struct auto_mem *auto_allocs = NULL;
|
|
|
|
#define get_auto_allocs() (auto_allocs)
|
|
#define set_auto_allocs(am) do { auto_allocs = (am); } while(0)
|
|
#endif
|
|
|
|
char *
|
|
ecpg_auto_alloc(long size, int lineno)
|
|
{
|
|
void *ptr = (void *) ecpg_alloc(size, lineno);
|
|
|
|
if (!ptr)
|
|
return NULL;
|
|
|
|
if (!ecpg_add_mem(ptr, lineno))
|
|
{
|
|
ecpg_free(ptr);
|
|
return NULL;
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
bool
|
|
ecpg_add_mem(void *ptr, int lineno)
|
|
{
|
|
struct auto_mem *am = (struct auto_mem *) ecpg_alloc(sizeof(struct auto_mem), lineno);
|
|
|
|
if (!am)
|
|
return false;
|
|
|
|
am->pointer = ptr;
|
|
am->next = get_auto_allocs();
|
|
set_auto_allocs(am);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
ECPGfree_auto_mem(void)
|
|
{
|
|
struct auto_mem *am = get_auto_allocs();
|
|
|
|
/* free all memory we have allocated for the user */
|
|
if (am)
|
|
{
|
|
do
|
|
{
|
|
struct auto_mem *act = am;
|
|
|
|
am = am->next;
|
|
ecpg_free(act->pointer);
|
|
ecpg_free(act);
|
|
} while (am);
|
|
set_auto_allocs(NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
ecpg_clear_auto_mem(void)
|
|
{
|
|
struct auto_mem *am = get_auto_allocs();
|
|
|
|
/* only free our own structure */
|
|
if (am)
|
|
{
|
|
do
|
|
{
|
|
struct auto_mem *act = am;
|
|
|
|
am = am->next;
|
|
ecpg_free(act);
|
|
} while (am);
|
|
set_auto_allocs(NULL);
|
|
}
|
|
}
|