]> git.draconx.ca Git - cdecl99.git/commitdiff
libcdecl: Punt gnulib tls module.
authorNick Bowler <nbowler@draconx.ca>
Tue, 23 Jan 2024 06:40:24 +0000 (01:40 -0500)
committerNick Bowler <nbowler@draconx.ca>
Thu, 25 Jan 2024 05:34:31 +0000 (00:34 -0500)
It seems like the gnulib tls module doesn't actually help much.  Drop
it, and implement suitable shims directly in the error handling code.

It does not look like gnulib performs any feature tests regarding the
TLS functionality: it simply goes and uses the appropriate functions
for the selected API (posix, isoc, windows or none).

With the exception of destructor callbacks, all of these TLS APIs are
essentially identical.

Changing this doesn't fix the problem with TLS destructors on Windows
but it does delete almost 2 kilobytes of disfunctional gnulib code
that purports to implement TLS destructors without actually doing so.

Makefile.am
bootstrap
lib/local/modules/dx-threadlib
src/error.c
src/thread-posix.h [new file with mode: 0644]
src/thread-stdc.h [new file with mode: 0644]
src/thread-w32.h [new file with mode: 0644]

index 4b3ea88b23a89adb753b827fce3cc1d44159d594..f3625c8b941f9e80870b3308aa263a9e9f23da6f 100644 (file)
@@ -32,8 +32,9 @@ EXTRA_DIST = bootstrap $(DX_BASEDIR)/scripts/fix-gnulib.pl m4/gnulib-cache.m4 \
 dist_man_MANS = doc/cdecl99.1 doc/libcdecl.3
 
 noinst_HEADERS = conf_pre.h conf_post.h common/src/help.h common/src/tap.h \
-                 common/src/xtra.h src/cdecl.h src/intconv.h src/scan.h \
-                 src/parse.h src/version.h t/declgen.h t/test.h
+                 common/src/xtra.h src/cdecl.h src/intconv.h src/parse.h \
+                 src/scan.h src/thread-posix.h src/thread-stdc.h \
+                 src/thread-w32.h src/version.h t/declgen.h t/test.h
 
 noinst_DATA = $(MOFILES)
 
index 328bbca7804a8bcab63afa54bfa9bba35c85c4b6..3f3f2a3054e5a0d73a52710814e127ebdf308a77 100755 (executable)
--- a/bootstrap
+++ b/bootstrap
@@ -33,7 +33,7 @@ if test -x $GNULIB/gnulib-tool; then
   exec 3>lib/symfiles.tmp 4<lib/symfiles.tmp
   rm -f lib/symfiles.tmp
 
-  shared_modules='lock tls'
+  shared_modules='lock'
   set x --extract-recursive-dependencies $shared_modules; shift
   (set -x; $GNULIB/gnulib-tool "$@" >&3 ) || die "gnulib-tool failed"
   shared_modules=`LC_ALL=C sort -u <&4`
index 6578fdc9d529f09bb455f63c1221a822687f635d..85699e39b886394b6600637f9667dc9ced095711 100644 (file)
@@ -8,7 +8,6 @@ Depends-on:
 gnulib-local
 threadlib
 lock [test x"$glthreads_api" != x"none"]
-tls  [test x"$glthreads_api" != x"none"]
 
 configure.ac-early:
 dnl AC_REQUIRE has the effect of making the macro expansion unconditional;
index 94987af6a90f3a7eb83ce661a4d87b3c75efb7a8..0ff31ee0a4f6871e5eaadac892aed76c4b2b7878 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #include "cdecl.h"
 #include "cdecl-internal.h"
 
 #include <glthread/lock.h>
-#include <glthread/tls.h>
 
 #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;
 }
diff --git a/src/thread-posix.h b/src/thread-posix.h
new file mode 100644 (file)
index 0000000..b1cd990
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2024 Nick Bowler
+ *
+ * Helpers for hosts using POSIX threading (pthreads) API.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+#if USE_POSIX_THREADS_WEAK
+#  pragma weak pthread_key_create
+#  pragma weak pthread_getspecific
+#  pragma weak pthread_setspecific
+#endif
+
+static struct {
+       union {
+               pthread_key_t mt;
+#if USE_POSIX_THREADS_WEAK
+               void *st;
+#endif
+       } u;
+
+#if USE_POSIX_THREADS_WEAK
+       signed char valid;
+#else
+       bool valid;
+#endif
+} tls_key;
+#define tls_key_valid (tls_key.valid != 0)
+
+static void tls_key_init(void)
+{
+       if (pthread_in_use())
+               tls_key.valid = !pthread_key_create(&tls_key.u.mt, free);
+       else
+               tls_key.valid = -1;
+}
+
+static void *tls_get(void)
+{
+#if USE_POSIX_THREADS_WEAK
+       if (tls_key.valid < 0)
+               return tls_key.u.st;
+#endif
+       return pthread_getspecific(tls_key.u.mt);
+}
+
+static int tls_set(void *p)
+{
+#if USE_POSIX_THREADS_WEAK
+       if (tls_key.valid < 0)
+               return (tls_key.u.st = p, 1);
+#endif
+       return !pthread_setspecific(tls_key.u.mt, p);
+}
diff --git a/src/thread-stdc.h b/src/thread-stdc.h
new file mode 100644 (file)
index 0000000..46fe361
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2024 Nick Bowler
+ *
+ * Helpers for hosts using standard C threading API.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <threads.h>
+
+static tss_t tls_key;
+static bool tls_key_valid;
+
+static void tls_key_init(void)
+{
+       tls_key_valid = (tss_create(&tls_key, free) == thrd_success);
+}
+
+static void *tls_get(void)
+{
+       return tss_get(tls_key);
+}
+
+static int tls_set(void *p)
+{
+       return tss_set(tls_key, p) == thrd_success;
+}
diff --git a/src/thread-w32.h b/src/thread-w32.h
new file mode 100644 (file)
index 0000000..44282d8
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2024 Nick Bowler
+ *
+ * Helpers for hosts using native Windows threading API.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+static DWORD tls_key;
+#define tls_key_valid (tls_key != TLS_OUT_OF_INDEXES)
+
+static void tls_key_init(void)
+{
+       tls_key = TlsAlloc();
+}
+
+static void *tls_get(void)
+{
+       return TlsGetValue(tls_key);
+}
+
+static BOOL tls_set(void *p)
+{
+       return TlsSetValue(tls_key, p);
+}