From c9ec41ecea841cac0ad1aa265cdc6859a61c4ac2 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 28 Feb 2012 20:05:06 -0500 Subject: [PATCH] Avoid recursively calling glthread_once in error init. Apparently at least the GNU C library will deadlock when pthread_once is called recursively on the same control variable. This behaviour of the library doesn't seem to be consistent with the POSIX standard, but it's easy enough to avoid in this instance. This can all go away once all the error paths have been updated to cdecl__set_error. --- src/error.c | 63 +++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/error.c b/src/error.c index 30a481e..8d26d5b 100644 --- a/src/error.c +++ b/src/error.c @@ -43,39 +43,11 @@ static void free_err(void *err) free(err); } -static void initialize(void) -{ - cdecl__init_i18n(); - err_no_mem.err.str = cdecl__strerror(CDECL_ENOMEM); - - gl_tls_key_init(tls_key, free_err); - - /* - * This default error message is a stop-gap measure until all library - * error conditions use the new interface. - */ - cdecl__set_error(&(const struct cdecl_error){ .code = CDECL_ENOPARSE }); -} - -const struct cdecl_error *cdecl_get_error(void) -{ - struct err_state *state; - - gl_once(tls_initialized, initialize); - - state = gl_tls_get(tls_key); - assert(state); - - return &state->err; -} - -void cdecl__set_error(const struct cdecl_error *err) +static void set_error(const struct cdecl_error *err) { struct err_state *state; size_t need_len = 0; - gl_once(tls_initialized, initialize); - if (err->str) { need_len = strlen(err->str) + 1; } @@ -111,3 +83,36 @@ void cdecl__set_error(const struct cdecl_error *err) state->err.str = cdecl__strerror(state->err.code); } } + +static void initialize(void) +{ + cdecl__init_i18n(); + err_no_mem.err.str = cdecl__strerror(CDECL_ENOMEM); + + gl_tls_key_init(tls_key, free_err); + + /* + * This default error message is a stop-gap measure until all library + * error conditions use the new interface. + */ + set_error(&(const struct cdecl_error){ .code = CDECL_ENOPARSE }); +} + +const struct cdecl_error *cdecl_get_error(void) +{ + struct err_state *state; + + gl_once(tls_initialized, initialize); + + state = gl_tls_get(tls_key); + assert(state); + + return &state->err; +} + +void cdecl__set_error(const struct cdecl_error *err) +{ + gl_once(tls_initialized, initialize); + + set_error(err); +} -- 2.43.0