/src/gdal/port/cpl_atomic_ops.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | int CPLAtomicAdd(volatile int *ptr, int increment) |
55 | 19.4k | { |
56 | 19.4k | int temp = increment; |
57 | 19.4k | __asm__ __volatile__("lock; xaddl %0,%1" |
58 | 19.4k | : "+r"(temp), "+m"(*ptr) |
59 | 19.4k | : |
60 | 19.4k | : "memory"); |
61 | 19.4k | return temp + increment; |
62 | 19.4k | } |
63 | | |
64 | | int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval) |
65 | 0 | { |
66 | 0 | unsigned char ret; |
67 | |
|
68 | 0 | __asm__ __volatile__(" lock; cmpxchgl %2,%1\n" |
69 | 0 | " sete %0\n" |
70 | 0 | : "=q"(ret), "=m"(*ptr) |
71 | 0 | : "r"(newval), "m"(*ptr), "a"(oldval) |
72 | 0 | : "memory"); |
73 | |
|
74 | 0 | return static_cast<int>(ret); |
75 | 0 | } |
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 |