Coverage Report

Created: 2025-07-11 06:23

/src/icu/source/common/umutex.h
Line
Count
Source (jump to first uncovered line)
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
**********************************************************************
5
*   Copyright (C) 1997-2015, International Business Machines
6
*   Corporation and others.  All Rights Reserved.
7
**********************************************************************
8
*
9
* File UMUTEX.H
10
*
11
* Modification History:
12
*
13
*   Date        Name        Description
14
*   04/02/97  aliu        Creation.
15
*   04/07/99  srl         rewrite - C interface, multiple mutices
16
*   05/13/99  stephen     Changed to umutex (from cmutex)
17
******************************************************************************
18
*/
19
20
#ifndef UMUTEX_H
21
#define UMUTEX_H
22
23
#include "unicode/utypes.h"
24
#include "unicode/uclean.h"
25
#include "putilimp.h"
26
27
28
29
// Forward Declarations. UMutex is not in the ICU namespace (yet) because
30
//                       there are some remaining references from plain C.
31
struct UMutex;
32
struct UConditionVar;
33
34
U_NAMESPACE_BEGIN
35
struct UInitOnce;
36
U_NAMESPACE_END
37
38
// Stringify macros, to allow #include of user supplied atomic & mutex files.
39
#define U_MUTEX_STR(s) #s
40
#define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
41
42
/****************************************************************************
43
 *
44
 *   Low Level Atomic Operations.
45
 *      Compiler dependent. Not operating system dependent.
46
 *
47
 ****************************************************************************/
48
#if defined (U_USER_ATOMICS_H)
49
#include U_MUTEX_XSTR(U_USER_ATOMICS_H)
50
51
#elif U_HAVE_STD_ATOMICS
52
53
//  C++11 atomics are available.
54
55
#include <atomic>
56
57
U_NAMESPACE_BEGIN
58
59
typedef std::atomic<int32_t> u_atomic_int32_t;
60
#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
61
62
3.34k
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
63
3.34k
    return var.load(std::memory_order_acquire);
64
3.34k
}
65
66
4.46k
inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
67
4.46k
    var.store(val, std::memory_order_release);
68
4.46k
}
69
70
0
inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
71
0
    return var->fetch_add(1) + 1;
72
0
}
73
74
0
inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
75
0
    return var->fetch_sub(1) - 1;
76
0
}
77
U_NAMESPACE_END
78
79
#elif U_PLATFORM_HAS_WIN32_API
80
81
// MSVC compiler. Reads and writes of volatile variables have
82
//                acquire and release memory semantics, respectively.
83
//                This is a Microsoft extension, not standard C++ behavior.
84
//
85
//   Update:      can't use this because of MinGW, built with gcc.
86
//                Original plan was to use gcc atomics for MinGW, but they
87
//                aren't supported, so we fold MinGW into this path.
88
89
#ifndef WIN32_LEAN_AND_MEAN
90
# define WIN32_LEAN_AND_MEAN
91
#endif
92
# define VC_EXTRALEAN
93
# define NOUSER
94
# define NOSERVICE
95
# define NOIME
96
# define NOMCX
97
# ifndef NOMINMAX
98
# define NOMINMAX
99
# endif
100
# include <windows.h>
101
102
U_NAMESPACE_BEGIN
103
typedef volatile LONG u_atomic_int32_t;
104
#define ATOMIC_INT32_T_INITIALIZER(val) val
105
106
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
107
    return InterlockedCompareExchange(&var, 0, 0);
108
}
109
110
inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
111
    InterlockedExchange(&var, val);
112
}
113
114
115
inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
116
    return InterlockedIncrement(var);
117
}
118
119
inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
120
    return InterlockedDecrement(var);
121
}
122
U_NAMESPACE_END
123
124
125
#elif U_HAVE_CLANG_ATOMICS
126
/*
127
 *  Clang __c11 atomic built-ins
128
 */
129
130
U_NAMESPACE_BEGIN
131
typedef _Atomic(int32_t) u_atomic_int32_t;
132
#define ATOMIC_INT32_T_INITIALIZER(val) val
133
134
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
135
     return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
136
}
137
138
inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
139
   return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
140
}
141
142
inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
143
    return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
144
}
145
146
inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
147
    return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
148
}
149
U_NAMESPACE_END
150
151
152
#elif U_HAVE_GCC_ATOMICS
153
/*
154
 * gcc atomic ops. These are available on several other compilers as well.
155
 */
156
157
U_NAMESPACE_BEGIN
158
typedef int32_t u_atomic_int32_t;
159
#define ATOMIC_INT32_T_INITIALIZER(val) val
160
161
inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
162
    int32_t val = var;
163
    __sync_synchronize();
164
    return val;
165
}
166
167
inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
168
    __sync_synchronize();
169
    var = val;
170
}
171
172
inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
173
   return __sync_add_and_fetch(p, 1);
174
}
175
176
inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
177
   return __sync_sub_and_fetch(p, 1);
178
}
179
U_NAMESPACE_END
180
181
#else
182
183
/*
184
 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
185
 *                   Slow but correct.
186
 */
187
188
#define U_NO_PLATFORM_ATOMICS
189
190
U_NAMESPACE_BEGIN
191
typedef int32_t u_atomic_int32_t;
192
#define ATOMIC_INT32_T_INITIALIZER(val) val
193
194
U_COMMON_API int32_t U_EXPORT2 
195
umtx_loadAcquire(u_atomic_int32_t &var);
196
197
U_COMMON_API void U_EXPORT2 
198
umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
199
200
U_COMMON_API int32_t U_EXPORT2 
201
umtx_atomic_inc(u_atomic_int32_t *p);
202
203
U_COMMON_API int32_t U_EXPORT2 
204
umtx_atomic_dec(u_atomic_int32_t *p);
205
206
U_NAMESPACE_END
207
208
#endif  /* Low Level Atomic Ops Platfrom Chain */
209
210
211
212
/*************************************************************************************************
213
 *
214
 *  UInitOnce Definitions.
215
 *     These are platform neutral.
216
 *
217
 *************************************************************************************************/
218
219
U_NAMESPACE_BEGIN
220
221
struct UInitOnce {
222
    u_atomic_int32_t   fState;
223
    UErrorCode       fErrCode;
224
6.69k
    void reset() {fState = 0;};
225
0
    UBool isReset() {return umtx_loadAcquire(fState) == 0;};
226
// Note: isReset() is used by service registration code.
227
//                 Thread safety of this usage needs review.
228
};
229
230
#define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
231
232
233
U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
234
U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
235
236
template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
237
    if (umtx_loadAcquire(uio.fState) == 2) {
238
        return;
239
    }
240
    if (umtx_initImplPreInit(uio)) {
241
        (obj->*fp)();
242
        umtx_initImplPostInit(uio);
243
    }
244
}
245
246
247
// umtx_initOnce variant for plain functions, or static class functions.
248
//               No context parameter.
249
1.11k
inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
250
1.11k
    if (umtx_loadAcquire(uio.fState) == 2) {
251
0
        return;
252
0
    }
253
1.11k
    if (umtx_initImplPreInit(uio)) {
254
1.11k
        (*fp)();
255
1.11k
        umtx_initImplPostInit(uio);
256
1.11k
    }
257
1.11k
}
258
259
// umtx_initOnce variant for plain functions, or static class functions.
260
//               With ErrorCode, No context parameter.
261
2.23k
inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
262
2.23k
    if (U_FAILURE(errCode)) {
263
0
        return;
264
0
    }
265
2.23k
    if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
266
        // We run the initialization.
267
1.11k
        (*fp)(errCode);
268
1.11k
        uio.fErrCode = errCode;
269
1.11k
        umtx_initImplPostInit(uio);
270
1.11k
    } else {
271
        // Someone else already ran the initialization.
272
1.11k
        if (U_FAILURE(uio.fErrCode)) {
273
0
            errCode = uio.fErrCode;
274
0
        }
275
1.11k
    }
276
2.23k
}
277
278
// umtx_initOnce variant for plain functions, or static class functions,
279
//               with a context parameter.
280
template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
281
    if (umtx_loadAcquire(uio.fState) == 2) {
282
        return;
283
    }
284
    if (umtx_initImplPreInit(uio)) {
285
        (*fp)(context);
286
        umtx_initImplPostInit(uio);
287
    }
288
}
289
290
// umtx_initOnce variant for plain functions, or static class functions,
291
//               with a context parameter and an error code.
292
0
template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
293
0
    if (U_FAILURE(errCode)) {
294
0
        return;
295
0
    }
296
0
    if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
297
        // We run the initialization.
298
0
        (*fp)(context, errCode);
299
0
        uio.fErrCode = errCode;
300
0
        umtx_initImplPostInit(uio);
301
0
    } else {
302
        // Someone else already ran the initialization.
303
0
        if (U_FAILURE(uio.fErrCode)) {
304
0
            errCode = uio.fErrCode;
305
0
        }
306
0
    }
307
0
}
Unexecuted instantiation: void icu_59::umtx_initOnce<char const*>(icu_59::UInitOnce&, void (*)(char const*, UErrorCode&), char const*, UErrorCode&)
Unexecuted instantiation: void icu_59::umtx_initOnce<icu_59::Normalizer2Impl*>(icu_59::UInitOnce&, void (*)(icu_59::Normalizer2Impl*, UErrorCode&), icu_59::Normalizer2Impl*, UErrorCode&)
308
309
U_NAMESPACE_END
310
311
312
313
/*************************************************************************************************
314
 *
315
 *  Mutex Definitions. Platform Dependent, #if platform chain follows.
316
 *         TODO:  Add a C++11 version.
317
 *                Need to convert all mutex using files to C++ first.
318
 *
319
 *************************************************************************************************/
320
321
#if defined(U_USER_MUTEX_H)
322
// #inlcude "U_USER_MUTEX_H"
323
#include U_MUTEX_XSTR(U_USER_MUTEX_H)
324
325
#elif U_PLATFORM_USES_ONLY_WIN32_API
326
327
/* For CRITICAL_SECTION */
328
329
/*
330
 *   Note: there is an earlier include of windows.h in this file, but it is in
331
 *         different conditionals.
332
 *         This one is needed if we are using C++11 for atomic ops, but
333
 *         win32 APIs for Critical Sections.
334
 */
335
336
#ifndef WIN32_LEAN_AND_MEAN
337
# define WIN32_LEAN_AND_MEAN
338
#endif
339
# define VC_EXTRALEAN
340
# define NOUSER
341
# define NOSERVICE
342
# define NOIME
343
# define NOMCX
344
# ifndef NOMINMAX
345
# define NOMINMAX
346
# endif
347
# include <windows.h>
348
349
350
typedef struct UMutex {
351
    icu::UInitOnce    fInitOnce;
352
    CRITICAL_SECTION  fCS;
353
} UMutex;
354
355
/* Initializer for a static UMUTEX. Deliberately contains no value for the
356
 *  CRITICAL_SECTION.
357
 */
358
#define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
359
360
struct UConditionVar {
361
    HANDLE           fEntryGate;
362
    HANDLE           fExitGate;
363
    int32_t          fWaitCount;
364
};
365
366
#define U_CONDITION_INITIALIZER {NULL, NULL, 0}
367
    
368
369
370
#elif U_PLATFORM_IMPLEMENTS_POSIX
371
372
/*
373
 *  POSIX platform
374
 */
375
376
#include <pthread.h>
377
378
struct UMutex {
379
    pthread_mutex_t  fMutex;
380
};
381
typedef struct UMutex UMutex;
382
#define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
383
384
struct UConditionVar {
385
    pthread_cond_t   fCondition;
386
};
387
#define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
388
389
#else
390
391
/*
392
 *  Unknow platform type.
393
 *      This is an error condition. ICU requires mutexes.
394
 */
395
396
#error Unknown Platform.
397
398
#endif
399
400
401
402
/**************************************************************************************
403
 *
404
 *  Mutex Implementation function declaratations.
405
 *     Declarations are platform neutral.
406
 *     Implementations, in umutex.cpp, are platform specific.
407
 *
408
 ************************************************************************************/
409
410
/* Lock a mutex.
411
 * @param mutex The given mutex to be locked.  Pass NULL to specify
412
 *              the global ICU mutex.  Recursive locks are an error
413
 *              and may cause a deadlock on some platforms.
414
 */
415
U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
416
417
/* Unlock a mutex.
418
 * @param mutex The given mutex to be unlocked.  Pass NULL to specify
419
 *              the global ICU mutex.
420
 */
421
U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
422
423
/*
424
 * Wait on a condition variable.
425
 * The calling thread will unlock the mutex and wait on the condition variable.
426
 * The mutex must be locked by the calling thread when invoking this function.
427
 *
428
 * @param cond the condition variable to wait on.
429
 * @param mutex the associated mutex.
430
 */
431
432
U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
433
434
435
/*
436
 * Broadcast wakeup of all threads waiting on a Condition.
437
 * The associated mutex must be locked by the calling thread when calling
438
 * this function; this is a temporary ICU restriction.
439
 * 
440
 * @param cond the condition variable.
441
 */
442
U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
443
444
/*
445
 * Signal a condition variable, waking up one waiting thread.
446
 * CAUTION: Do not use. Place holder only. Not implemented for Windows.
447
 */
448
U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
449
450
#endif /* UMUTEX_H */
451
/*eof*/