From: Nick Bowler Date: Wed, 24 Jan 2024 06:19:59 +0000 (-0500) Subject: libcdecl: Punt gnulib lock module. X-Git-Tag: v1.3~24 X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/commitdiff_plain/c11f668ec9c5b2f0016cf6920a111c52e895b24a libcdecl: Punt gnulib lock module. This module is total overkill for what we need, which is to provide one-time library initialization. Except for the pthread_in_use detection, this module does not appear to work around any particular portability problem with POSIX pthread_once or standard C call_once. On the other hand, on GNU/Linux the unused code this module links in represents almost 5% of the size of the entire library (which includes eight pointless PLT entries). We have to make a local copy of the pthread_in_use macro definition, as it is no longer imported into the project. Further improvements may be possible to specialize this test for our use case, but for now stick with the Gnulib version which is known to work on a lot of different systems. --- diff --git a/bootstrap b/bootstrap index 3f3f2a3..02ca644 100755 --- a/bootstrap +++ b/bootstrap @@ -33,7 +33,7 @@ if test -x $GNULIB/gnulib-tool; then exec 3>lib/symfiles.tmp 4&3 ) || die "gnulib-tool failed" shared_modules=`LC_ALL=C sort -u <&4` diff --git a/lib/local/modules/dx-threadlib b/lib/local/modules/dx-threadlib index 85699e3..9499e3b 100644 --- a/lib/local/modules/dx-threadlib +++ b/lib/local/modules/dx-threadlib @@ -7,7 +7,7 @@ Files: Depends-on: gnulib-local threadlib -lock [test x"$glthreads_api" != x"none"] +windows-once [test x"$gl_threads_api" = x"windows"] configure.ac-early: dnl AC_REQUIRE has the effect of making the macro expansion unconditional; diff --git a/src/error.c b/src/error.c index 0ff31ee..eb85b89 100644 --- a/src/error.c +++ b/src/error.c @@ -24,32 +24,8 @@ #include "cdecl.h" #include "cdecl-internal.h" - -#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; - char str[FLEXIBLE_ARRAY_MEMBER]; -}; - /* This pre-initialized error is reserved for dire out-of-memory conditions. */ static struct cdecl_error err_no_mem; @@ -69,16 +45,43 @@ static void set_err(unsigned code, struct cdecl_error *err) err->str = _(&errmsgs[code]); } -static void initialize_cb(void) +static void init_once_cb(void) { #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); bindtextdomain("bison-runtime", BISON_LOCALEDIR); #endif set_err(CDECL__ENOMEM, &err_no_mem); - tls_key_init(); } +#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_get() tls_key +#define tls_set(a) ((tls_key = (a)), 1) + +static int init_once(void) +{ + if (!err_no_mem.code) + init_once_cb(); + return 1; +} + +#endif + +struct err_state { + struct cdecl_error err; + size_t nstr; + char str[FLEXIBLE_ARRAY_MEMBER]; +}; + static void *alloc_err_state(void *old, size_t buf_size) { struct err_state *state; @@ -109,8 +112,7 @@ static struct err_state *get_err_state(void) { void *state; - gl_once_define(static, tls_initialized) - if (glthread_once(&tls_initialized, initialize_cb) || !tls_key_valid) + if (!init_once()) return NULL; if (!(state = tls_get())) diff --git a/src/thread-posix.h b/src/thread-posix.h index b1cd990..22378ed 100644 --- a/src/thread-posix.h +++ b/src/thread-posix.h @@ -8,6 +8,16 @@ * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * + * The pthread_in_use detection is based on Gnulib code written by Bruno + * Haible, distributed with the following copyright and permission notice: + * + * Copyright (C) 2005-2022 Free Software Foundation, Inc. + * + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 @@ -19,6 +29,29 @@ #include +extern int glthread_in_use(); + +#if !defined c11_threads_in_use +# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC +# define c11_threads_in_use 1 +# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK +# include +# pragma weak thrd_exit +# define c11_threads_in_use (thrd_exit != NULL) +# else +# define c11_threads_in_use 0 +# endif +#endif + +#if PTHREAD_IN_USE_DETECTION_HARD +# define pthread_in_use glthread_in_use() +#elif USE_POSIX_THREADS_WEAK +# pragma weak pthread_mutexattr_gettype +# define pthread_in_use (pthread_mutexattr_gettype || c11_threads_in_use) +#else +# define pthread_in_use 1 +#endif + #if USE_POSIX_THREADS_WEAK # pragma weak pthread_key_create # pragma weak pthread_getspecific @@ -41,13 +74,7 @@ static struct { } 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 init_once_cb(void); static void *tls_get(void) { @@ -66,3 +93,22 @@ static int tls_set(void *p) #endif return !pthread_setspecific(tls_key.u.mt, p); } + +static void init_once_with_tls(void) +{ + tls_key.valid = !pthread_key_create(&tls_key.u.mt, free); + init_once_cb(); +} + +static int init_once(void) +{ + if (pthread_in_use) { + static pthread_once_t ctrl = PTHREAD_ONCE_INIT; + return !pthread_once(&ctrl, init_once_with_tls); + } else if (!tls_key_valid) { + tls_key.valid = -1; + init_once_cb(); + } + + return 1; +} diff --git a/src/thread-stdc.h b/src/thread-stdc.h index 46fe361..a29ec8c 100644 --- a/src/thread-stdc.h +++ b/src/thread-stdc.h @@ -22,10 +22,7 @@ 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 init_once_cb(void); static void *tls_get(void) { @@ -36,3 +33,17 @@ static int tls_set(void *p) { return tss_set(tls_key, p) == thrd_success; } + +static void init_once_with_tls(void) +{ + tls_key_valid = (tss_create(&tls_key, free) == thrd_success); + init_once_cb(); +} + +static int init_once(void) +{ + static once_flag flag; + + call_once(&flag, init_once_with_tls); + return 1; +} diff --git a/src/thread-w32.h b/src/thread-w32.h index 44282d8..fb3bdc4 100644 --- a/src/thread-w32.h +++ b/src/thread-w32.h @@ -19,14 +19,12 @@ #define WIN32_LEAN_AND_MEAN #include +#include "windows-once.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 init_once_cb(void); static void *tls_get(void) { @@ -37,3 +35,17 @@ static BOOL tls_set(void *p) { return TlsSetValue(tls_key, p); } + +static void init_once_with_tls(void) +{ + tls_key = TlsAlloc(); + init_once_cb(); +} + +static int init_once(void) +{ + static glwthread_once_t ctrl = GLWTHREAD_ONCE_INIT; + + glwthread_once(&ctrl, init_once_with_tls); + return 1; +}