]> Savannah Git Hosting - gnulib.git/commitdiff
setlocale-null: New module.
authorBruno Haible <bruno@clisp.org>
Sun, 15 Dec 2019 20:39:55 +0000 (21:39 +0100)
committerBruno Haible <bruno@clisp.org>
Sun, 15 Dec 2019 20:39:55 +0000 (21:39 +0100)
* lib/locale.in.h (SETLOCALE_NULL_MAX, SETLOCALE_NULL_ALL_MAX,
setlocale_null): New declarations.
* lib/setlocale_null.c: New file.
* lib/setlocale-lock.c: New file.
* m4/threadlib.m4 (gl_PTHREADLIB_BODY): Define C macro HAVE_PTHREAD_API.
* m4/setlocale_null.m4: New file.
* m4/locale_h.m4 (gl_LOCALE_H_DEFAULTS): Initialize
GNULIB_SETLOCALE_NULL.
* modules/locale (Makefile.am): Substitute GNULIB_SETLOCALE_NULL.
* modules/setlocale-null: New file.
* doc/posix-functions/setlocale.texi: Mention the new module.

ChangeLog
doc/posix-functions/setlocale.texi
lib/locale.in.h
lib/setlocale-lock.c [new file with mode: 0644]
lib/setlocale_null.c [new file with mode: 0644]
m4/locale_h.m4
m4/setlocale_null.m4 [new file with mode: 0644]
m4/threadlib.m4
modules/locale
modules/setlocale-null [new file with mode: 0644]

index 39ba464ba3daf822729e1dcdd634e82cede03b72..51f367c718026cc895ac14c47e772e9d023fc9b1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2019-12-15  Bruno Haible  <bruno@clisp.org>
+
+       setlocale-null: New module.
+       * lib/locale.in.h (SETLOCALE_NULL_MAX, SETLOCALE_NULL_ALL_MAX,
+       setlocale_null): New declarations.
+       * lib/setlocale_null.c: New file.
+       * lib/setlocale-lock.c: New file.
+       * m4/threadlib.m4 (gl_PTHREADLIB_BODY): Define C macro HAVE_PTHREAD_API.
+       * m4/setlocale_null.m4: New file.
+       * m4/locale_h.m4 (gl_LOCALE_H_DEFAULTS): Initialize
+       GNULIB_SETLOCALE_NULL.
+       * modules/locale (Makefile.am): Substitute GNULIB_SETLOCALE_NULL.
+       * modules/setlocale-null: New file.
+       * doc/posix-functions/setlocale.texi: Mention the new module.
+
 2019-12-15  Bruno Haible  <bruno@clisp.org>
 
        lock tests: Skip test when no multithreading is enabled.
index 0678ac91e357996fd59292ce94efe221bfde168e..cd172c0b855657bcd6c69372bda6f2318d6c17fd 100644 (file)
@@ -4,9 +4,9 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html}
 
-Gnulib module: setlocale
+Gnulib module: setlocale, setlocale-null
 
-Portability problems fixed by Gnulib:
+Portability problems fixed by Gnulib module @code{setlocale}:
 @itemize
 @item
 On Windows platforms (excluding Cygwin), @code{setlocale(@var{category},NULL)}
@@ -26,6 +26,16 @@ always fails.  The replacement, however, supports only the locale names
 @code{"C"} and @code{"POSIX"}.
 @end itemize
 
+Portability problems fixed by Gnulib module @code{setlocale-null}:
+@itemize
+@item
+Invocations of @code{setlocale (..., NULL)} are not multithread-safe on some
+platforms:
+musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin.
+To make these invocations multithread-safe, you need to change the code to
+invoke @code{setlocale_null} instead.
+@end itemize
+
 Portability problems not fixed by Gnulib:
 @itemize
 @item
index 9e897a3ea0d7f00d2cc2c637706cee0ef7c423bf..598668308bbd9c5dd39e9218fcf8089182c40b0a 100644 (file)
@@ -206,6 +206,45 @@ _GL_WARN_ON_USE (setlocale, "setlocale works differently on native Windows - "
 # endif
 #endif
 
+#if @GNULIB_SETLOCALE_NULL@
+/* Recommended size of a buffer for a locale name for a single category.
+   On glibc systems, you can have locale names that are relative file names;
+   assume a maximum length 256.
+   In native Windows, in 2018 the longest locale name was of length 58
+   ("FYRO Macedonian_Former Yugoslav Republic of Macedonia.1251").  */
+# define SETLOCALE_NULL_MAX (256+1)
+/* Recommended size of a buffer for a locale name with all categories.
+   On glibc systems, you can have locale names that are relative file names;
+   assume maximum length 256 for each.  There are 12 categories; so, the
+   maximum total length is 148+12*256.
+   In native Windows, there are 5 categories, and the maximum total length is
+   55+5*58.  */
+# define SETLOCALE_NULL_ALL_MAX (148+12*256+1)
+/* setlocale_null (CATEGORY, BUF, BUFSIZE) is like setlocale (CATEGORY, NULL),
+   except that
+     - it is guaranteed to be multithread-safe,
+     - it returns the resulting locale category name or locale name in the
+       user-supplied buffer BUF, which must be BUFSIZE bytes long.
+   The recommended minimum buffer size is
+     - SETLOCALE_NULL_MAX for CATEGORY != LC_ALL, and
+     - SETLOCALE_NULL_ALL_MAX for CATEGORY == LC_ALL.
+   The return value is an error code: 0 if the call is successful, ERANGE if
+   BUFSIZE is smaller than the length needed size (including the trailing NUL
+   byte).  In the latter case, a truncated result is returned in BUF, but
+   still NUL-terminated if BUFSIZE > 0.
+   For this call to be multithread-safe, *all* calls to
+   setlocale (CATEGORY, NULL) in all other threads must have been converted
+   to use setlocale_null as well, and the other threads must not make other
+   setlocale invocations (since changing the global locale has side effects
+   on all threads).  */
+_GL_FUNCDECL_SYS (setlocale_null, int,
+                  (int category, char *buf, size_t bufsize)
+                  _GL_ARG_NONNULL ((2)));
+_GL_CXXALIAS_SYS (setlocale_null, int,
+                  (int category, char *buf, size_t bufsize));
+_GL_CXXALIASWARN (setlocale_null);
+#endif
+
 #if /*@GNULIB_NEWLOCALE@ ||*/ (@GNULIB_LOCALENAME@ && @HAVE_NEWLOCALE@)
 # if @REPLACE_NEWLOCALE@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/setlocale-lock.c b/lib/setlocale-lock.c
new file mode 100644 (file)
index 0000000..ed6ab9f
--- /dev/null
@@ -0,0 +1,124 @@
+/* Return the internal lock used by setlocale_null.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2019.  */
+
+#include <config.h>
+
+/* This file defines the internal lock used by setlocale_null.
+   It is a separate compilation unit, so that only one copy of it is
+   present when linking statically.  */
+
+/* Prohibit renaming this symbol.  */
+#undef gl_get_setlocale_null_lock
+
+#if defined _WIN32 && !defined __CYGWIN__
+
+# define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+# include <windows.h>
+
+# include "windows-initguard.h"
+
+/* The return type is a 'CRITICAL_SECTION *', not a 'glwthread_mutex_t *',
+   because the latter is not guaranteed to be a stable ABI in the future.  */
+
+/* Make sure the function gets exported from DLLs.  */
+__declspec(dllexport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
+
+static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT;
+static CRITICAL_SECTION lock;
+
+/* Returns the internal lock used by setlocale_null.  */
+CRITICAL_SECTION *
+gl_get_setlocale_null_lock (void)
+{
+  if (!guard.done)
+    {
+      if (InterlockedIncrement (&guard.started) == 0)
+        {
+          /* This thread is the first one to need the lock.  Initialize it.  */
+          InitializeCriticalSection (&lock);
+          guard.done = 1;
+        }
+      else
+        {
+          /* Don't let guard.started grow and wrap around.  */
+          InterlockedDecrement (&guard.started);
+          /* Yield the CPU while waiting for another thread to finish
+             initializing this mutex.  */
+          while (!guard.done)
+            Sleep (0);
+        }
+    }
+  return &lock;
+}
+
+#elif HAVE_PTHREAD_API
+
+# include <pthread.h>
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+# if defined _WIN32 || defined __CYGWIN__
+/* Make sure the function gets exported from DLLs.  */
+__declspec(dllexport) pthread_mutex_t *gl_get_setlocale_null_lock (void);
+# endif
+
+/* Returns the internal lock used by setlocale_null.  */
+pthread_mutex_t *
+gl_get_setlocale_null_lock (void)
+{
+  return &mutex;
+}
+
+#elif HAVE_THREADS_H
+
+# include <threads.h>
+# include <stdlib.h>
+
+static int volatile init_needed = 1;
+static once_flag init_once = ONCE_FLAG_INIT;
+static mtx_t mutex;
+
+static void
+atomic_init (void)
+{
+  if (mtx_init (&mutex, mtx_plain) != thrd_success)
+    abort ();
+  init_needed = 0;
+}
+
+/* Returns the internal lock used by setlocale_null.  */
+mtx_t *
+gl_get_setlocale_null_lock (void)
+{
+  if (init_needed)
+    call_once (&init_once, atomic_init);
+  return &mutex;
+}
+
+#endif
+
+#if defined _WIN32 || defined __CYGWIN__
+/* Make sure the '__declspec(dllimport)' in setlocale_null.c does not cause
+   a link failure when no DLLs are involved.  */
+# if defined _WIN64 || defined _LP64
+#  define IMP(x) __imp_##x
+# else
+#  define IMP(x) _imp__##x
+# endif
+void * IMP(gl_get_setlocale_null_lock) = &gl_get_setlocale_null_lock;
+#endif
diff --git a/lib/setlocale_null.c b/lib/setlocale_null.c
new file mode 100644 (file)
index 0000000..b0506b9
--- /dev/null
@@ -0,0 +1,204 @@
+/* Query the name of the current global locale.
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2019.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <locale.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _WIN32 && !defined __CYGWIN__
+# include <wchar.h>
+#endif
+
+#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE)
+# if defined _WIN32 && !defined __CYGWIN__
+#  define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+#  include <windows.h>
+# elif HAVE_PTHREAD_API
+#  include <pthread.h>
+# elif HAVE_THREADS_H
+#  include <threads.h>
+# endif
+#endif
+
+/* Use the system's setlocale() function, not the gnulib override, here.  */
+#undef setlocale
+
+static int
+setlocale_null_unlocked (int category, char *buf, size_t bufsize)
+{
+#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
+  /* On native Windows, nowadays, the setlocale() implementation is based
+     on _wsetlocale() and uses malloc() for the result.  We are better off
+     using _wsetlocale() directly.  */
+  const wchar_t *result = _wsetlocale (category, NULL);
+  size_t length = wcslen (result);
+  if (length < bufsize)
+    {
+      size_t i;
+
+      /* Convert wchar_t[] -> char[], assuming plain ASCII.  */
+      for (i = 0; i <= length; i++)
+        buf[i] = result[i];
+
+      return 0;
+    }
+  else
+    {
+      if (bufsize > 0)
+        {
+          /* Return a truncated result in BUF.
+             This is a convenience for callers that don't want to write
+             explicit code for handling ERANGE.  */
+          size_t i;
+
+          /* Convert wchar_t[] -> char[], assuming plain ASCII.  */
+          for (i = 0; i < bufsize; i++)
+            buf[i] = result[i];
+          buf[bufsize - 1] = '\0';
+        }
+      return ERANGE;
+    }
+#else
+  const char *result = setlocale (category, NULL);
+  size_t length = strlen (result);
+  if (length < bufsize)
+    {
+      memcpy (buf, result, length + 1);
+      return 0;
+    }
+  else
+    {
+      if (bufsize > 0)
+        {
+          /* Return a truncated result in BUF.
+             This is a convenience for callers that don't want to write
+             explicit code for handling ERANGE.  */
+          memcpy (buf, result, bufsize - 1);
+          buf[bufsize - 1] = '\0';
+        }
+      return ERANGE;
+    }
+#endif
+}
+
+#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE)
+
+/* Use a lock, so that no two threads can invoke setlocale_null_unlocked
+   at the same time.  */
+
+/* Prohibit renaming this symbol.  */
+# undef gl_get_setlocale_null_lock
+
+# if defined _WIN32 && !defined __CYGWIN__
+
+extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
+
+static int
+setlocale_null_with_lock (int category, char *buf, size_t bufsize)
+{
+  CRITICAL_SECTION *lock = gl_get_setlocale_null_lock ();
+  int ret;
+
+  EnterCriticalSection (lock);
+  ret = setlocale_null_unlocked (category, buf, bufsize);
+  LeaveCriticalSection (lock);
+
+  return ret;
+}
+
+# elif HAVE_PTHREAD_API
+
+extern
+#  if defined _WIN32 || defined __CYGWIN__
+  __declspec(dllimport)
+#  endif
+  pthread_mutex_t *gl_get_setlocale_null_lock (void);
+
+static int
+setlocale_null_with_lock (int category, char *buf, size_t bufsize)
+{
+  pthread_mutex_t *lock = gl_get_setlocale_null_lock ();
+  int ret;
+
+  if (pthread_mutex_lock (lock))
+    abort ();
+  ret = setlocale_null_unlocked (category, buf, bufsize);
+  if (pthread_mutex_unlock (lock))
+    abort ();
+
+  return ret;
+}
+
+# elif HAVE_THREADS_H
+
+extern mtx_t *gl_get_setlocale_null_lock (void);
+
+static int
+setlocale_null_with_lock (int category, char *buf, size_t bufsize)
+{
+  mtx_t *lock = gl_get_setlocale_null_lock ();
+  int ret;
+
+  if (mtx_lock (lock) != thrd_success)
+    abort ();
+  ret = setlocale_null_unlocked (category, buf, bufsize);
+  if (mtx_unlock (lock) != thrd_success)
+    abort ();
+
+  return ret;
+}
+
+# endif
+
+#endif
+
+int
+setlocale_null (int category, char *buf, size_t bufsize)
+{
+#if SETLOCALE_NULL_ALL_MTSAFE
+# if SETLOCALE_NULL_ONE_MTSAFE
+
+  return setlocale_null_unlocked (category, buf, bufsize);
+
+# else
+
+  if (category == LC_ALL)
+    return setlocale_null_unlocked (category, buf, bufsize);
+  else
+    return setlocale_null_with_lock (category, buf, bufsize);
+
+# endif
+#else
+# if SETLOCALE_NULL_ONE_MTSAFE
+
+  if (category == LC_ALL)
+    return setlocale_null_with_lock (category, buf, bufsize);
+  else
+    return setlocale_null_unlocked (category, buf, bufsize);
+
+# else
+
+  return setlocale_null_with_lock (category, buf, bufsize);
+
+# endif
+#endif
+}
index c0ec3fc808eb4b817c978bb9c65571ea04d5ba69..fd7de42643c009d4827473f8be00b8f278766881 100644 (file)
@@ -1,4 +1,4 @@
-# locale_h.m4 serial 23
+# locale_h.m4 serial 24
 dnl Copyright (C) 2007, 2009-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -140,10 +140,11 @@ AC_DEFUN([gl_LOCALE_MODULE_INDICATOR],
 
 AC_DEFUN([gl_LOCALE_H_DEFAULTS],
 [
-  GNULIB_LOCALECONV=0; AC_SUBST([GNULIB_LOCALECONV])
-  GNULIB_SETLOCALE=0;  AC_SUBST([GNULIB_SETLOCALE])
-  GNULIB_DUPLOCALE=0;  AC_SUBST([GNULIB_DUPLOCALE])
-  GNULIB_LOCALENAME=0; AC_SUBST([GNULIB_LOCALENAME])
+  GNULIB_LOCALECONV=0;     AC_SUBST([GNULIB_LOCALECONV])
+  GNULIB_SETLOCALE=0;      AC_SUBST([GNULIB_SETLOCALE])
+  GNULIB_SETLOCALE_NULL=0; AC_SUBST([GNULIB_SETLOCALE_NULL])
+  GNULIB_DUPLOCALE=0;      AC_SUBST([GNULIB_DUPLOCALE])
+  GNULIB_LOCALENAME=0;     AC_SUBST([GNULIB_LOCALENAME])
   dnl Assume proper GNU behavior unless another module says otherwise.
   HAVE_NEWLOCALE=1;       AC_SUBST([HAVE_NEWLOCALE])
   HAVE_DUPLOCALE=1;       AC_SUBST([HAVE_DUPLOCALE])
diff --git a/m4/setlocale_null.m4 b/m4/setlocale_null.m4
new file mode 100644 (file)
index 0000000..5c69a3f
--- /dev/null
@@ -0,0 +1,84 @@
+# setlocale_null.m4 serial 1
+dnl Copyright (C) 2019 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_SETLOCALE_NULL],
+[
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([gl_PTHREADLIB])
+  AC_CHECK_HEADERS_ONCE([threads.h])
+
+  AC_CACHE_CHECK([whether setlocale (LC_ALL, NULL) is multithread-safe],
+    [gl_cv_func_setlocale_null_all_mtsafe],
+    [case "$host_os" in
+       # Guess no on musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin.
+       *-musl* | darwin* | freebsd* | netbsd* | openbsd* | aix* | haiku* | cygwin*)
+         gl_cv_func_setlocale_null_all_mtsafe=no ;;
+       # Guess yes on glibc, HP-UX, IRIX, Solaris, native Windows.
+       *-gnu* | gnu* | hpux* | irix* | solaris* | mingw*)
+         gl_cv_func_setlocale_null_all_mtsafe=yes ;;
+       # If we don't know, obey --enable-cross-guesses.
+       *)
+         gl_cv_func_setlocale_null_all_mtsafe="$gl_cross_guess_normal" ;;
+     esac
+    ])
+  dnl On platforms without multithreading, there is no issue.
+  case "$host_os" in
+    mingw*) ;;
+    *)
+      if test $gl_pthread_api = no && test $ac_cv_header_threads_h = no; then
+        gl_cv_func_setlocale_null_all_mtsafe="trivially yes"
+      fi
+      ;;
+  esac
+  case "$gl_cv_func_setlocale_null_all_mtsafe" in
+    *yes) SETLOCALE_NULL_ALL_MTSAFE=1 ;;
+    *)    SETLOCALE_NULL_ALL_MTSAFE=0 ;;
+  esac
+  AC_DEFINE_UNQUOTED([SETLOCALE_NULL_ALL_MTSAFE], [$SETLOCALE_NULL_ALL_MTSAFE],
+    [Define to 1 if setlocale (LC_ALL, NULL) is multithread-safe.])
+
+  dnl This is about a single category (not LC_ALL).
+  AC_CACHE_CHECK([whether setlocale (category, NULL) is multithread-safe],
+    [gl_cv_func_setlocale_null_one_mtsafe],
+    [case "$host_os" in
+       # Guess no on OpenBSD, AIX.
+       openbsd* | aix*)
+         gl_cv_func_setlocale_null_one_mtsafe=no ;;
+       # Guess yes on glibc, musl libc, macOS, FreeBSD, NetBSD, HP-UX, IRIX, Solaris, Haiku, Cygwin, native Windows.
+       *-gnu* | gnu* | *-musl* | darwin* | freebsd* | netbsd* | hpux* | irix* | solaris* | haiku* | cygwin* | mingw*)
+         gl_cv_func_setlocale_null_one_mtsafe=yes ;;
+       # If we don't know, obey --enable-cross-guesses.
+       *)
+         gl_cv_func_setlocale_null_one_mtsafe="$gl_cross_guess_normal" ;;
+     esac
+    ])
+  dnl On platforms without multithreading, there is no issue.
+  case "$host_os" in
+    mingw*) ;;
+    *)
+      if test $gl_pthread_api = no && test $ac_cv_header_threads_h = no; then
+        gl_cv_func_setlocale_null_one_mtsafe="trivially yes"
+      fi
+      ;;
+  esac
+  case "$gl_cv_func_setlocale_null_one_mtsafe" in
+    *yes) SETLOCALE_NULL_ONE_MTSAFE=1 ;;
+    *)    SETLOCALE_NULL_ONE_MTSAFE=0 ;;
+  esac
+  AC_DEFINE_UNQUOTED([SETLOCALE_NULL_ONE_MTSAFE], [$SETLOCALE_NULL_ONE_MTSAFE],
+    [Define to 1 if setlocale (category, NULL) is multithread-safe.])
+
+  dnl Determine link dependencies of lib/setlocale_null.c and lib/setlocale-lock.c.
+  if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then
+    case "$host_os" in
+      mingw*) LIB_SETLOCALE_NULL= ;;
+      *)      LIB_SETLOCALE_NULL="$LIBPTHREAD" ;;
+    esac
+  else
+    LIB_SETLOCALE_NULL=
+  fi
+  AC_SUBST([LIB_SETLOCALE_NULL])
+])
index d22e0d666c648602360b1741f0a7e93020e025ab..d6e6bf99716c6c16e1ef5a13cff0c390c3998de0 100644 (file)
@@ -1,4 +1,4 @@
-# threadlib.m4 serial 22
+# threadlib.m4 serial 23
 dnl Copyright (C) 2005-2019 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -18,6 +18,8 @@ dnl LIBPMULTITHREAD is that on platforms supporting weak symbols, typically
 dnl LIBPTHREAD is empty whereas LIBPMULTITHREAD is not.
 dnl Adds to CPPFLAGS the flag -D_REENTRANT or -D_THREAD_SAFE if needed for
 dnl multithread-safe programs.
+dnl Defines the C macro HAVE_PTHREAD_API if (at least parts of) the POSIX
+dnl threads API is available.
 
 dnl gl_THREADLIB
 dnl ------------
@@ -220,6 +222,10 @@ AC_DEFUN([gl_PTHREADLIB_BODY],
     AC_MSG_RESULT([$gl_pthread_api])
     AC_SUBST([LIBPTHREAD])
     AC_SUBST([LIBPMULTITHREAD])
+    if test $gl_pthread_api = yes; then
+      AC_DEFINE([HAVE_PTHREAD_API], [1],
+        [Define if you have the <pthread.h> header and the POSIX threads API.])
+    fi
     gl_threadlib_body_done=done
   fi
 ])
index 488e4372af961133471e4d4b95c8e86b03e71ceb..aac463cd67decb2840b17de876601b9731adf9c9 100644 (file)
@@ -31,6 +31,7 @@ locale.h: locale.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''NEXT_LOCALE_H''@|$(NEXT_LOCALE_H)|g' \
              -e 's/@''GNULIB_LOCALECONV''@/$(GNULIB_LOCALECONV)/g' \
              -e 's/@''GNULIB_SETLOCALE''@/$(GNULIB_SETLOCALE)/g' \
+             -e 's/@''GNULIB_SETLOCALE_NULL''@/$(GNULIB_SETLOCALE_NULL)/g' \
              -e 's/@''GNULIB_DUPLOCALE''@/$(GNULIB_DUPLOCALE)/g' \
              -e 's/@''GNULIB_LOCALENAME''@/$(GNULIB_LOCALENAME)/g' \
              -e 's|@''HAVE_NEWLOCALE''@|$(HAVE_NEWLOCALE)|g' \
diff --git a/modules/setlocale-null b/modules/setlocale-null
new file mode 100644 (file)
index 0000000..17e8d9d
--- /dev/null
@@ -0,0 +1,34 @@
+Description:
+setlocale_null() function: query the name of the current global locale.
+
+Files:
+lib/setlocale_null.c
+lib/setlocale-lock.c
+lib/windows-initguard.h
+m4/setlocale_null.m4
+m4/threadlib.m4
+
+Depends-on:
+locale
+
+configure.ac:
+gl_FUNC_SETLOCALE_NULL
+if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then
+  AC_LIBOBJ([setlocale-lock])
+fi
+gl_LOCALE_MODULE_INDICATOR([setlocale_null])
+
+Makefile.am:
+lib_SOURCES += setlocale_null.c
+
+Include:
+<locale.h>
+
+Link:
+$(LIB_SETLOCALE_NULL)
+
+License:
+LGPLv2+
+
+Maintainer:
+Bruno Haible