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 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_atomic_ops.h"
15 :
16 : #include "cpl_config.h"
17 :
18 : // TODO: If C++11, use #include <atomic>.
19 :
20 : #if defined(_MSC_VER)
21 :
22 : #include <windows.h>
23 :
24 : int CPLAtomicAdd(volatile int *ptr, int increment)
25 : {
26 : return InterlockedExchangeAdd((volatile LONG *)(ptr), (LONG)(increment)) +
27 : increment;
28 : }
29 :
30 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
31 : {
32 : return (LONG)InterlockedCompareExchange((volatile LONG *)(ptr),
33 : (LONG)newval,
34 : (LONG)oldval) == (LONG)oldval;
35 : }
36 :
37 : #elif defined(__MINGW32__) && defined(__i386__)
38 :
39 : #include <windows.h>
40 :
41 : int CPLAtomicAdd(volatile int *ptr, int increment)
42 : {
43 : return InterlockedExchangeAdd((LONG *)(ptr), (LONG)(increment)) + increment;
44 : }
45 :
46 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
47 : {
48 : return (LONG)InterlockedCompareExchange((LONG *)(ptr), (LONG)newval,
49 : (LONG)oldval) == (LONG)oldval;
50 : }
51 :
52 : #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
53 :
54 37075400 : int CPLAtomicAdd(volatile int *ptr, int increment)
55 : {
56 37075400 : int temp = increment;
57 : __asm__ __volatile__("lock; xaddl %0,%1"
58 : : "+r"(temp), "+m"(*ptr)
59 : :
60 37075400 : : "memory");
61 37075700 : return temp + increment;
62 : }
63 :
64 3134400 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
65 : {
66 : unsigned char ret;
67 :
68 : __asm__ __volatile__(" lock; cmpxchgl %2,%1\n"
69 : " sete %0\n"
70 : : "=q"(ret), "=m"(*ptr)
71 : : "r"(newval), "m"(*ptr), "a"(oldval)
72 3134400 : : "memory");
73 :
74 3134400 : return static_cast<int>(ret);
75 : }
76 :
77 : #elif defined(HAVE_GCC_ATOMIC_BUILTINS)
78 : // Starting with GCC 4.1.0, built-in functions for atomic memory access are
79 : // provided. See:
80 : // http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
81 : // We use a ./configure test to determine whether this builtins are available.
82 : // as it appears that the GCC 4.1 version used on debian etch is broken when
83 : // linking such instructions.
84 : int CPLAtomicAdd(volatile int *ptr, int increment)
85 : {
86 : if (increment > 0)
87 : return __sync_add_and_fetch(ptr, increment);
88 :
89 : return __sync_sub_and_fetch(ptr, -increment);
90 : }
91 :
92 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
93 : {
94 : return __sync_bool_compare_and_swap(ptr, oldval, newval);
95 : }
96 :
97 : #elif defined(__MACH__) && defined(__APPLE__)
98 :
99 : #include <libkern/OSAtomic.h>
100 :
101 : int CPLAtomicAdd(volatile int *ptr, int increment)
102 : {
103 : return OSAtomicAdd32(increment, (int *)(ptr));
104 : }
105 :
106 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
107 : {
108 : return OSAtomicCompareAndSwap32(oldval, newval, (int *)(ptr));
109 : }
110 :
111 : #elif !defined(CPL_MULTIPROC_PTHREAD)
112 : #warning "Needs real lock API to implement properly atomic increment"
113 :
114 : // Dummy implementation.
115 : int CPLAtomicAdd(volatile int *ptr, int increment)
116 : {
117 : (*ptr) += increment;
118 : return *ptr;
119 : }
120 :
121 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
122 : {
123 : if (*ptr == oldval)
124 : {
125 : *ptr = newval;
126 : return TRUE;
127 : }
128 : return FALSE;
129 : }
130 :
131 : #else
132 :
133 : #include "cpl_multiproc.h"
134 :
135 : static CPLLock *hAtomicOpLock = nullptr;
136 :
137 : // Slow, but safe, implementation using a mutex.
138 : int CPLAtomicAdd(volatile int *ptr, int increment)
139 : {
140 : CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
141 : (*ptr) += increment;
142 : return *ptr;
143 : }
144 :
145 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
146 : {
147 : CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
148 : if (*ptr == oldval)
149 : {
150 : *ptr = newval;
151 : return TRUE;
152 : }
153 : return FALSE;
154 : }
155 :
156 : #endif
|