1 /* Use the internal lock used by mbrtowc and mbrtoc32. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program 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 General Public License for more details. 13 14 You should have received a copy of the GNU 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 defined _WIN32 && !defined __CYGWIN__ 36 37 extern __declspec(dllimport) CRITICAL_SECTION *gl_get_mbtowc_lock (void); 38 39 static int 40 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 41 { 42 CRITICAL_SECTION *lock = gl_get_mbtowc_lock (); 43 int ret; 44 45 EnterCriticalSection (lock); 46 ret = mbtowc_unlocked (pwc, p, m); 47 LeaveCriticalSection (lock); 48 49 return ret; 50 } 51 52 #elif HAVE_PTHREAD_API /* AIX, IRIX, Cygwin */ 53 54 extern 55 # if defined _WIN32 || defined __CYGWIN__ 56 __declspec(dllimport) 57 # endif 58 pthread_mutex_t *gl_get_mbtowc_lock (void); 59 60 # if HAVE_WEAK_SYMBOLS /* IRIX */ 61 62 /* Avoid the need to link with '-lpthread'. */ 63 # pragma weak pthread_mutex_lock 64 # pragma weak pthread_mutex_unlock 65 66 /* Determine whether libpthread is in use. */ 67 # pragma weak pthread_mutexattr_gettype 68 /* See the comments in lock.h. */ 69 # define pthread_in_use() \ 70 (pthread_mutexattr_gettype != NULL || c11_threads_in_use ()) 71 72 # else 73 # define pthread_in_use() 1 74 # endif 75 76 static int 77 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 78 { 79 if (pthread_in_use()) 80 { 81 pthread_mutex_t *lock = gl_get_mbtowc_lock (); 82 int ret; 83 84 if (pthread_mutex_lock (lock)) 85 abort (); 86 ret = mbtowc_unlocked (pwc, p, m); 87 if (pthread_mutex_unlock (lock)) 88 abort (); 89 90 return ret; 91 } 92 else 93 return mbtowc_unlocked (pwc, p, m); 94 } 95 96 #elif HAVE_THREADS_H 97 98 extern mtx_t *gl_get_mbtowc_lock (void); 99 100 static int 101 mbtowc_with_lock (wchar_t *pwc, const char *p, size_t m) 102 { 103 mtx_t *lock = gl_get_mbtowc_lock (); 104 int ret; 105 106 if (mtx_lock (lock) != thrd_success) 107 abort (); 108 ret = mbtowc_unlocked (pwc, p, m); 109 if (mtx_unlock (lock) != thrd_success) 110 abort (); 111 112 return ret; 113 } 114 115 #endif 116