2012-12-18 16:52:47 +00:00
|
|
|
#include <stdlib.h>
|
2012-12-18 17:01:23 +00:00
|
|
|
#include <stdio.h>
|
2012-12-18 16:52:47 +00:00
|
|
|
#include "jv_alloc.h"
|
|
|
|
|
2013-06-06 17:26:15 -05:00
|
|
|
struct nomem_handler {
|
|
|
|
jv_nomem_handler_f handler;
|
|
|
|
void *data;
|
|
|
|
};
|
|
|
|
|
2014-04-16 18:42:36 -05:00
|
|
|
#if !defined(HAVE_PTHREAD_KEY_CREATE) || \
|
|
|
|
!defined(HAVE_PTHREAD_ONCE) || \
|
|
|
|
!defined(HAVE_ATEXIT)
|
|
|
|
|
|
|
|
/* Try thread-local storage? */
|
|
|
|
|
2013-06-06 17:26:15 -05:00
|
|
|
#ifdef _MSC_VER
|
2014-04-16 18:42:36 -05:00
|
|
|
/* Visual C++: yes */
|
2013-06-06 17:26:15 -05:00
|
|
|
static __declspec(thread) struct nomem_handler nomem_handler;
|
2014-04-16 18:42:36 -05:00
|
|
|
#define USE_TLS
|
2013-06-06 17:26:15 -05:00
|
|
|
#else
|
2014-04-16 18:42:36 -05:00
|
|
|
#ifdef HAVE___THREAD
|
|
|
|
/* GCC and friends: yes */
|
2013-06-06 17:26:15 -05:00
|
|
|
static __thread struct nomem_handler nomem_handler;
|
2014-04-16 18:42:36 -05:00
|
|
|
#define USE_TLS
|
|
|
|
#endif /* HAVE___THREAD */
|
|
|
|
#endif /* _MSC_VER */
|
2013-06-06 17:26:15 -05:00
|
|
|
|
2014-04-16 18:42:36 -05:00
|
|
|
#endif /* !HAVE_PTHREAD_KEY_CREATE */
|
|
|
|
|
|
|
|
#ifdef USE_TLS
|
2013-06-06 17:26:15 -05:00
|
|
|
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
|
|
|
|
nomem_handler.handler = handler;
|
|
|
|
}
|
|
|
|
|
2012-12-18 17:01:23 +00:00
|
|
|
static void memory_exhausted() {
|
2013-06-06 17:26:15 -05:00
|
|
|
if (nomem_handler.handler)
|
|
|
|
nomem_handler.handler(nomem_handler.data); // Maybe handler() will longjmp() to safety
|
|
|
|
// Or not
|
2012-12-18 17:01:23 +00:00
|
|
|
fprintf(stderr, "error: cannot allocate memory\n");
|
|
|
|
abort();
|
|
|
|
}
|
2014-04-16 18:42:36 -05:00
|
|
|
#else /* USE_TLS */
|
|
|
|
|
2013-06-06 17:26:15 -05:00
|
|
|
#ifdef HAVE_PTHREAD_KEY_CREATE
|
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
pthread_key_t nomem_handler_key;
|
|
|
|
pthread_once_t mem_once = PTHREAD_ONCE_INIT;
|
|
|
|
|
2014-04-16 18:42:36 -05:00
|
|
|
static void tsd_fini(void) {
|
|
|
|
struct nomem_handler *nomem_handler;
|
|
|
|
nomem_handler = pthread_getspecific(nomem_handler_key);
|
|
|
|
if (nomem_handler) {
|
|
|
|
(void) pthread_setspecific(nomem_handler_key, NULL);
|
|
|
|
free(nomem_handler);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-06 17:26:15 -05:00
|
|
|
static void tsd_init(void) {
|
|
|
|
if (pthread_key_create(&nomem_handler_key, NULL) != 0) {
|
|
|
|
fprintf(stderr, "error: cannot create thread specific key");
|
|
|
|
abort();
|
|
|
|
}
|
2014-04-16 18:42:36 -05:00
|
|
|
if (atexit(tsd_fini) != 0) {
|
|
|
|
fprintf(stderr, "error: cannot set an exit handler");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler));
|
|
|
|
if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) {
|
|
|
|
fprintf(stderr, "error: cannot set thread specific data");
|
|
|
|
abort();
|
|
|
|
}
|
2013-06-06 17:26:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
|
|
|
|
pthread_once(&mem_once, tsd_init); // cannot fail
|
2014-04-16 18:42:36 -05:00
|
|
|
struct nomem_handler *nomem_handler;
|
|
|
|
|
|
|
|
nomem_handler = pthread_getspecific(nomem_handler_key);
|
2013-06-06 17:26:15 -05:00
|
|
|
if (nomem_handler == NULL) {
|
|
|
|
handler(data);
|
|
|
|
fprintf(stderr, "error: cannot allocate memory\n");
|
|
|
|
abort();
|
|
|
|
}
|
2014-04-16 18:42:36 -05:00
|
|
|
nomem_handler->handler = handler;
|
|
|
|
nomem_handler->data = data;
|
2013-06-06 17:26:15 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void memory_exhausted() {
|
2014-04-16 18:42:36 -05:00
|
|
|
struct nomem_handler *nomem_handler;
|
2013-06-06 17:26:15 -05:00
|
|
|
|
|
|
|
pthread_once(&mem_once, tsd_init);
|
2014-04-16 18:42:36 -05:00
|
|
|
nomem_handler = pthread_getspecific(nomem_handler_key);
|
|
|
|
if (nomem_handler)
|
|
|
|
nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety
|
2013-06-06 17:26:15 -05:00
|
|
|
// Or not
|
|
|
|
fprintf(stderr, "error: cannot allocate memory\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2014-04-16 18:42:36 -05:00
|
|
|
/* No thread-local storage of any kind that we know how to handle */
|
|
|
|
|
2013-06-06 17:26:15 -05:00
|
|
|
static struct nomem_handler nomem_handler;
|
|
|
|
void jv_nomem_handler(jv_nomem_handler_f handler, void *data) {
|
|
|
|
nomem_handler.handler = handler;
|
|
|
|
nomem_handler.data = data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void memory_exhausted() {
|
|
|
|
fprintf(stderr, "error: cannot allocate memory\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_PTHREAD_KEY_CREATE */
|
2014-04-16 18:42:36 -05:00
|
|
|
#endif /* USE_TLS */
|
2013-06-06 17:26:15 -05:00
|
|
|
|
2012-12-18 16:52:47 +00:00
|
|
|
|
|
|
|
void* jv_mem_alloc(size_t sz) {
|
2012-12-18 17:01:23 +00:00
|
|
|
void* p = malloc(sz);
|
|
|
|
if (!p) {
|
|
|
|
memory_exhausted();
|
|
|
|
}
|
|
|
|
return p;
|
2012-12-18 16:52:47 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 17:26:15 -05:00
|
|
|
void* jv_mem_alloc_unguarded(size_t sz) {
|
|
|
|
return malloc(sz);
|
|
|
|
}
|
|
|
|
|
2012-12-18 16:52:47 +00:00
|
|
|
void jv_mem_free(void* p) {
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void* jv_mem_realloc(void* p, size_t sz) {
|
2012-12-18 17:01:23 +00:00
|
|
|
p = realloc(p, sz);
|
|
|
|
if (!p) {
|
|
|
|
memory_exhausted();
|
|
|
|
}
|
|
|
|
return p;
|
2012-12-18 16:52:47 +00:00
|
|
|
}
|
2012-12-24 17:11:18 +00:00
|
|
|
|
2013-05-05 23:12:10 +01:00
|
|
|
#ifndef NDEBUG
|
2012-12-24 17:11:18 +00:00
|
|
|
volatile char jv_mem_uninitialised;
|
|
|
|
__attribute__((constructor)) void jv_mem_uninit_setup(){
|
|
|
|
char* p = malloc(1);
|
|
|
|
jv_mem_uninitialised = *p;
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
#endif
|