]> git.draconx.ca Git - cdecl99.git/commitdiff
Avoid recursively calling glthread_once in error init.
authorNick Bowler <nbowler@draconx.ca>
Wed, 29 Feb 2012 01:05:06 +0000 (20:05 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 1 Mar 2012 01:16:59 +0000 (20:16 -0500)
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

index 30a481e49a1bb6ed88a77691a634eaa5862ec32b..8d26d5b7c604db7b4ecde35ffd2985a51f327fb6 100644 (file)
@@ -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);
+}