~ubuntu-branches/ubuntu/maverick/icu/maverick-updates

« back to all changes in this revision

Viewing changes to source/common/umutex.c

  • Committer: Package Import Robot
  • Author(s): Jay Berkenbilt
  • Date: 2009-09-04 11:56:06 UTC
  • mfrom: (10.1.6 sid)
  • Revision ID: package-import@ubuntu.com-20090904115606-sqxxuizelam5tozb
Tags: 4.2.1-3
Change install-doc target to not fail if there are subdirectories of
doc/html.  This is necessary to handle the doc/html/search directory
created by doxygen 3.6.1.  (Closes: #544799)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
******************************************************************************
 
3
*
 
4
*   Copyright (C) 1997-2008, International Business Machines
 
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
 
 
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)
 
28
#if defined(__STRICT_ANSI__)
 
29
#define UPRV_REMAP_INLINE
 
30
#define inline
 
31
#endif
 
32
#include <libkern/OSAtomic.h>
 
33
#define USE_MAC_OS_ATOMIC_INCREMENT 1
 
34
#if defined(UPRV_REMAP_INLINE)
 
35
#undef inline
 
36
#undef UPRV_REMAP_INLINE
 
37
#endif
 
38
#endif
 
39
#endif
 
40
 
 
41
/* Assume POSIX, and modify as necessary below */
 
42
#define POSIX
 
43
 
 
44
#if defined(U_WINDOWS)
 
45
#undef POSIX
 
46
#endif
 
47
#if defined(macintosh)
 
48
#undef POSIX
 
49
#endif
 
50
#if defined(OS2)
 
51
#undef POSIX
 
52
#endif
 
53
 
 
54
#if defined(POSIX) && (ICU_USE_THREADS==1)
 
55
# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
 
56
 
 
57
#endif /* POSIX && (ICU_USE_THREADS==1) */
 
58
 
 
59
#ifdef U_WINDOWS
 
60
# define WIN32_LEAN_AND_MEAN
 
61
# define VC_EXTRALEAN
 
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
 
 
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
 
 
101
#define  MAX_MUTEXES  40
 
102
static UMTX              gGlobalMutex          = NULL;
 
103
static UMTX              gIncDecMutex          = NULL;       
 
104
#if (ICU_USE_THREADS == 1)
 
105
static UBool             gMutexPoolInitialized = FALSE;
 
106
static char              gMutexesInUse[MAX_MUTEXES];   
 
107
 
 
108
#if defined(U_WINDOWS) 
 
109
/*-------------------------------------------------------------
 
110
 *
 
111
 *   WINDOWS  platform variable declarations
 
112
 *
 
113
 *-------------------------------------------------------------*/
 
114
static CRITICAL_SECTION  gMutexes[MAX_MUTEXES];
 
115
static 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)
 
142
static int32_t gRecursionCount = 0; /* detect global mutex locking */      
 
143
static int32_t gRecursionCountPool[MAX_MUTEXES]; /* ditto for non-global */
 
144
#endif
 
145
 
 
146
 
 
147
#elif defined(POSIX) 
 
148
/*-------------------------------------------------------------
 
149
 *
 
150
 *   POSIX   platform variable declarations
 
151
 *
 
152
 *-------------------------------------------------------------*/
 
153
static 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
};
 
162
 
 
163
#else 
 
164
/*-------------------------------------------------------------
 
165
 *
 
166
 *   UNKNOWN   platform  declarations
 
167
 *
 
168
 *-------------------------------------------------------------*/
 
169
static 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
 
184
#endif
 
185
#endif /* ICU_USE_THREADS==1 */
 
186
 
 
187
 
 
188
 
 
189
 
 
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
 */
 
195
static UMtxInitFn    *pMutexInitFn    = NULL;
 
196
static UMtxFn        *pMutexDestroyFn = NULL;
 
197
static UMtxFn        *pMutexLockFn    = NULL;
 
198
static UMtxFn        *pMutexUnlockFn  = NULL;
 
199
static const void    *gMutexContext   = NULL;
 
200
 
 
201
 
 
202
 
 
203
/*
 
204
 *   umtx_lock
 
205
 */
 
206
U_CAPI void  U_EXPORT2
 
207
umtx_lock(UMTX *mutex)
 
208
{
 
209
    if (mutex == NULL) {
 
210
        mutex = &gGlobalMutex;
 
211
    }
 
212
 
 
213
    if (*mutex == NULL) {
 
214
        /* Lock of an uninitialized mutex.  Initialize it before proceeding.   */
 
215
        umtx_init(mutex);    
 
216
    }
 
217
 
 
218
    if (pMutexLockFn != NULL) {
 
219
        (*pMutexLockFn)(gMutexContext, mutex);
 
220
    } else {
 
221
 
 
222
#if (ICU_USE_THREADS == 1)
 
223
#if defined(U_WINDOWS)
 
224
        EnterCriticalSection((CRITICAL_SECTION*) *mutex);
 
225
#elif defined(POSIX)
 
226
        pthread_mutex_lock((pthread_mutex_t*) *mutex);
 
227
#endif   /* cascade of platforms */
 
228
#endif /* ICU_USE_THREADS==1 */
 
229
    }
 
230
 
 
231
#if defined(U_WINDOWS) && defined(U_DEBUG) && (ICU_USE_THREADS==1)
 
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. */
 
235
    }
 
236
    /* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
 
237
    else if (pMutexLockFn == NULL) { /* see comments above */
 
238
        size_t i = ((CRITICAL_SECTION*)*mutex) - &gMutexes[0];
 
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*/
 
252
}
 
253
 
 
254
 
 
255
 
 
256
/*
 
257
 * umtx_unlock
 
258
 */
 
259
U_CAPI void  U_EXPORT2
 
260
umtx_unlock(UMTX* mutex)
 
261
{
 
262
    if(mutex == NULL) {
 
263
        mutex = &gGlobalMutex;
 
264
    }
 
265
 
 
266
    if(*mutex == NULL)    {
 
267
#if (ICU_USE_THREADS == 1)
 
268
        U_ASSERT(FALSE);  /* This mutex is not initialized.     */
 
269
#endif
 
270
        return; 
 
271
    }
 
272
 
 
273
#if defined (U_WINDOWS) && defined (U_DEBUG) && (ICU_USE_THREADS==1)
 
274
    if (mutex == &gGlobalMutex) {
 
275
        gRecursionCount--;
 
276
        U_ASSERT(gRecursionCount == 0);  /* Detect unlock of an already unlocked mutex */
 
277
    }
 
278
    /* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
 
279
    else if (pMutexLockFn == NULL) { /* see comments above */
 
280
        size_t i = ((CRITICAL_SECTION*)*mutex) - &gMutexes[0];
 
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
        */
 
293
    }
 
294
#endif
 
295
 
 
296
    if (pMutexUnlockFn) {
 
297
        (*pMutexUnlockFn)(gMutexContext, mutex);
 
298
    } else {
 
299
#if (ICU_USE_THREADS==1)
 
300
#if defined (U_WINDOWS)
 
301
        LeaveCriticalSection((CRITICAL_SECTION*)*mutex);
 
302
#elif defined (POSIX)
 
303
        pthread_mutex_unlock((pthread_mutex_t*)*mutex);
 
304
#endif  /* cascade of platforms */
 
305
#endif /* ICU_USE_THREADS == 1 */
 
306
    }
 
307
}
 
308
 
 
309
 
 
310
 
 
311
 
 
312
/*
 
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.
 
317
 */
 
318
static 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
     */
 
338
#if (ICU_USE_THREADS == 1)
 
339
    /*
 
340
     *  for Windows, init the pool of critical sections that we
 
341
     *    will use as needed for ICU mutexes.
 
342
     */
 
343
#if defined (U_WINDOWS)
 
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
 
351
        }
 
352
        gMutexPoolInitialized = TRUE;
 
353
    }
 
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;
 
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);
 
365
        }
 
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 */
 
383
}
 
384
 
 
385
 
 
386
 
 
387
 
 
388
 
 
389
U_CAPI void  U_EXPORT2
 
390
umtx_init(UMTX *mutex)
 
391
{
 
392
    if (mutex == NULL || mutex == &gGlobalMutex) {
 
393
        initGlobalMutex();
 
394
    } else {
 
395
        umtx_lock(NULL);
 
396
        if (*mutex != NULL) {
 
397
            /* Another thread initialized this mutex first. */
 
398
            umtx_unlock(NULL);
 
399
            return;
 
400
        }
 
401
 
 
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
 
422
        }
 
423
        umtx_unlock(NULL);
 
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
 
430
    }
 
431
}
 
432
 
 
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
 */                  
 
441
U_CAPI void  U_EXPORT2
 
442
umtx_destroy(UMTX *mutex) {
 
443
    if (mutex == NULL) {  /* destroy the global mutex */
 
444
        mutex = &gGlobalMutex;
 
445
    }
 
446
    
 
447
    if (*mutex == NULL) {  /* someone already did it. */
 
448
        return;
 
449
    }
 
450
 
 
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
    }
 
455
 
 
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
        }
 
473
#endif
 
474
    }
 
475
 
 
476
    *mutex = NULL;
 
477
}
 
478
 
 
479
 
 
480
 
 
481
U_CAPI void U_EXPORT2 
 
482
u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
 
483
                    UErrorCode *status) {
 
484
    if (U_FAILURE(*status)) {
 
485
        return;
 
486
    }
 
487
 
 
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
    }
 
493
 
 
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
    }
 
499
 
 
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.                                          */
 
509
}
 
510
 
 
511
 
 
512
 
 
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.  */
 
522
static UMtxAtomicFn  *pIncFn = NULL;
 
523
static UMtxAtomicFn  *pDecFn = NULL;
 
524
static const void *gIncDecContext  = NULL;
 
525
 
 
526
 
 
527
U_CAPI int32_t U_EXPORT2
 
528
umtx_atomic_inc(int32_t *p)  {
 
529
    int32_t retVal;
 
530
    if (pIncFn) {
 
531
        retVal = (*pIncFn)(gIncDecContext, p);
 
532
    } else {
 
533
        #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
 
534
            retVal = InterlockedIncrement((LONG*)p);
 
535
        #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
 
536
            retVal = OSAtomicIncrement32Barrier(p);
 
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
}
 
548
 
 
549
U_CAPI int32_t U_EXPORT2
 
550
umtx_atomic_dec(int32_t *p) {
 
551
    int32_t retVal;
 
552
    if (pDecFn) {
 
553
        retVal = (*pDecFn)(gIncDecContext, p);
 
554
    } else {
 
555
        #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
 
556
            retVal = InterlockedDecrement((LONG*)p);
 
557
        #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
 
558
            retVal = OSAtomicDecrement32Barrier(p);
 
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
    }
 
568
    return retVal;
 
569
}
 
570
 
 
571
/* TODO:  Some POSIXy platforms have atomic inc/dec functions available.  Use them. */
 
572
 
 
573
 
 
574
 
 
575
 
 
576
 
 
577
U_CAPI void U_EXPORT2
 
578
u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
 
579
                                UErrorCode *status) {
 
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;
 
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
 
607
}
 
608
 
 
609
 
 
610
 
 
611
/*
 
612
 *  Mutex Cleanup Function
 
613
 *
 
614
 *      Destroy the global mutex(es), and reset the mutex function callback pointers.
 
615
 */
 
616
U_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;
 
626
    gIncDecContext  = NULL;
 
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]) {
 
634
#if defined (U_WINDOWS)
 
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
 
645
 
 
646
    return TRUE;
 
647
}
 
648
 
 
649