| /* 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 |