diff options
Diffstat (limited to 'lib/mbtowc-lock.h')
| -rw-r--r-- | lib/mbtowc-lock.h | 125 | 
1 files changed, 125 insertions, 0 deletions
diff --git a/lib/mbtowc-lock.h b/lib/mbtowc-lock.h new file mode 100644 index 00000000..ecfd44e8 --- /dev/null +++ b/lib/mbtowc-lock.h @@ -0,0 +1,125 @@ +/* Use the internal lock used by mbrtowc and mbrtoc32. +   Copyright (C) 2019-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 file 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 Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public License +   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2019-2020.  */ + +/* Use a lock, so that no two threads can invoke mbtowc at the same time.  */ + +static inline int +mbtowc_unlocked (wchar_t *pwc, const char *p, size_t m) +{ +  /* Put the hidden internal state of mbtowc into its initial state. +     This is needed at least with glibc, uClibc, and MSVC CRT. +     See <https://sourceware.org/bugzilla/show_bug.cgi?id=9674>.  */ +  mbtowc (NULL, NULL, 0); + +  return mbtowc (pwc, p, m); +} + +/* Prohibit renaming this symbol.  */ +#undef gl_get_mbtowc_lock + +#if GNULIB_MBRTOWC_SINGLE_THREAD + +/* All uses of this function are in a single thread.  No locking needed.  */ + +static int +mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) +{ +  return mbtowc_unlocked (pwc, p, m); +} + +#elif defined _WIN32 && !defined __CYGWIN__ + +extern __declspec(dllimport) CRITICAL_SECTION *gl_get_mbtowc_lock (void); + +static int +mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) +{ +  CRITICAL_SECTION *lock = gl_get_mbtowc_lock (); +  int ret; + +  EnterCriticalSection (lock); +  ret = mbtowc_unlocked (pwc, p, m); +  LeaveCriticalSection (lock); + +  return ret; +} + +#elif HAVE_PTHREAD_API /* AIX, IRIX, Cygwin */ + +extern +# if defined _WIN32 || defined __CYGWIN__ +  __declspec(dllimport) +# endif +  pthread_mutex_t *gl_get_mbtowc_lock (void); + +# if HAVE_WEAK_SYMBOLS /* IRIX */ + +   /* Avoid the need to link with '-lpthread'.  */ +#  pragma weak pthread_mutex_lock +#  pragma weak pthread_mutex_unlock + +   /* Determine whether libpthread is in use.  */ +#  pragma weak pthread_mutexattr_gettype +   /* See the comments in lock.h.  */ +#  define pthread_in_use() \ +     (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) + +# else +#  define pthread_in_use() 1 +# endif + +static int +mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) +{ +  if (pthread_in_use()) +    { +      pthread_mutex_t *lock = gl_get_mbtowc_lock (); +      int ret; + +      if (pthread_mutex_lock (lock)) +        abort (); +      ret = mbtowc_unlocked (pwc, p, m); +      if (pthread_mutex_unlock (lock)) +        abort (); + +      return ret; +    } +  else +    return mbtowc_unlocked (pwc, p, m); +} + +#elif HAVE_THREADS_H + +extern mtx_t *gl_get_mbtowc_lock (void); + +static int +mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) +{ +  mtx_t *lock = gl_get_mbtowc_lock (); +  int ret; + +  if (mtx_lock (lock) != thrd_success) +    abort (); +  ret = mbtowc_unlocked (pwc, p, m); +  if (mtx_unlock (lock) != thrd_success) +    abort (); + +  return ret; +} + +#endif  | 
