Fixes gcc8 build error:
[platform/upstream/db4.git] / dbinc / atomic.h
1 /*
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2009 Oracle.  All rights reserved.
5  *
6  * $Id$
7  */
8
9 #ifndef _DB_ATOMIC_H_
10 #define _DB_ATOMIC_H_
11
12 #if defined(__cplusplus)
13 extern "C" {
14 #endif
15
16 /*
17  *      Atomic operation support for Oracle Berkeley DB
18  *
19  * HAVE_ATOMIC_SUPPORT configures whether to use the assembly language
20  * or system calls to perform:
21  *
22  *       atomic_inc(env, valueptr)
23  *          Adds 1 to the db_atomic_t value, returning the new value.
24  *
25  *       atomic_dec(env, valueptr)
26  *          Subtracts 1 from the db_atomic_t value, returning the new value.
27  *
28  *       atomic_compare_exchange(env, valueptr, oldval, newval)
29  *          If the db_atomic_t's value is still oldval, set it to newval.
30  *          It returns 1 for success or 0 for failure.
31  *
32  * The ENV * paramter is used only when HAVE_ATOMIC_SUPPORT is undefined.
33  *
34  * If the platform does not natively support any one of these operations,
35  * then atomic operations will be emulated with this sequence:
36  *              MUTEX_LOCK()
37  *              <op>
38  *              MUTEX_UNLOCK();
39  * Uses where mutexes are not available (e.g. the environment has not yet
40  * attached to the mutex region) must be avoided.
41  */
42 #if defined(DB_WIN32)
43 typedef DWORD   atomic_value_t;
44 #else
45 typedef int32_t  atomic_value_t;
46 #endif
47
48 /*
49  * Windows CE has strange issues using the Interlocked APIs with variables
50  * stored in shared memory. It seems like the page needs to have been written
51  * prior to the API working as expected. Work around this by allocating an
52  * additional 32-bit value that can be harmlessly written for each value
53  * used in Interlocked instructions.
54  */
55 #if defined(DB_WINCE)
56 typedef struct {
57         volatile atomic_value_t value;
58         volatile atomic_value_t dummy;
59 } db_atomic_t;
60 #else
61 typedef struct {
62         volatile atomic_value_t value;
63 } db_atomic_t;
64 #endif
65
66 /*
67  * These macro hide the db_atomic_t structure layout and help detect
68  * non-atomic_t actual argument to the atomic_xxx() calls. DB requires
69  * aligned 32-bit reads to be atomic even outside of explicit 'atomic' calls.
70  * These have no memory barriers; the caller must include them when necessary.
71  */
72 #define atomic_read(p)          ((p)->value)
73 #define atomic_init(p, val)     ((p)->value = (val))
74
75 #ifdef HAVE_ATOMIC_SUPPORT
76
77 #if defined(DB_WIN32)
78 #if defined(DB_WINCE)
79 #define WINCE_ATOMIC_MAGIC(p)                                           \
80         /*                                                              \
81          * Memory mapped regions on Windows CE cause problems with      \
82          * InterlockedXXX calls. Each page in a mapped region needs to  \
83          * have been written to prior to an InterlockedXXX call, or the \
84          * InterlockedXXX call hangs. This does not seem to be          \
85          * documented anywhere. For now, read/write a non-critical      \
86          * piece of memory from the shared region prior to attempting   \
87          * shared region prior to attempting an InterlockedExchange     \
88          * InterlockedXXX operation.                                    \
89          */                                                             \
90         (p)->dummy = 0
91 #else
92 #define WINCE_ATOMIC_MAGIC(p) 0
93 #endif
94
95 #if defined(DB_WINCE) || (defined(_MSC_VER) && _MSC_VER < 1300)
96 /*
97  * The Interlocked instructions on Windows CE have different parameter
98  * definitions. The parameters lost their 'volatile' qualifier,
99  * cast it away, to avoid compiler warnings.
100  * These definitions should match those in dbinc/mutex_int.h for tsl_t, except
101  * that the WINCE version drops the volatile qualifier.
102  */
103 typedef PLONG interlocked_val;
104 #define atomic_inc(env, p)                                              \
105         (WINCE_ATOMIC_MAGIC(p),                                         \
106         InterlockedIncrement((interlocked_val)(&(p)->value)))
107
108 #else
109 typedef LONG volatile *interlocked_val;
110 #define atomic_inc(env, p)      \
111         InterlockedIncrement((interlocked_val)(&(p)->value))
112 #endif
113
114 #define atomic_dec(env, p)                                              \
115         (WINCE_ATOMIC_MAGIC(p),                                         \
116         InterlockedDecrement((interlocked_val)(&(p)->value)))
117 #if defined(_MSC_VER) && _MSC_VER < 1300
118 #define atomic_compare_exchange(env, p, oldval, newval)                 \
119         (WINCE_ATOMIC_MAGIC(p),                                         \
120         (InterlockedCompareExchange((PVOID *)(&(p)->value),             \
121         (PVOID)(newval), (PVOID)(oldval)) == (PVOID)(oldval)))
122 #else
123 #define atomic_compare_exchange(env, p, oldval, newval)                 \
124         (WINCE_ATOMIC_MAGIC(p),                                         \
125         (InterlockedCompareExchange((interlocked_val)(&(p)->value),     \
126         (newval), (oldval)) == (oldval)))
127 #endif
128 #endif
129
130 #if defined(HAVE_ATOMIC_SOLARIS)
131 /* Solaris sparc & x86/64 */
132 #include <atomic.h>
133 #define atomic_inc(env, p)      \
134         atomic_inc_uint_nv((volatile unsigned int *) &(p)->value)
135 #define atomic_dec(env, p)      \
136         atomic_dec_uint_nv((volatile unsigned int *) &(p)->value)
137 #define atomic_compare_exchange(env, p, oval, nval)             \
138         (atomic_cas_32((volatile unsigned int *) &(p)->value,   \
139             (oval), (nval)) == (oval))
140 #endif
141
142 #if defined(HAVE_ATOMIC_X86_GCC_ASSEMBLY)
143 /* x86/x86_64 gcc  */
144 #define atomic_inc(env, p)      __atomic_inc(p)
145 #define atomic_dec(env, p)      __atomic_dec(p)
146 #define atomic_compare_exchange(env, p, o, n)   \
147         __db_atomic_compare_exchange((p), (o), (n))
148 static inline int __atomic_inc(db_atomic_t *p)
149 {
150         int     temp;
151
152         temp = 1;
153         __asm__ __volatile__("lock; xadd %0, (%1)"
154                 : "+r"(temp)
155                 : "r"(p));
156         return (temp + 1);
157 }
158
159 static inline int __atomic_dec(db_atomic_t *p)
160 {
161         int     temp;
162
163         temp = -1;
164         __asm__ __volatile__("lock; xadd %0, (%1)"
165                 : "+r"(temp)
166                 : "r"(p));
167         return (temp - 1);
168 }
169
170 /*
171  * x86/gcc Compare exchange for shared latches. i486+
172  *      Returns 1 for success, 0 for failure
173  *
174  * GCC 4.1+ has an equivalent  __sync_bool_compare_and_swap() as well as
175  * __sync_val_compare_and_swap() which returns the value read from *dest
176  * http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
177  * which configure could be changed to use.
178  */
179 static inline int __db_atomic_compare_exchange(
180         db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
181 {
182         atomic_value_t was;
183
184         if (p->value != oldval) /* check without expensive cache line locking */
185                 return 0;
186         __asm__ __volatile__("lock; cmpxchgl %1, (%2);"
187             :"=a"(was)
188             :"r"(newval), "r"(p), "a"(oldval)
189             :"memory", "cc");
190         return (was == oldval);
191 }
192 #endif
193
194 #else
195 /*
196  * No native hardware support for atomic increment, decrement, and
197  * compare-exchange. Emulate them when mutexes are supported;
198  * do them without concern for atomicity when no mutexes.
199  */
200 #ifndef HAVE_MUTEX_SUPPORT
201 /*
202  * These minimal versions are correct to use only for single-threaded,
203  * single-process environments.
204  */
205 #define atomic_inc(env, p)      (++(p)->value)
206 #define atomic_dec(env, p)      (--(p)->value)
207 #define atomic_compare_exchange(env, p, oldval, newval)         \
208         (DB_ASSERT(env, atomic_read(p) == (oldval)),            \
209         atomic_init(p, (newval)), 1)
210 #else
211 #define atomic_inc(env, p)      __atomic_inc(env, p)
212 #define atomic_dec(env, p)      __atomic_dec(env, p)
213 #endif
214 #endif
215
216 #if defined(__cplusplus)
217 }
218 #endif
219
220 #endif /* !_DB_ATOMIC_H_ */