Commit | Line | Data |
---|---|---|
5df4cba6 SM |
1 | /* Return 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 | #include <config.h> | |
20 | ||
21 | /* When it is known that the gl_get_mbtowc_lock function is defined | |
22 | by a dependency library, it should not be defined here. */ | |
23 | #if OMIT_MBTOWC_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 mbrtowc and mbrtoc32. | |
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_mbtowc_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_mbtowc_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 mbrtowc and mbrtoc32. */ | |
68 | CRITICAL_SECTION * | |
69 | gl_get_mbtowc_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_mbtowc_lock (void); | |
100 | ||
101 | /* Returns the internal lock used by mbrtowc and mbrtoc32. */ | |
102 | pthread_mutex_t * | |
103 | gl_get_mbtowc_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_mbtowc_lock (void); | |
127 | ||
128 | /* Returns the internal lock used by mbrtowc and mbrtoc32. */ | |
129 | mtx_t * | |
130 | gl_get_mbtowc_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 mbrtowc.c and mbrtoc32.c does not | |
141 | cause 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_mbtowc_lock) = &gl_get_mbtowc_lock; | |
148 | # endif | |
149 | ||
150 | #endif |