Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: cpl_atomic_ops.cpp
4 : * Project: CPL - Common Portability Library
5 : * Purpose: Atomic operation functions.
6 : * Author: Even Rouault, <even dot rouault at spatialys.com>
7 : *
8 : **********************************************************************
9 : * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_atomic_ops.h"
31 :
32 : #include "cpl_config.h"
33 :
34 : // TODO: If C++11, use #include <atomic>.
35 :
36 : #if defined(_MSC_VER)
37 :
38 : #include <windows.h>
39 :
40 : int CPLAtomicAdd(volatile int *ptr, int increment)
41 : {
42 : return InterlockedExchangeAdd((volatile LONG *)(ptr), (LONG)(increment)) +
43 : increment;
44 : }
45 :
46 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
47 : {
48 : return (LONG)InterlockedCompareExchange((volatile LONG *)(ptr),
49 : (LONG)newval,
50 : (LONG)oldval) == (LONG)oldval;
51 : }
52 :
53 : #elif defined(__MINGW32__) && defined(__i386__)
54 :
55 : #include <windows.h>
56 :
57 : int CPLAtomicAdd(volatile int *ptr, int increment)
58 : {
59 : return InterlockedExchangeAdd((LONG *)(ptr), (LONG)(increment)) + increment;
60 : }
61 :
62 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
63 : {
64 : return (LONG)InterlockedCompareExchange((LONG *)(ptr), (LONG)newval,
65 : (LONG)oldval) == (LONG)oldval;
66 : }
67 :
68 : #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
69 :
70 27764800 : int CPLAtomicAdd(volatile int *ptr, int increment)
71 : {
72 27764800 : int temp = increment;
73 : __asm__ __volatile__("lock; xaddl %0,%1"
74 : : "+r"(temp), "+m"(*ptr)
75 : :
76 27764800 : : "memory");
77 27764800 : return temp + increment;
78 : }
79 :
80 2977790 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
81 : {
82 : unsigned char ret;
83 :
84 : __asm__ __volatile__(" lock; cmpxchgl %2,%1\n"
85 : " sete %0\n"
86 : : "=q"(ret), "=m"(*ptr)
87 : : "r"(newval), "m"(*ptr), "a"(oldval)
88 2977790 : : "memory");
89 :
90 2977790 : return static_cast<int>(ret);
91 : }
92 :
93 : #elif defined(HAVE_GCC_ATOMIC_BUILTINS)
94 : // Starting with GCC 4.1.0, built-in functions for atomic memory access are
95 : // provided. See:
96 : // http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
97 : // We use a ./configure test to determine whether this builtins are available.
98 : // as it appears that the GCC 4.1 version used on debian etch is broken when
99 : // linking such instructions.
100 : int CPLAtomicAdd(volatile int *ptr, int increment)
101 : {
102 : if (increment > 0)
103 : return __sync_add_and_fetch(ptr, increment);
104 :
105 : return __sync_sub_and_fetch(ptr, -increment);
106 : }
107 :
108 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
109 : {
110 : return __sync_bool_compare_and_swap(ptr, oldval, newval);
111 : }
112 :
113 : #elif defined(__MACH__) && defined(__APPLE__)
114 :
115 : #include <libkern/OSAtomic.h>
116 :
117 : int CPLAtomicAdd(volatile int *ptr, int increment)
118 : {
119 : return OSAtomicAdd32(increment, (int *)(ptr));
120 : }
121 :
122 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
123 : {
124 : return OSAtomicCompareAndSwap32(oldval, newval, (int *)(ptr));
125 : }
126 :
127 : #elif !defined(CPL_MULTIPROC_PTHREAD)
128 : #warning "Needs real lock API to implement properly atomic increment"
129 :
130 : // Dummy implementation.
131 : int CPLAtomicAdd(volatile int *ptr, int increment)
132 : {
133 : (*ptr) += increment;
134 : return *ptr;
135 : }
136 :
137 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
138 : {
139 : if (*ptr == oldval)
140 : {
141 : *ptr = newval;
142 : return TRUE;
143 : }
144 : return FALSE;
145 : }
146 :
147 : #else
148 :
149 : #include "cpl_multiproc.h"
150 :
151 : static CPLLock *hAtomicOpLock = nullptr;
152 :
153 : // Slow, but safe, implementation using a mutex.
154 : int CPLAtomicAdd(volatile int *ptr, int increment)
155 : {
156 : CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
157 : (*ptr) += increment;
158 : return *ptr;
159 : }
160 :
161 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
162 : {
163 : CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
164 : if (*ptr == oldval)
165 : {
166 : *ptr = newval;
167 : return TRUE;
168 : }
169 : return FALSE;
170 : }
171 :
172 : #endif
|