1 /* Use the internal lock used by mbrtowc and mbrtoc32. 2 Copyright (C) 2019-2022 Free Software Foundation, Inc. 3 4 This file is free software: you can redistribute it and/or modify 5 it under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 2.1 of the 7 License, or (at your option) any later version. 8 9 This file is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public License 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 17 /* Written by Bruno Haible <bruno@clisp.org>, 2019-2020. */ 18 19 /* Use a lock, so that no two threads can invoke mbtowc at the same time. */ 20 21 static inline int 22 mbtowc_unlocked (wchar_t *pwc, const char *p, size_t m) 23 { 24 /* Put the hidden internal state of mbtowc into its initial state. 25 This is needed at least with glibc, uClibc, and MSVC CRT. 26 See <https://sourceware.org/bugzilla/show_bug.cgi?id=9674>. */ 27 mbtowc (NULL, NULL, 0); 28 29 return mbtowc (pwc, p, m); 30 } 31 32 /* Prohibit renaming this symbol. */ 33 #undef gl_get_mbtowc_lock 34 35 #if GNULIB_MBRTOWC_SINGLE_THREAD 36 37 /* All uses of this function are in a single thread. No locking needed. */ 38 39 static int 40 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 41 { 42 return mbtowc_unlocked (pwc, p, m); 43 } 44 45 #elif defined _WIN32 && !defined __CYGWIN__ 46 47 extern __declspec(dllimport) CRITICAL_SECTION *gl_get_mbtowc_lock (void); 48 49 static int 50 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 51 { 52 CRITICAL_SECTION *lock = gl_get_mbtowc_lock (); 53 int ret; 54 55 EnterCriticalSection (lock); 56 ret = mbtowc_unlocked (pwc, p, m); 57 LeaveCriticalSection (lock); 58 59 return ret; 60 } 61 62 #elif HAVE_PTHREAD_API /* AIX, IRIX, Cygwin */ 63 64 extern 65 # if defined _WIN32 || defined __CYGWIN__ 66 __declspec(dllimport) 67 # endif 68 pthread_mutex_t *gl_get_mbtowc_lock (void); 69 70 # if HAVE_WEAK_SYMBOLS /* IRIX */ 71 72 /* Avoid the need to link with '-lpthread'. */ 73 # pragma weak pthread_mutex_lock 74 # pragma weak pthread_mutex_unlock 75 76 /* Determine whether libpthread is in use. */ 77 # pragma weak pthread_mutexattr_gettype 78 /* See the comments in lock.h. */ 79 # define pthread_in_use() \ 80 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) 81 82 # else 83 # define pthread_in_use() 1 84 # endif 85 86 static int 87 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 88 { 89 if (pthread_in_use()) 90 { 91 pthread_mutex_t *lock = gl_get_mbtowc_lock (); 92 int ret; 93 94 if (pthread_mutex_lock (lock)) 95 abort (); 96 ret = mbtowc_unlocked (pwc, p, m); 97 if (pthread_mutex_unlock (lock)) 98 abort (); 99 100 return ret; 101 } 102 else 103 return mbtowc_unlocked (pwc, p, m); 104 } 105 106 #elif HAVE_THREADS_H 107 108 extern mtx_t *gl_get_mbtowc_lock (void); 109 110 static int 111 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 112 { 113 mtx_t *lock = gl_get_mbtowc_lock (); 114 int ret; 115 116 if (mtx_lock (lock) != thrd_success) 117 abort (); 118 ret = mbtowc_unlocked (pwc, p, m); 119 if (mtx_unlock (lock) != thrd_success) 120 abort (); 121 122 return ret; 123 } 124 125 #endif 126