1/*
2**********************************************************************
3*   Copyright (C) 1997-2012, International Business Machines
4*   Corporation and others.  All Rights Reserved.
5**********************************************************************
6*
7* File UMUTEX.H
8*
9* Modification History:
10*
11*   Date        Name        Description
12*   04/02/97  aliu        Creation.
13*   04/07/99  srl         rewrite - C interface, multiple mutices
14*   05/13/99  stephen     Changed to umutex (from cmutex)
15******************************************************************************
16*/
17
18#ifndef UMUTEX_H
19#define UMUTEX_H
20
21#include "unicode/utypes.h"
22#include "unicode/uclean.h"
23#include "putilimp.h"
24
25/* For _ReadWriteBarrier(). */
26#if defined(_MSC_VER) && _MSC_VER >= 1500
27# include <intrin.h>
28#endif
29
30/* For CRITICAL_SECTION */
31#if U_PLATFORM_HAS_WIN32_API
32#if 0
33/* TODO(andy): Why doesn't windows.h compile in all files? It does in some.
34 *             The intent was to include windows.h here, and have struct UMutex
35 *             have an embedded CRITICAL_SECTION when building on Windows.
36 *             The workaround is to put some char[] storage in UMutex instead,
37 *             avoiding the need to include windows.h everwhere this header is included.
38 */
39# define WIN32_LEAN_AND_MEAN
40# define VC_EXTRALEAN
41# define NOUSER
42# define NOSERVICE
43# define NOIME
44# define NOMCX
45# include <windows.h>
46#endif  /* 0 */
47#define U_WINDOWS_CRIT_SEC_SIZE 64
48#endif  /* win32 */
49
50#if U_PLATFORM_IS_DARWIN_BASED
51#if defined(__STRICT_ANSI__)
52#define UPRV_REMAP_INLINE
53#define inline
54#endif
55#include <libkern/OSAtomic.h>
56#define USE_MAC_OS_ATOMIC_INCREMENT 1
57#if defined(UPRV_REMAP_INLINE)
58#undef inline
59#undef UPRV_REMAP_INLINE
60#endif
61#endif
62
63/*
64 * If we do not compile with dynamic_annotations.h then define
65 * empty annotation macros.
66 *  See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
67 */
68#ifndef ANNOTATE_HAPPENS_BEFORE
69# define ANNOTATE_HAPPENS_BEFORE(obj)
70# define ANNOTATE_HAPPENS_AFTER(obj)
71# define ANNOTATE_UNPROTECTED_READ(x) (x)
72#endif
73
74#ifndef UMTX_FULL_BARRIER
75# if U_HAVE_GCC_ATOMICS
76#  define UMTX_FULL_BARRIER __sync_synchronize();
77# elif defined(_MSC_VER) && _MSC_VER >= 1500
78    /* From MSVC intrin.h. Use _ReadWriteBarrier() only on MSVC 9 and higher. */
79#  define UMTX_FULL_BARRIER _ReadWriteBarrier();
80# elif U_PLATFORM_IS_DARWIN_BASED
81#  define UMTX_FULL_BARRIER OSMemoryBarrier();
82# else
83#  define UMTX_FULL_BARRIER \
84    { \
85        umtx_lock(NULL); \
86        umtx_unlock(NULL); \
87    }
88# endif
89#endif
90
91#ifndef UMTX_ACQUIRE_BARRIER
92# define UMTX_ACQUIRE_BARRIER UMTX_FULL_BARRIER
93#endif
94
95#ifndef UMTX_RELEASE_BARRIER
96# define UMTX_RELEASE_BARRIER UMTX_FULL_BARRIER
97#endif
98
99/**
100 * \def UMTX_CHECK
101 * Encapsulates a safe check of an expression
102 * for use with double-checked lazy inititialization.
103 * Either memory barriers or mutexes are required, to prevent both the hardware
104 * and the compiler from reordering operations across the check.
105 * The expression must involve only a  _single_ variable, typically
106 *    a possibly null pointer or a boolean that indicates whether some service
107 *    is initialized or not.
108 * The setting of the variable involved in the test must be the last step of
109 *    the initialization process.
110 *
111 * @internal
112 */
113#define UMTX_CHECK(pMutex, expression, result) \
114    { \
115        (result)=(expression); \
116        UMTX_ACQUIRE_BARRIER; \
117    }
118/*
119 * TODO: Replace all uses of UMTX_CHECK and surrounding code
120 * with SimpleSingleton or TriStateSingleton, and remove UMTX_CHECK.
121 */
122
123/*
124 * Code within ICU that accesses shared static or global data should
125 * instantiate a Mutex object while doing so.  The unnamed global mutex
126 * is used throughout ICU, so keep locking short and sweet.
127 *
128 * For example:
129 *
130 * void Function(int arg1, int arg2)
131 * {
132 *   static Object* foo;     // Shared read-write object
133 *   umtx_lock(NULL);        // Lock the ICU global mutex
134 *   foo->Method();
135 *   umtx_unlock(NULL);
136 * }
137 *
138 * an alternative C++ mutex API is defined in the file common/mutex.h
139 */
140
141/*
142 * UMutex - Mutexes for use by ICU implementation code.
143 *          Must be declared as static or globals. They cannot appear as members
144 *          of other objects.
145 *          UMutex structs must be initialized.
146 *          Example:
147 *            static UMutex = U_MUTEX_INITIALIZER;
148 *          The declaration of struct UMutex is platform dependent.
149 */
150
151
152#if U_PLATFORM_HAS_WIN32_API
153
154/*  U_INIT_ONCE mimics the windows API INIT_ONCE, which exists on Windows Vista and newer.
155 *  When ICU no longer needs to support older Windows platforms (XP) that do not have
156 * a native INIT_ONCE, switch this implementation over to wrap the native Windows APIs.
157 */
158typedef struct U_INIT_ONCE {
159    long               fState;
160    void              *fContext;
161} U_INIT_ONCE;
162#define U_INIT_ONCE_STATIC_INIT {0, NULL}
163
164typedef struct UMutex {
165    U_INIT_ONCE       fInitOnce;
166    UMTX              fUserMutex;
167    UBool             fInitialized;  /* Applies to fUserMutex only. */
168    /* CRITICAL_SECTION  fCS; */  /* See note above. Unresolved problems with including
169                                   * Windows.h, which would allow using CRITICAL_SECTION
170                                   * directly here. */
171    char              fCS[U_WINDOWS_CRIT_SEC_SIZE];
172} UMutex;
173
174/* Initializer for a static UMUTEX. Deliberately contains no value for the
175 *  CRITICAL_SECTION.
176 */
177#define U_MUTEX_INITIALIZER {U_INIT_ONCE_STATIC_INIT, NULL, FALSE}
178
179#elif U_PLATFORM_IMPLEMENTS_POSIX
180#include <pthread.h>
181
182struct UMutex {
183    pthread_mutex_t  fMutex;
184    UMTX             fUserMutex;
185    UBool            fInitialized;
186};
187#define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER, NULL, FALSE}
188
189#else
190/* Unknow platform type. */
191struct UMutex {
192    void *fMutex;
193};
194#define U_MUTEX_INITIALIZER {NULL}
195#error Unknown Platform.
196
197#endif
198
199#if (U_PLATFORM != U_PF_CYGWIN && U_PLATFORM != U_PF_MINGW) || defined(CYGWINMSVC)
200typedef struct UMutex UMutex;
201#endif
202
203/* Lock a mutex.
204 * @param mutex The given mutex to be locked.  Pass NULL to specify
205 *              the global ICU mutex.  Recursive locks are an error
206 *              and may cause a deadlock on some platforms.
207 */
208U_CAPI void U_EXPORT2 umtx_lock(UMutex* mutex);
209
210/* Unlock a mutex.
211 * @param mutex The given mutex to be unlocked.  Pass NULL to specify
212 *              the global ICU mutex.
213 */
214U_CAPI void U_EXPORT2 umtx_unlock (UMutex* mutex);
215
216/*
217 * Atomic Increment and Decrement of an int32_t value.
218 *
219 * Return Values:
220 *   If the result of the operation is zero, the return zero.
221 *   If the result of the operation is not zero, the sign of returned value
222 *      is the same as the sign of the result, but the returned value itself may
223 *      be different from the result of the operation.
224 */
225U_CAPI int32_t U_EXPORT2 umtx_atomic_inc(int32_t *);
226U_CAPI int32_t U_EXPORT2 umtx_atomic_dec(int32_t *);
227
228#endif /*_CMUTEX*/
229/*eof*/
230