X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/beac10d6593fee948759c05d956b83db6803f2ec..1b96e9580714d7a677d10a8e286b3f8a2bddc6f5:/src/error.c diff --git a/src/error.c b/src/error.c index 94987af..0ff31ee 100644 --- a/src/error.c +++ b/src/error.c @@ -20,15 +20,30 @@ #include #include #include +#include #include "cdecl.h" #include "cdecl-internal.h" #include -#include #include "errmsg.h" +#if USE_POSIX_THREADS +# include "thread-posix.h" +#elif USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS +# include "thread-stdc.h" +#elif USE_WINDOWS_THREADS +# include "thread-w32.h" +#else +static void *tls_key; +enum { tls_key_valid = 1 }; + +#define tls_key_init() ((void)0) +#define tls_get() tls_key +#define tls_set(a) (tls_key = (a), 1) +#endif + struct err_state { struct cdecl_error err; size_t nstr; @@ -37,15 +52,6 @@ struct err_state { /* This pre-initialized error is reserved for dire out-of-memory conditions. */ static struct cdecl_error err_no_mem; -static gl_tls_key_t tls_key; - -static void free_err(void *err) -{ - if (err == &err_no_mem) - return; - - free(err); -} static void set_err(unsigned code, struct cdecl_error *err) { @@ -70,7 +76,7 @@ static void initialize_cb(void) bindtextdomain("bison-runtime", BISON_LOCALEDIR); #endif set_err(CDECL__ENOMEM, &err_no_mem); - gl_tls_key_init(tls_key, free_err); + tls_key_init(); } static void *alloc_err_state(void *old, size_t buf_size) @@ -81,16 +87,22 @@ static void *alloc_err_state(void *old, size_t buf_size) state = p = realloc(old, offsetof(struct err_state, str) + buf_size); if (state) { state->nstr = buf_size; + if (!tls_set(state)) { + /* + * We have to presume that pthread_setspecific etc. + * cannot fail after the key has been successfully + * assigned once, because there seems to be no + * reasonable recovery from such a scenario. + */ + free(p); + p = NULL; + } } else if (old) { /* Failed allocation, but existing state is still good */ p = old; - } else { - /* Failed allocation, no existing state */ - p = &err_no_mem; } - gl_tls_set(tls_key, p); - return state; + return p; } static struct err_state *get_err_state(void) @@ -98,12 +110,10 @@ static struct err_state *get_err_state(void) void *state; gl_once_define(static, tls_initialized) - gl_once(tls_initialized, initialize_cb); + if (glthread_once(&tls_initialized, initialize_cb) || !tls_key_valid) + return NULL; - state = gl_tls_get(tls_key); - if (state == &err_no_mem) - state = NULL; - if (!state) + if (!(state = tls_get())) return alloc_err_state(state, 100); return state; } @@ -197,5 +207,5 @@ const struct cdecl_error *cdecl_get_error(void) { struct err_state *state = get_err_state(); - return state ? &state->err : NULL; + return state ? &state->err : &err_no_mem; }