diff --git a/src/jv_alloc.c b/src/jv_alloc.c index 42a18c59..678335c7 100644 --- a/src/jv_alloc.c +++ b/src/jv_alloc.c @@ -45,9 +45,11 @@ static void memory_exhausted() { #ifdef HAVE_PTHREAD_KEY_CREATE #include -pthread_key_t nomem_handler_key; -pthread_once_t mem_once = PTHREAD_ONCE_INIT; +static pthread_key_t nomem_handler_key; +static pthread_once_t mem_once = PTHREAD_ONCE_INIT; +/* tsd_fini is called on application exit */ +/* it clears the nomem_handler allocated in the main thread */ static void tsd_fini(void) { struct nomem_handler *nomem_handler; nomem_handler = pthread_getspecific(nomem_handler_key); @@ -57,8 +59,15 @@ static void tsd_fini(void) { } } +/* The tsd_fini_thread is a destructor set by calling */ +/* pthread_key_create(&nomem_handler_key, tsd_fini_thread) */ +/* It is called when thread ends */ +static void tsd_fini_thread(void *nomem_handler) { + free(nomem_handler); +} + static void tsd_init(void) { - if (pthread_key_create(&nomem_handler_key, NULL) != 0) { + if (pthread_key_create(&nomem_handler_key, tsd_fini_thread) != 0) { fprintf(stderr, "jq: error: cannot create thread specific key"); abort(); } @@ -66,15 +75,23 @@ static void tsd_init(void) { fprintf(stderr, "jq: 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, "jq: error: cannot set thread specific data"); - abort(); +} + +static void tsd_init_nomem_handler(void) +{ + if (pthread_getspecific(nomem_handler_key) == NULL) { + struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler)); + if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) { + fprintf(stderr, "jq: error: cannot set thread specific data"); + abort(); + } } } void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { pthread_once(&mem_once, tsd_init); // cannot fail + tsd_init_nomem_handler(); + struct nomem_handler *nomem_handler; nomem_handler = pthread_getspecific(nomem_handler_key); @@ -91,6 +108,8 @@ static void memory_exhausted() { struct nomem_handler *nomem_handler; pthread_once(&mem_once, tsd_init); + tsd_init_nomem_handler(); + nomem_handler = pthread_getspecific(nomem_handler_key); if (nomem_handler) nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety