Coverage Report

Created: 2025-06-13 06:18

/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
0
{
56
0
    int temp = increment;
57
0
    __asm__ __volatile__("lock; xaddl %0,%1"
58
0
                         : "+r"(temp), "+m"(*ptr)
59
0
                         :
60
0
                         : "memory");
61
0
    return temp + increment;
62
0
}
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