Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / common / umutex.c
1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 1997-2009, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 ******************************************************************************
8 *
9 * File umutex.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 /*
26  * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
27  * platform independent set of mutex operations.  For internal ICU use only.
28  */
29
30 #if defined(U_DARWIN)
31 #include <AvailabilityMacros.h>
32 #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)
33 #if defined(__STRICT_ANSI__)
34 #define UPRV_REMAP_INLINE
35 #define inline
36 #endif
37 #include <libkern/OSAtomic.h>
38 #define USE_MAC_OS_ATOMIC_INCREMENT 1
39 #if defined(UPRV_REMAP_INLINE)
40 #undef inline
41 #undef UPRV_REMAP_INLINE
42 #endif
43 #endif
44 #endif
45
46 /* Assume POSIX, and modify as necessary below */
47 #define POSIX
48
49 #if defined(U_WINDOWS)
50 #undef POSIX
51 #endif
52 #if defined(macintosh)
53 #undef POSIX
54 #endif
55 #if defined(OS2)
56 #undef POSIX
57 #endif
58
59 #if defined(POSIX) && (ICU_USE_THREADS==1)
60 # include <pthread.h> /* must be first, so that we get the multithread versions of things. */
61
62 #endif /* POSIX && (ICU_USE_THREADS==1) */
63
64 #ifdef U_WINDOWS
65 # define WIN32_LEAN_AND_MEAN
66 # define VC_EXTRALEAN
67 # define NOUSER
68 # define NOSERVICE
69 # define NOIME
70 # define NOMCX
71 # include <windows.h>
72 #endif
73
74 #include "umutex.h"
75 #include "cmemory.h"
76
77 /*
78  * A note on ICU Mutex Initialization and ICU startup:
79  *
80  *   ICU mutexes, as used through the rest of the ICU code, are self-initializing.
81  *   To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init
82  *   of other ICU mutexes.  For the global mutex itself, we need some other mechanism
83  *   to safely initialize it on first use.  This becomes important when two or more
84  *   threads are more or less simultaenously the first to use ICU in a process, and
85  *   are racing into the mutex initialization code.
86  *
87  *
88  *   The solution for the global mutex init is platform dependent.
89  *   On POSIX systems, plain C-style initialization can be used on a mutex, with the 
90  *   macro PTHREAD_MUTEX_INITIALIZER.  The mutex is then ready for use, without
91  *   first calling pthread_mutex_init().
92  *
93  *   Windows has no equivalent statically initialized mutex or CRITICAL SECION.
94  *   InitializeCriticalSection() must be called.  If the global mutex does not
95  *   appear to be initialized, a thread will create and initialize a new
96  *   CRITICAL_SECTION, then use a Windows InterlockedCompareAndExchange to
97  *   swap it in as the global mutex while avoid problems with race conditions.
98  */ 
99
100 /* On WIN32 mutexes are reentrant.  On POSIX platforms they are not, and a deadlock
101  *  will occur if a thread attempts to acquire a mutex it already has locked.
102  *  ICU mutexes (in debug builds) include checking code that will cause an assertion
103  *  failure if a mutex is reentered.  If you are having deadlock problems
104  *  on a POSIX machine, debugging may be easier on Windows.
105  */
106
107
108 #if (ICU_USE_THREADS == 0)
109 #define MUTEX_TYPE void *
110 #define PLATFORM_MUTEX_INIT(m) 
111 #define PLATFORM_MUTEX_LOCK(m) 
112 #define PLATFORM_MUTEX_UNLOCK(m) 
113 #define PLATFORM_MUTEX_DESTROY(m) 
114 #define PLATFORM_MUTEX_INITIALIZER NULL
115 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
116             mutexed_compare_and_swap(dest, newval, oldval)
117
118
119 #elif defined(U_WINDOWS)
120 #define MUTEX_TYPE CRITICAL_SECTION
121 #define PLATFORM_MUTEX_INIT(m) InitializeCriticalSection(m)
122 #define PLATFORM_MUTEX_LOCK(m) EnterCriticalSection(m)
123 #define PLATFORM_MUTEX_UNLOCK(m) LeaveCriticalSection(m)
124 #define PLATFORM_MUTEX_DESTROY(m) DeleteCriticalSection(m)
125 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
126             InterlockedCompareExchangePointer(dest, newval, oldval)
127
128
129 #elif defined(POSIX)
130 #define MUTEX_TYPE pthread_mutex_t   
131 #define PLATFORM_MUTEX_INIT(m) pthread_mutex_init(m, NULL)
132 #define PLATFORM_MUTEX_LOCK(m) pthread_mutex_lock(m)
133 #define PLATFORM_MUTEX_UNLOCK(m) pthread_mutex_unlock(m)
134 #define PLATFORM_MUTEX_DESTROY(m) pthread_mutex_destroy(m)
135 #define PLATFORM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
136 #if (U_HAVE_GCC_ATOMICS == 1)
137 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
138             __sync_val_compare_and_swap(dest, oldval, newval)
139 #else
140 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
141             mutexed_compare_and_swap(dest, newval, oldval)
142 #endif
143
144
145 #else   
146 /* Unknown platform.  Note that user can still set mutex functions at run time. */
147 #define MUTEX_TYPE void *
148 #define PLATFORM_MUTEX_INIT(m) 
149 #define PLATFORM_MUTEX_LOCK(m)
150 #define PLATFORM_MUTEX_UNLOCK(m) 
151 #define PLATFORM_MUTEX_DESTROY(m) 
152 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
153             mutexed_compare_and_swap(dest, newval, oldval)
154
155 #endif
156
157 /*  Forward declarations */
158 static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval);
159 typedef struct ICUMutex ICUMutex;
160
161 /*
162  * ICUMutex   One of these is set up for each UMTX that is used by other ICU code.
163  *            The opaque UMTX points to the corresponding ICUMutex struct.
164  *            
165  *            Because the total number of ICU mutexes is quite small, no effort has
166  *            been made to squeeze every byte out of this struct.
167  */
168 struct ICUMutex {
169     UMTX        *owner;             /* Points back to the UMTX corrsponding to this   */
170                                     /*    ICUMutex object.                            */
171     
172     UBool        heapAllocated;     /* Set if this ICUMutex is heap allocated, and    */
173                                     /*   will need to be deleted.  The global mutex   */
174                                     /*   is static on POSIX platforms; all others     */
175                                     /*   will be heap allocated.                      */
176
177     ICUMutex    *next;              /* All ICUMutexes are chained into a list so that  */
178                                     /*   they can be found and deleted by u_cleanup(). */
179
180     int32_t      recursionCount;    /* For debugging, detect recursive mutex locks.    */
181
182     MUTEX_TYPE   platformMutex;     /* The underlying OS mutex being wrapped.          */
183
184     UMTX         userMutex;         /* For use with u_setMutexFunctions operations,    */
185                                     /*    corresponds to platformMutex.                */
186 };
187
188
189 /*   The global ICU mutex.
190  *   For POSIX platforms, it gets a C style initialization, and is ready to use
191  *        at program startup.
192  *   For Windows, it will be lazily instantiated on first use.
193  */
194
195 #if defined(POSIX)
196 static UMTX  globalUMTX;
197 static ICUMutex globalMutex = {&globalUMTX, FALSE, NULL, 0, PLATFORM_MUTEX_INITIALIZER, NULL};
198 static UMTX  globalUMTX = &globalMutex;
199 #else
200 static UMTX  globalUMTX = NULL;
201 #endif
202
203 /* Head of the list of all ICU mutexes.
204  * Linked list is through ICUMutex::next
205  * Modifications to the list are synchronized with the global mutex.
206  * The list is used by u_cleanup(), which needs to dispose of all of the ICU mutexes.
207  *
208  * The statically initialized global mutex on POSIX platforms does not get added to this
209  * mutex list, but that's not a problem - the global mutex gets special handling
210  * during u_cleanup().
211  */
212 static ICUMutex *mutexListHead;
213
214
215 /*
216  *  User mutex implementation functions.  If non-null, call back to these rather than
217  *  directly using the system (Posix or Windows) APIs.  See u_setMutexFunctions().
218  *    (declarations are in uclean.h)
219  */
220 static UMtxInitFn    *pMutexInitFn    = NULL;
221 static UMtxFn        *pMutexDestroyFn = NULL;
222 static UMtxFn        *pMutexLockFn    = NULL;
223 static UMtxFn        *pMutexUnlockFn  = NULL;
224 static const void    *gMutexContext   = NULL;
225
226
227 /*
228  *   umtx_lock
229  */
230 U_CAPI void  U_EXPORT2
231 umtx_lock(UMTX *mutex)
232 {
233     ICUMutex *m;
234
235     if (mutex == NULL) {
236         mutex = &globalUMTX;
237     }
238     m = (ICUMutex *)*mutex;
239     if (m == NULL) {
240         /* See note on lazy initialization, above.  We can get away with it here, with mutexes,
241          * where we couldn't with normal user level data.
242          */
243         umtx_init(mutex);    
244         m = (ICUMutex *)*mutex;
245     }
246     U_ASSERT(m->owner == mutex);
247
248     if (pMutexLockFn != NULL) {
249         (*pMutexLockFn)(gMutexContext, &m->userMutex);
250     } else {
251         PLATFORM_MUTEX_LOCK(&m->platformMutex);
252     }
253
254 #if defined(U_DEBUG)
255     m->recursionCount++;              /* Recursion causes deadlock on Unixes.               */
256     U_ASSERT(m->recursionCount == 1); /* Recursion detection works on Windows.              */
257                                       /* Assertion failure on non-Windows indicates a       */
258                                       /*   problem with the mutex implementation itself.    */
259 #endif
260 }
261
262
263
264 /*
265  * umtx_unlock
266  */
267 U_CAPI void  U_EXPORT2
268 umtx_unlock(UMTX* mutex)
269 {
270     ICUMutex *m;
271     if(mutex == NULL) {
272         mutex = &globalUMTX;
273     }
274     m = (ICUMutex *)*mutex;
275     if (m == NULL) {
276         U_ASSERT(FALSE);  /* This mutex is not initialized.     */
277         return; 
278     }
279     U_ASSERT(m->owner == mutex);
280
281 #if defined (U_DEBUG)
282     m->recursionCount--;
283     U_ASSERT(m->recursionCount == 0);  /* Detect unlock of an already unlocked mutex */
284 #endif
285
286     if (pMutexUnlockFn) {
287         (*pMutexUnlockFn)(gMutexContext, &m->userMutex);
288     } else {
289         PLATFORM_MUTEX_UNLOCK(&m->platformMutex);
290     }
291 }
292
293
294 /* umtx_ct   Allocate and initialize a new ICUMutex.
295  *           If a non-null pointer is supplied, initialize an existing ICU Mutex.
296  */
297 static ICUMutex *umtx_ct(ICUMutex *m) {
298     if (m == NULL) {
299         m = (ICUMutex *)uprv_malloc(sizeof(ICUMutex));
300         m->heapAllocated = TRUE;
301     }
302     m->next = NULL;    /* List of mutexes is maintained at a higher level.  */
303     m->recursionCount = 0;
304     m->userMutex = NULL;
305     if (pMutexInitFn != NULL) {
306         UErrorCode status = U_ZERO_ERROR;
307         (*pMutexInitFn)(gMutexContext, &m->userMutex, &status);
308         U_ASSERT(U_SUCCESS(status));
309     } else {
310         PLATFORM_MUTEX_INIT(&m->platformMutex);
311     }
312     return m;
313 }
314
315
316 /* umtx_dt   Delete a ICUMutex.  Destroy the underlying OS Platform mutex.
317  *           Does not touch the linked list of ICU Mutexes.
318  */
319 static void umtx_dt(ICUMutex *m) {
320     if (pMutexDestroyFn != NULL) {
321         (*pMutexDestroyFn)(gMutexContext, &m->userMutex);
322         m->userMutex = NULL;
323     } else {
324         PLATFORM_MUTEX_DESTROY(&m->platformMutex);
325     }
326
327     if (m->heapAllocated) {
328         uprv_free(m);
329     }
330 }
331     
332
333 U_CAPI void  U_EXPORT2
334 umtx_init(UMTX *mutex) {
335     ICUMutex *m = NULL;
336     void *originalValue;
337
338     if (*mutex != NULL) {
339         /* Mutex is already initialized.  
340          * Multiple umtx_init()s of a UMTX by other ICU code are explicitly permitted.
341          */
342         return;
343     }
344 #if defined(POSIX)
345     if (mutex == &globalUMTX) {
346         m = &globalMutex;
347     }
348 #endif
349
350     m = umtx_ct(m);
351     originalValue = SYNC_COMPARE_AND_SWAP(mutex, NULL, m);
352     if (originalValue != NULL) {
353         umtx_dt(m);
354         return;
355     }
356
357     m->owner = mutex;
358
359     /* Hook the new mutex into the list of all ICU mutexes, so that we can find and
360      * delete it for u_cleanup().
361      */
362
363     umtx_lock(NULL);
364     m->next = mutexListHead;
365     mutexListHead = m;
366     umtx_unlock(NULL);
367     return;
368 }
369
370
371 /*
372  *  umtx_destroy.    Un-initialize a mutex, releasing any underlying resources
373  *                   that it may be holding.  Destroying an already destroyed
374  *                   mutex has no effect.  Unlike umtx_init(), this function
375  *                   is not thread safe;  two threads must not concurrently try to
376  *                   destroy the same mutex.
377  */                  
378 U_CAPI void  U_EXPORT2
379 umtx_destroy(UMTX *mutex) {
380     ICUMutex *m;
381     
382     /* No one should be deleting the global ICU mutex. 
383      *   (u_cleanup() does delete it, but does so explicitly, not by passing NULL)
384      */
385     U_ASSERT(mutex != NULL);
386     if (mutex == NULL) { 
387         return;
388     }
389     
390     m = (ICUMutex *)*mutex;
391     if (m == NULL) {  /* Mutex not initialized, or already destroyed.  */
392         return;
393     }
394
395     U_ASSERT(m->owner == mutex);
396     if (m->owner != mutex) {
397         return;
398     }
399
400     /* Remove this mutex from the linked list of mutexes.  */
401     umtx_lock(NULL);
402     if (mutexListHead == m) {
403         mutexListHead = m->next;
404     } else {
405         ICUMutex *prev;
406         for (prev = mutexListHead; prev!=NULL && prev->next!=m; prev = prev->next);
407             /*  Empty for loop body */
408         if (prev != NULL) {
409             prev->next = m->next;
410         }
411     }
412     umtx_unlock(NULL);
413
414     umtx_dt(m);        /* Delete the internal ICUMutex   */
415     *mutex = NULL;     /* Clear the caller's UMTX        */
416 }
417
418
419
420 U_CAPI void U_EXPORT2 
421 u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
422                     UErrorCode *status) {
423     if (U_FAILURE(*status)) {
424         return;
425     }
426
427     /* Can not set a mutex function to a NULL value  */
428     if (i==NULL || d==NULL || l==NULL || u==NULL) {
429         *status = U_ILLEGAL_ARGUMENT_ERROR;
430         return;
431     }
432
433     /* If ICU is not in an initial state, disallow this operation. */
434     if (cmemory_inUse()) {
435         *status = U_INVALID_STATE_ERROR;
436         return;
437     }
438     
439     /* Kill any existing global mutex.  POSIX platforms have a global mutex
440      * even before any other part of ICU is initialized.
441      */
442     umtx_destroy(&globalUMTX);
443
444     /* Swap in the mutex function pointers.  */
445     pMutexInitFn    = i;
446     pMutexDestroyFn = d;
447     pMutexLockFn    = l;
448     pMutexUnlockFn  = u;
449     gMutexContext   = context;
450
451 #if defined (POSIX) 
452     /* POSIX platforms must have a pre-initialized global mutex 
453      * to allow other mutexes to initialize safely. */
454     umtx_init(&globalUMTX);
455 #endif
456 }
457
458
459 /*   synchronized compare and swap function, for use when OS or compiler built-in
460  *   equivalents aren't available.
461  *
462  *   This operation relies on the ICU global mutex for synchronization.
463  *
464  *   There are two cases where this function can be entered when the global mutex is not
465  *   yet initialized - at the end  u_cleanup(), and at the end of u_setMutexFunctions, both
466  *   of which re-init the global mutex.  But neither function is thread-safe, so the lack of
467  *   synchronization at these points doesn't matter.
468  */
469 static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) {
470     void *temp;
471     UBool needUnlock = FALSE;
472
473     if (globalUMTX != NULL) {
474         umtx_lock(&globalUMTX);
475         needUnlock = TRUE;
476     }
477
478     temp = *dest;
479     if (temp == oldval) {
480         *dest = newval;
481     }
482     
483     if (needUnlock) {
484         umtx_unlock(&globalUMTX);
485     }
486     return temp;
487 }
488
489
490
491 /*-----------------------------------------------------------------
492  *
493  *  Atomic Increment and Decrement
494  *     umtx_atomic_inc
495  *     umtx_atomic_dec
496  *
497  *----------------------------------------------------------------*/
498
499 /* Pointers to user-supplied inc/dec functions.  Null if no funcs have been set.  */
500 static UMtxAtomicFn  *pIncFn = NULL;
501 static UMtxAtomicFn  *pDecFn = NULL;
502 static const void *gIncDecContext  = NULL;
503
504 static UMTX    gIncDecMutex = NULL;
505
506 U_CAPI int32_t U_EXPORT2
507 umtx_atomic_inc(int32_t *p)  {
508     int32_t retVal;
509     if (pIncFn) {
510         retVal = (*pIncFn)(gIncDecContext, p);
511     } else {
512         #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
513             retVal = InterlockedIncrement((LONG*)p);
514         #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
515             retVal = OSAtomicIncrement32Barrier(p);
516         #elif (U_HAVE_GCC_ATOMICS == 1)
517             retVal = __sync_add_and_fetch(p, 1);
518         #elif defined (POSIX) && ICU_USE_THREADS == 1
519             umtx_lock(&gIncDecMutex);
520             retVal = ++(*p);
521             umtx_unlock(&gIncDecMutex);
522         #else
523             /* Unknown Platform, or ICU thread support compiled out. */
524             retVal = ++(*p);
525         #endif
526     }
527     return retVal;
528 }
529
530 U_CAPI int32_t U_EXPORT2
531 umtx_atomic_dec(int32_t *p) {
532     int32_t retVal;
533     if (pDecFn) {
534         retVal = (*pDecFn)(gIncDecContext, p);
535     } else {
536         #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
537             retVal = InterlockedDecrement((LONG*)p);
538         #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
539             retVal = OSAtomicDecrement32Barrier(p);
540         #elif (U_HAVE_GCC_ATOMICS == 1)
541             retVal = __sync_sub_and_fetch(p, 1);
542         #elif defined (POSIX) && ICU_USE_THREADS == 1
543             umtx_lock(&gIncDecMutex);
544             retVal = --(*p);
545             umtx_unlock(&gIncDecMutex);
546         #else
547             /* Unknown Platform, or ICU thread support compiled out. */
548             retVal = --(*p);
549         #endif
550     }
551     return retVal;
552 }
553
554
555
556 U_CAPI void U_EXPORT2
557 u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
558                                 UErrorCode *status) {
559     if (U_FAILURE(*status)) {
560         return;
561     }
562     /* Can not set a mutex function to a NULL value  */
563     if (ip==NULL || dp==NULL) {
564         *status = U_ILLEGAL_ARGUMENT_ERROR;
565         return;
566     }
567     /* If ICU is not in an initial state, disallow this operation. */
568     if (cmemory_inUse()) {
569         *status = U_INVALID_STATE_ERROR;
570         return;
571     }
572
573     pIncFn = ip;
574     pDecFn = dp;
575     gIncDecContext = context;
576
577 #if !U_RELEASE
578     {
579         int32_t   testInt = 0;
580         U_ASSERT(umtx_atomic_inc(&testInt) == 1);     /* Sanity Check.    Do the functions work at all? */
581         U_ASSERT(testInt == 1);
582         U_ASSERT(umtx_atomic_dec(&testInt) == 0);
583         U_ASSERT(testInt == 0);
584     }
585 #endif
586 }
587
588
589
590 /*
591  *  Mutex Cleanup Function
592  *
593  *      Destroy the global mutex(es), and reset the mutex function callback pointers.
594  */
595 U_CFUNC UBool umtx_cleanup(void) {
596     ICUMutex *thisMutex = NULL;
597     ICUMutex *nextMutex = NULL;
598
599     /* Extra, do-nothing function call to suppress compiler warnings on platforms where
600      *   mutexed_compare_and_swap is not otherwise used.  */
601     mutexed_compare_and_swap(&globalUMTX, NULL, NULL);
602
603     /* Delete all of the ICU mutexes.  Do the global mutex last because it is used during
604      * the umtx_destroy operation of other mutexes.
605      */
606     for (thisMutex=mutexListHead; thisMutex!=NULL; thisMutex=nextMutex) {
607         UMTX *umtx = thisMutex->owner;
608         nextMutex = thisMutex->next;
609         U_ASSERT(*umtx = (void *)thisMutex);
610         if (umtx != &globalUMTX) {
611             umtx_destroy(umtx);
612         }
613     }
614     umtx_destroy(&globalUMTX);
615         
616     pMutexInitFn    = NULL;
617     pMutexDestroyFn = NULL;
618     pMutexLockFn    = NULL;
619     pMutexUnlockFn  = NULL;
620     gMutexContext   = NULL;
621     pIncFn          = NULL;
622     pDecFn          = NULL;
623     gIncDecContext  = NULL;
624     gIncDecMutex    = NULL;
625
626 #if defined (POSIX) 
627     /* POSIX platforms must come out of u_cleanup() with a functioning global mutex 
628      * to permit the safe resumption of use of ICU in multi-threaded environments. 
629      */
630     umtx_init(&globalUMTX);
631 #endif
632     return TRUE;
633 }
634
635