1 /* Return the internal lock used by setlocale_null_r. 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. */ 18 19 #include <config.h> 20 21 /* When it is known that the gl_get_setlocale_null_lock function is defined 22 by a dependency library, it should not be defined here. */ 23 #if OMIT_SETLOCALE_LOCK 24 25 /* This declaration is solely to ensure that after preprocessing 26 this file is never empty. */ 27 typedef int dummy; 28 29 #else 30 31 /* This file defines the internal lock used by setlocale_null_r. 32 It is a separate compilation unit, so that only one copy of it is 33 present when linking statically. */ 34 35 /* Prohibit renaming this symbol. */ 36 # undef gl_get_setlocale_null_lock 37 38 /* Macro for exporting a symbol (function, not variable) defined in this file, 39 when compiled into a shared library. */ 40 # ifndef DLL_EXPORTED 41 # if HAVE_VISIBILITY 42 /* Override the effect of the compiler option '-fvisibility=hidden'. */ 43 # define DLL_EXPORTED __attribute__((__visibility__("default"))) 44 # elif defined _WIN32 || defined __CYGWIN__ 45 # define DLL_EXPORTED __declspec(dllexport) 46 # else 47 # define DLL_EXPORTED 48 # endif 49 # endif 50 51 # if defined _WIN32 && !defined __CYGWIN__ 52 53 # define WIN32_LEAN_AND_MEAN /* avoid including junk */ 54 # include <windows.h> 55 56 # include "windows-initguard.h" 57 58 /* The return type is a 'CRITICAL_SECTION *', not a 'glwthread_mutex_t *', 59 because the latter is not guaranteed to be a stable ABI in the future. */ 60 61 /* Make sure the function gets exported from DLLs. */ 62 DLL_EXPORTED CRITICAL_SECTION *gl_get_setlocale_null_lock (void); 63 64 static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT; 65 static CRITICAL_SECTION lock; 66 67 /* Returns the internal lock used by setlocale_null_r. */ 68 CRITICAL_SECTION * 69 gl_get_setlocale_null_lock (void) 70 { 71 if (!guard.done) 72 { 73 if (InterlockedIncrement (&guard.started) == 0) 74 { 75 /* This thread is the first one to need the lock. Initialize it. */ 76 InitializeCriticalSection (&lock); 77 guard.done = 1; 78 } 79 else 80 { 81 /* Don't let guard.started grow and wrap around. */ 82 InterlockedDecrement (&guard.started); 83 /* Yield the CPU while waiting for another thread to finish 84 initializing this mutex. */ 85 while (!guard.done) 86 Sleep (0); 87 } 88 } 89 return &lock; 90 } 91 92 # elif HAVE_PTHREAD_API 93 94 # include <pthread.h> 95 96 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 97 98 /* Make sure the function gets exported from shared libraries. */ 99 DLL_EXPORTED pthread_mutex_t *gl_get_setlocale_null_lock (void); 100 101 /* Returns the internal lock used by setlocale_null_r. */ 102 pthread_mutex_t * 103 gl_get_setlocale_null_lock (void) 104 { 105 return &mutex; 106 } 107 108 # elif HAVE_THREADS_H 109 110 # include <threads.h> 111 # include <stdlib.h> 112 113 static int volatile init_needed = 1; 114 static once_flag init_once = ONCE_FLAG_INIT; 115 static mtx_t mutex; 116 117 static void 118 atomic_init (void) 119 { 120 if (mtx_init (&mutex, mtx_plain) != thrd_success) 121 abort (); 122 init_needed = 0; 123 } 124 125 /* Make sure the function gets exported from shared libraries. */ 126 DLL_EXPORTED mtx_t *gl_get_setlocale_null_lock (void); 127 128 /* Returns the internal lock used by setlocale_null_r. */ 129 mtx_t * 130 gl_get_setlocale_null_lock (void) 131 { 132 if (init_needed) 133 call_once (&init_once, atomic_init); 134 return &mutex; 135 } 136 137 # endif 138 139 # if (defined _WIN32 || defined __CYGWIN__) && !defined _MSC_VER 140 /* Make sure the '__declspec(dllimport)' in setlocale_null.c does not cause 141 a link failure when no DLLs are involved. */ 142 # if defined _WIN64 || defined _LP64 143 # define IMP(x) __imp_##x 144 # else 145 # define IMP(x) _imp__##x 146 # endif 147 void * IMP(gl_get_setlocale_null_lock) = &gl_get_setlocale_null_lock; 148 # endif 149 150 #endif 151