]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.c
ICU-400.37.tar.gz
[apple/icu.git] / icuSources / common / umutex.c
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
3*
46f4442e 4* Copyright (C) 1997-2008, International Business Machines
b75a7d8f
A
5* Corporation and others. All Rights Reserved.
6*
7******************************************************************************
8*
9* File CMUTEX.C
10*
11* Modification History:
12*
13* Date Name Description
14* 04/02/97 aliu Creation.
15* 04/07/99 srl updated
16* 05/13/99 stephen Changed to umutex (from cmutex).
17* 11/22/99 aliu Make non-global mutex autoinitialize [j151]
18******************************************************************************
19*/
20
73c04bcf
A
21#include "unicode/utypes.h"
22#include "uassert.h"
23#include "ucln_cmn.h"
24
25#if defined(U_DARWIN)
26#include <AvailabilityMacros.h>
27#if (ICU_USE_THREADS == 1) && defined(MAC_OS_X_VERSION_10_4) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
46f4442e
A
28#if defined(__STRICT_ANSI__)
29#define UPRV_REMAP_INLINE
30#define inline
31#endif
73c04bcf
A
32#include <libkern/OSAtomic.h>
33#define USE_MAC_OS_ATOMIC_INCREMENT 1
46f4442e
A
34#if defined(UPRV_REMAP_INLINE)
35#undef inline
36#undef UPRV_REMAP_INLINE
37#endif
73c04bcf
A
38#endif
39#endif
40
b75a7d8f
A
41/* Assume POSIX, and modify as necessary below */
42#define POSIX
43
73c04bcf 44#if defined(U_WINDOWS)
b75a7d8f
A
45#undef POSIX
46#endif
47#if defined(macintosh)
48#undef POSIX
49#endif
50#if defined(OS2)
51#undef POSIX
52#endif
53
b75a7d8f 54#if defined(POSIX) && (ICU_USE_THREADS==1)
b75a7d8f
A
55# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
56
b75a7d8f
A
57#endif /* POSIX && (ICU_USE_THREADS==1) */
58
73c04bcf 59#ifdef U_WINDOWS
b75a7d8f 60# define WIN32_LEAN_AND_MEAN
374ca955 61# define VC_EXTRALEAN
b75a7d8f
A
62# define NOUSER
63# define NOSERVICE
64# define NOIME
65# define NOMCX
66# include <windows.h>
67#endif
68
69#include "umutex.h"
70#include "cmemory.h"
71
374ca955
A
72/*
73 * A note on ICU Mutex Initialization and ICU startup:
74 *
75 * ICU mutexes, as used through the rest of the ICU code, are self-initializing.
76 * To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init
77 * of other ICU mutexes. For the global mutex itself, we need some other mechanism
78 * to safely initialize it on first use. This becomes important if two or more
79 * threads were more or less simultaenously the first to use ICU in a process, and
80 * were racing into the mutex initialization code.
81 *
82 * The solution for the global mutex init is platform dependent.
83 * On POSIX systems, C-style init can be used on a mutex, with the
84 * macro PTHREAD_MUTEX_INITIALIZER. The mutex is then ready for use, without
85 * first calling pthread_mutex_init().
86 *
87 * Windows has no equivalent statically initialized mutex or CRITICAL SECION.
88 * InitializeCriticalSection() must be called. If the global mutex does not
89 * appear to be initialized, a thread will create and initialize a new
90 * CRITICAL_SECTION, then use a Windows InterlockedCompareAndExchange to
91 * avoid problems with race conditions.
92 *
93 * If an application has overridden the ICU mutex implementation
94 * by calling u_setMutexFunctions(), the user supplied init function must
95 * be safe in the event that multiple threads concurrently attempt to init
96 * the same mutex. The first thread should do the init, and the others should
97 * have no effect.
98 *
99 */
100
46f4442e 101#define MAX_MUTEXES 40
374ca955
A
102static UMTX gGlobalMutex = NULL;
103static UMTX gIncDecMutex = NULL;
b75a7d8f 104#if (ICU_USE_THREADS == 1)
374ca955
A
105static UBool gMutexPoolInitialized = FALSE;
106static char gMutexesInUse[MAX_MUTEXES];
107
73c04bcf 108#if defined(U_WINDOWS)
374ca955
A
109/*-------------------------------------------------------------
110 *
111 * WINDOWS platform variable declarations
112 *
113 *-------------------------------------------------------------*/
114static CRITICAL_SECTION gMutexes[MAX_MUTEXES];
115static CRITICAL_SECTION gGlobalWinMutex;
116
117
118/* On WIN32 mutexes are reentrant. This makes it difficult to debug
119 * deadlocking problems that show up on POSIXy platforms, where
120 * mutexes deadlock upon reentry. ICU contains checking code for
121 * the global mutex as well as for other mutexes in the pool.
122 *
123 * This is for debugging purposes.
124 *
125 * This has no effect on non-WIN32 platforms, non-DEBUG builds, and
126 * non-ICU_USE_THREADS builds.
127 *
128 * Note: The CRITICAL_SECTION structure already has a RecursionCount
129 * member that can be used for this purpose, but portability to
130 * Win98/NT/2K needs to be tested before use. Works fine on XP.
131 * After portability is confirmed, the built-in RecursionCount can be
132 * used, and the gRecursionCountPool can be removed.
133 *
134 * Note: Non-global mutex checking only happens if there is no custom
135 * pMutexLockFn defined. Use one function, not two (don't use
136 * pMutexLockFn and pMutexUnlockFn) so the increment and decrement of
137 * the recursion count don't get out of sync. Users might set just
138 * one function, e.g., to perform a custom action, followed by a
139 * standard call to EnterCriticalSection.
140 */
141#if defined(U_DEBUG) && (ICU_USE_THREADS==1)
142static int32_t gRecursionCount = 0; /* detect global mutex locking */
143static int32_t gRecursionCountPool[MAX_MUTEXES]; /* ditto for non-global */
144#endif
b75a7d8f 145
b75a7d8f 146
374ca955
A
147#elif defined(POSIX)
148/*-------------------------------------------------------------
149 *
150 * POSIX platform variable declarations
151 *
152 *-------------------------------------------------------------*/
153static pthread_mutex_t gMutexes[MAX_MUTEXES] = {
154 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
155 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
156 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
157 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
158 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
159 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER,
160 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER
161};
b75a7d8f 162
374ca955
A
163#else
164/*-------------------------------------------------------------
165 *
166 * UNKNOWN platform declarations
167 *
168 *-------------------------------------------------------------*/
169static void *gMutexes[MAX_MUTEXES] = {
170 NULL, NULL, NULL,
171 NULL, NULL, NULL,
172 NULL, NULL, NULL,
173 NULL, NULL, NULL,
174 NULL, NULL, NULL,
175 NULL, NULL, NULL,
176 NULL, NULL };
177
178/* Unknown platform. OK so long as ICU_USE_THREAD is not set.
179 Note that user can still set mutex functions at run time,
180 and that the global mutex variable is still needed in that case. */
181#if (ICU_USE_THREADS == 1)
182#error no ICU mutex implementation for this platform
183#endif
b75a7d8f
A
184#endif
185#endif /* ICU_USE_THREADS==1 */
186
187
188
b75a7d8f 189
374ca955
A
190/*
191 * User mutex implementation functions. If non-null, call back to these rather than
192 * directly using the system (Posix or Windows) APIs.
193 * (declarations are in uclean.h)
194 */
195static UMtxInitFn *pMutexInitFn = NULL;
196static UMtxFn *pMutexDestroyFn = NULL;
197static UMtxFn *pMutexLockFn = NULL;
198static UMtxFn *pMutexUnlockFn = NULL;
199static const void *gMutexContext = NULL;
200
201
202
203/*
204 * umtx_lock
205 */
b75a7d8f
A
206U_CAPI void U_EXPORT2
207umtx_lock(UMTX *mutex)
208{
374ca955 209 if (mutex == NULL) {
b75a7d8f
A
210 mutex = &gGlobalMutex;
211 }
212
374ca955
A
213 if (*mutex == NULL) {
214 /* Lock of an uninitialized mutex. Initialize it before proceeding. */
215 umtx_init(mutex);
b75a7d8f
A
216 }
217
374ca955
A
218 if (pMutexLockFn != NULL) {
219 (*pMutexLockFn)(gMutexContext, mutex);
220 } else {
b75a7d8f 221
374ca955 222#if (ICU_USE_THREADS == 1)
73c04bcf 223#if defined(U_WINDOWS)
374ca955 224 EnterCriticalSection((CRITICAL_SECTION*) *mutex);
b75a7d8f 225#elif defined(POSIX)
374ca955
A
226 pthread_mutex_lock((pthread_mutex_t*) *mutex);
227#endif /* cascade of platforms */
228#endif /* ICU_USE_THREADS==1 */
229 }
b75a7d8f 230
73c04bcf 231#if defined(U_WINDOWS) && defined(U_DEBUG) && (ICU_USE_THREADS==1)
374ca955
A
232 if (mutex == &gGlobalMutex) { /* Detect Reentrant locking of the global mutex. */
233 gRecursionCount++; /* Recursion causes deadlocks on Unixes. */
234 U_ASSERT(gRecursionCount == 1); /* Detection works on Windows. Debug problems there. */
b75a7d8f 235 }
374ca955
A
236 /* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
237 else if (pMutexLockFn == NULL) { /* see comments above */
73c04bcf 238 size_t i = ((CRITICAL_SECTION*)*mutex) - &gMutexes[0];
374ca955
A
239 U_ASSERT(i >= 0 && i < MAX_MUTEXES);
240 ++gRecursionCountPool[i];
241
242 U_ASSERT(gRecursionCountPool[i] == 1); /* !Detect Deadlock! */
243
244 /* This works and is fast, but needs testing on Win98/NT/2K.
245 See comments above. [alan]
246 U_ASSERT((CRITICAL_SECTION*)*mutex >= &gMutexes[0] &&
247 (CRITICAL_SECTION*)*mutex <= &gMutexes[MAX_MUTEXES]);
248 U_ASSERT(((CRITICAL_SECTION*)*mutex)->RecursionCount == 1);
249 */
250 }
251#endif /*U_DEBUG*/
b75a7d8f
A
252}
253
374ca955
A
254
255
256/*
257 * umtx_unlock
258 */
b75a7d8f
A
259U_CAPI void U_EXPORT2
260umtx_unlock(UMTX* mutex)
261{
374ca955 262 if(mutex == NULL) {
b75a7d8f
A
263 mutex = &gGlobalMutex;
264 }
265
374ca955
A
266 if(*mutex == NULL) {
267#if (ICU_USE_THREADS == 1)
268 U_ASSERT(FALSE); /* This mutex is not initialized. */
269#endif
270 return;
b75a7d8f
A
271 }
272
73c04bcf 273#if defined (U_WINDOWS) && defined (U_DEBUG) && (ICU_USE_THREADS==1)
b75a7d8f
A
274 if (mutex == &gGlobalMutex) {
275 gRecursionCount--;
374ca955 276 U_ASSERT(gRecursionCount == 0); /* Detect unlock of an already unlocked mutex */
b75a7d8f 277 }
374ca955
A
278 /* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
279 else if (pMutexLockFn == NULL) { /* see comments above */
73c04bcf 280 size_t i = ((CRITICAL_SECTION*)*mutex) - &gMutexes[0];
374ca955
A
281 U_ASSERT(i >= 0 && i < MAX_MUTEXES);
282 --gRecursionCountPool[i];
283
284 U_ASSERT(gRecursionCountPool[i] == 0); /* !Detect Deadlock! */
285
286 /* This works and is fast, but needs testing on Win98/NT/2K.
287 Note that RecursionCount will be 1, not 0, since we haven't
288 left the CRITICAL_SECTION yet. See comments above. [alan]
289 U_ASSERT((CRITICAL_SECTION*)*mutex >= &gMutexes[0] &&
290 (CRITICAL_SECTION*)*mutex <= &gMutexes[MAX_MUTEXES]);
291 U_ASSERT(((CRITICAL_SECTION*)*mutex)->RecursionCount == 1);
292 */
b75a7d8f
A
293 }
294#endif
295
374ca955
A
296 if (pMutexUnlockFn) {
297 (*pMutexUnlockFn)(gMutexContext, mutex);
298 } else {
299#if (ICU_USE_THREADS==1)
73c04bcf 300#if defined (U_WINDOWS)
374ca955
A
301 LeaveCriticalSection((CRITICAL_SECTION*)*mutex);
302#elif defined (POSIX)
303 pthread_mutex_unlock((pthread_mutex_t*)*mutex);
304#endif /* cascade of platforms */
b75a7d8f 305#endif /* ICU_USE_THREADS == 1 */
374ca955 306 }
b75a7d8f
A
307}
308
309
310
374ca955 311
b75a7d8f 312/*
374ca955
A
313 * initGlobalMutex Do the platform specific initialization of the ICU global mutex.
314 * Separated out from the other mutexes because it is different:
315 * Mutex storage is static for POSIX, init must be thread safe
316 * without the use of another mutex.
b75a7d8f 317 */
374ca955
A
318static void initGlobalMutex() {
319 /*
320 * If User Supplied mutex functions are in use
321 * init the icu global mutex using them.
322 */
323 if (pMutexInitFn != NULL) {
324 if (gGlobalMutex==NULL) {
325 UErrorCode status = U_ZERO_ERROR;
326 (*pMutexInitFn)(gMutexContext, &gGlobalMutex, &status);
327 if (U_FAILURE(status)) {
328 /* TODO: how should errors here be handled? */
329 return;
330 }
331 }
332 return;
333 }
334
335 /* No user override of mutex functions.
336 * Use default ICU mutex implementations.
337 */
b75a7d8f 338#if (ICU_USE_THREADS == 1)
374ca955
A
339 /*
340 * for Windows, init the pool of critical sections that we
341 * will use as needed for ICU mutexes.
342 */
73c04bcf 343#if defined (U_WINDOWS)
374ca955
A
344 if (gMutexPoolInitialized == FALSE) {
345 int i;
346 for (i=0; i<MAX_MUTEXES; i++) {
347 InitializeCriticalSection(&gMutexes[i]);
348#if defined (U_DEBUG)
349 gRecursionCountPool[i] = 0; /* see comments above */
350#endif
b75a7d8f 351 }
374ca955
A
352 gMutexPoolInitialized = TRUE;
353 }
46f4442e
A
354#elif defined (U_DARWIN)
355 /* PTHREAD_MUTEX_INITIALIZER works, don't need to call pthread_mutex_init
356 * as below (which is subject to a race condition)
357 */
358 gMutexPoolInitialized = TRUE;
374ca955
A
359#elif defined (POSIX)
360 /* TODO: experimental code. Shouldn't need to explicitly init the mutexes. */
361 if (gMutexPoolInitialized == FALSE) {
362 int i;
363 for (i=0; i<MAX_MUTEXES; i++) {
364 pthread_mutex_init(&gMutexes[i], NULL);
b75a7d8f 365 }
374ca955
A
366 gMutexPoolInitialized = TRUE;
367 }
368#endif
369
370 /*
371 * for both Windows & POSIX, the first mutex in the array is used
372 * for the ICU global mutex.
373 */
374 gGlobalMutex = &gMutexes[0];
375 gMutexesInUse[0] = 1;
376
377#else /* ICU_USE_THREADS */
378 gGlobalMutex = &gGlobalMutex; /* With no threads, we must still set the mutex to
379 * some non-null value to make the rest of the
380 * (not ifdefed) mutex code think that it is initialized.
381 */
382#endif /* ICU_USE_THREADS */
b75a7d8f 383}
b75a7d8f
A
384
385
b75a7d8f 386
b75a7d8f 387
b75a7d8f 388
374ca955
A
389U_CAPI void U_EXPORT2
390umtx_init(UMTX *mutex)
391{
392 if (mutex == NULL || mutex == &gGlobalMutex) {
393 initGlobalMutex();
b75a7d8f 394 } else {
b75a7d8f 395 umtx_lock(NULL);
374ca955
A
396 if (*mutex != NULL) {
397 /* Another thread initialized this mutex first. */
398 umtx_unlock(NULL);
b75a7d8f
A
399 return;
400 }
401
374ca955
A
402 if (pMutexInitFn != NULL) {
403 UErrorCode status = U_ZERO_ERROR;
404 (*pMutexInitFn)(gMutexContext, mutex, &status);
405 /* TODO: how to report failure on init? */
406 umtx_unlock(NULL);
407 return;
408 }
409 else {
410#if (ICU_USE_THREADS == 1)
411 /* Search through our pool of pre-allocated mutexes for one that is not
412 * already in use. */
413 int i;
414 for (i=0; i<MAX_MUTEXES; i++) {
415 if (gMutexesInUse[i] == 0) {
416 gMutexesInUse[i] = 1;
417 *mutex = &gMutexes[i];
418 break;
419 }
420 }
421#endif
b75a7d8f
A
422 }
423 umtx_unlock(NULL);
374ca955
A
424
425#if (ICU_USE_THREADS == 1)
426 /* No more mutexes were available from our pre-allocated pool. */
427 /* TODO: how best to deal with this? */
428 U_ASSERT(*mutex != NULL);
429#endif
b75a7d8f 430 }
b75a7d8f
A
431}
432
374ca955
A
433
434/*
435 * umtx_destroy. Un-initialize a mutex, releasing any underlying resources
436 * that it may be holding. Destroying an already destroyed
437 * mutex has no effect. Unlike umtx_init(), this function
438 * is not thread safe; two threads must not concurrently try to
439 * destroy the same mutex.
440 */
b75a7d8f
A
441U_CAPI void U_EXPORT2
442umtx_destroy(UMTX *mutex) {
374ca955 443 if (mutex == NULL) { /* destroy the global mutex */
b75a7d8f
A
444 mutex = &gGlobalMutex;
445 }
374ca955
A
446
447 if (*mutex == NULL) { /* someone already did it. */
b75a7d8f 448 return;
374ca955 449 }
b75a7d8f 450
374ca955
A
451 /* The life of the inc/dec mutex is tied to that of the global mutex. */
452 if (mutex == &gGlobalMutex) {
453 umtx_destroy(&gIncDecMutex);
454 }
b75a7d8f 455
374ca955
A
456 if (pMutexDestroyFn != NULL) {
457 /* Mutexes are being managed by the app. Call back to it for the destroy. */
458 (*pMutexDestroyFn)(gMutexContext, mutex);
459 }
460 else {
461#if (ICU_USE_THREADS == 1)
462 /* Return this mutex to the pool of available mutexes, if it came from the
463 * pool in the first place.
464 */
465 /* TODO use pointer math here, instead of iterating! */
466 int i;
467 for (i=0; i<MAX_MUTEXES; i++) {
468 if (*mutex == &gMutexes[i]) {
469 gMutexesInUse[i] = 0;
470 break;
471 }
472 }
b75a7d8f 473#endif
b75a7d8f
A
474 }
475
476 *mutex = NULL;
b75a7d8f
A
477}
478
479
b75a7d8f 480
374ca955
A
481U_CAPI void U_EXPORT2
482u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
483 UErrorCode *status) {
484 if (U_FAILURE(*status)) {
485 return;
486 }
b75a7d8f 487
374ca955
A
488 /* Can not set a mutex function to a NULL value */
489 if (i==NULL || d==NULL || l==NULL || u==NULL) {
490 *status = U_ILLEGAL_ARGUMENT_ERROR;
491 return;
492 }
b75a7d8f 493
374ca955
A
494 /* If ICU is not in an initial state, disallow this operation. */
495 if (cmemory_inUse()) {
496 *status = U_INVALID_STATE_ERROR;
497 return;
498 }
b75a7d8f 499
374ca955
A
500 /* Swap in the mutex function pointers. */
501 pMutexInitFn = i;
502 pMutexDestroyFn = d;
503 pMutexLockFn = l;
504 pMutexUnlockFn = u;
505 gMutexContext = context;
506 gGlobalMutex = NULL; /* For POSIX, the global mutex will be pre-initialized */
507 /* Undo that, force re-initialization when u_init() */
508 /* happens. */
b75a7d8f
A
509}
510
b75a7d8f 511
b75a7d8f 512
374ca955
A
513/*-----------------------------------------------------------------
514 *
515 * Atomic Increment and Decrement
516 * umtx_atomic_inc
517 * umtx_atomic_dec
518 *
519 *----------------------------------------------------------------*/
520
521/* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */
522static UMtxAtomicFn *pIncFn = NULL;
523static UMtxAtomicFn *pDecFn = NULL;
73c04bcf 524static const void *gIncDecContext = NULL;
b75a7d8f
A
525
526
527U_CAPI int32_t U_EXPORT2
374ca955
A
528umtx_atomic_inc(int32_t *p) {
529 int32_t retVal;
530 if (pIncFn) {
531 retVal = (*pIncFn)(gIncDecContext, p);
532 } else {
73c04bcf 533 #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
374ca955 534 retVal = InterlockedIncrement((LONG*)p);
73c04bcf
A
535 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
536 retVal = OSAtomicIncrement32Barrier(p);
374ca955
A
537 #elif defined (POSIX) && ICU_USE_THREADS == 1
538 umtx_lock(&gIncDecMutex);
539 retVal = ++(*p);
540 umtx_unlock(&gIncDecMutex);
541 #else
542 /* Unknown Platform, or ICU thread support compiled out. */
543 retVal = ++(*p);
544 #endif
545 }
546 return retVal;
547}
b75a7d8f 548
374ca955
A
549U_CAPI int32_t U_EXPORT2
550umtx_atomic_dec(int32_t *p) {
551 int32_t retVal;
552 if (pDecFn) {
553 retVal = (*pDecFn)(gIncDecContext, p);
554 } else {
73c04bcf 555 #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
374ca955 556 retVal = InterlockedDecrement((LONG*)p);
73c04bcf
A
557 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
558 retVal = OSAtomicDecrement32Barrier(p);
374ca955
A
559 #elif defined (POSIX) && ICU_USE_THREADS == 1
560 umtx_lock(&gIncDecMutex);
561 retVal = --(*p);
562 umtx_unlock(&gIncDecMutex);
563 #else
564 /* Unknown Platform, or ICU thread support compiled out. */
565 retVal = --(*p);
566 #endif
567 }
b75a7d8f
A
568 return retVal;
569}
570
374ca955 571/* TODO: Some POSIXy platforms have atomic inc/dec functions available. Use them. */
b75a7d8f 572
b75a7d8f 573
b75a7d8f
A
574
575
b75a7d8f 576
374ca955
A
577U_CAPI void U_EXPORT2
578u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
579 UErrorCode *status) {
374ca955
A
580 if (U_FAILURE(*status)) {
581 return;
582 }
583 /* Can not set a mutex function to a NULL value */
584 if (ip==NULL || dp==NULL) {
585 *status = U_ILLEGAL_ARGUMENT_ERROR;
586 return;
587 }
588 /* If ICU is not in an initial state, disallow this operation. */
589 if (cmemory_inUse()) {
590 *status = U_INVALID_STATE_ERROR;
591 return;
592 }
593
594 pIncFn = ip;
595 pDecFn = dp;
73c04bcf
A
596 gIncDecContext = context;
597
598#if !U_RELEASE
599 {
600 int32_t testInt = 0;
601 U_ASSERT(umtx_atomic_inc(&testInt) == 1); /* Sanity Check. Do the functions work at all? */
602 U_ASSERT(testInt == 1);
603 U_ASSERT(umtx_atomic_dec(&testInt) == 0);
604 U_ASSERT(testInt == 0);
605 }
606#endif
b75a7d8f
A
607}
608
b75a7d8f 609
b75a7d8f 610
374ca955
A
611/*
612 * Mutex Cleanup Function
613 *
614 * Destroy the global mutex(es), and reset the mutex function callback pointers.
615 */
616U_CFUNC UBool umtx_cleanup(void) {
617 umtx_destroy(NULL);
618 pMutexInitFn = NULL;
619 pMutexDestroyFn = NULL;
620 pMutexLockFn = NULL;
621 pMutexUnlockFn = NULL;
622 gMutexContext = NULL;
623 gGlobalMutex = NULL;
624 pIncFn = NULL;
625 pDecFn = NULL;
73c04bcf 626 gIncDecContext = NULL;
374ca955
A
627 gIncDecMutex = NULL;
628
629#if (ICU_USE_THREADS == 1)
630 if (gMutexPoolInitialized) {
631 int i;
632 for (i=0; i<MAX_MUTEXES; i++) {
633 if (gMutexesInUse[i]) {
73c04bcf 634#if defined (U_WINDOWS)
374ca955
A
635 DeleteCriticalSection(&gMutexes[i]);
636#elif defined (POSIX)
637 pthread_mutex_destroy(&gMutexes[i]);
638#endif
639 gMutexesInUse[i] = 0;
640 }
641 }
642 }
643 gMutexPoolInitialized = FALSE;
644#endif
b75a7d8f 645
374ca955
A
646 return TRUE;
647}
b75a7d8f
A
648
649