summaryrefslogtreecommitdiffstats
path: root/deps/hdr_histogram/hdr_atomic.h
blob: ae1056a83612af5e370ce12fea82f334fce0c62c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
 * hdr_atomic.h
 * Written by Philip Orwig and released to the public domain,
 * as explained at http://creativecommons.org/publicdomain/zero/1.0/
 */

#ifndef HDR_ATOMIC_H__
#define HDR_ATOMIC_H__


#if defined(_MSC_VER)

#include <stdint.h>
#include <intrin.h>
#include <stdbool.h>

static void __inline * hdr_atomic_load_pointer(void** pointer)
{
	_ReadBarrier();
	return *pointer;
}

static void hdr_atomic_store_pointer(void** pointer, void* value)
{
	_WriteBarrier();
	*pointer = value;
}

static int64_t __inline hdr_atomic_load_64(int64_t* field)
{ 
	_ReadBarrier();
	return *field;
}

static void __inline hdr_atomic_store_64(int64_t* field, int64_t value)
{
	_WriteBarrier();
	*field = value;
}

static int64_t __inline hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
{
#if defined(_WIN64)
    return _InterlockedExchange64(field, value);
#else
    int64_t comparand;
    int64_t initial_value = *field;
    do
    {
        comparand = initial_value;
        initial_value = _InterlockedCompareExchange64(field, value, comparand);
    }
    while (comparand != initial_value);

    return initial_value;
#endif
}

static int64_t __inline hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
{
#if defined(_WIN64)
	return _InterlockedExchangeAdd64(field, value) + value;
#else
    int64_t comparand;
    int64_t initial_value = *field;
    do
    {
        comparand = initial_value;
        initial_value = _InterlockedCompareExchange64(field, comparand + value, comparand);
    }
    while (comparand != initial_value);

    return initial_value + value;
#endif
}

static bool __inline hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
{
    return *expected == _InterlockedCompareExchange64(field, desired, *expected);
}

#elif defined(__ATOMIC_SEQ_CST)

#define hdr_atomic_load_pointer(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
#define hdr_atomic_store_pointer(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
#define hdr_atomic_load_64(x) __atomic_load_n(x, __ATOMIC_SEQ_CST)
#define hdr_atomic_store_64(f,v) __atomic_store_n(f,v, __ATOMIC_SEQ_CST)
#define hdr_atomic_exchange_64(f,i) __atomic_exchange_n(f,i, __ATOMIC_SEQ_CST)
#define hdr_atomic_add_fetch_64(field, value) __atomic_add_fetch(field, value, __ATOMIC_SEQ_CST)
#define hdr_atomic_compare_exchange_64(field, expected, desired) __atomic_compare_exchange_n(field, expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)

#elif defined(__x86_64__)

#include <stdint.h>
#include <stdbool.h>

static inline void* hdr_atomic_load_pointer(void** pointer)
{
   void* p =  *pointer;
	asm volatile ("" ::: "memory");
	return p;
}

static inline void hdr_atomic_store_pointer(void** pointer, void* value)
{
    asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*pointer));
}

static inline int64_t hdr_atomic_load_64(int64_t* field)
{
    int64_t i = *field;
	asm volatile ("" ::: "memory");
	return i;
}

static inline void hdr_atomic_store_64(int64_t* field, int64_t value)
{
    asm volatile ("lock; xchgq %0, %1" : "+q" (value), "+m" (*field));
}

static inline int64_t hdr_atomic_exchange_64(volatile int64_t* field, int64_t value)
{
    int64_t result = 0;
    asm volatile ("lock; xchgq %1, %2" : "=r" (result), "+q" (value), "+m" (*field));
    return result;
}

static inline int64_t hdr_atomic_add_fetch_64(volatile int64_t* field, int64_t value)
{
    return __sync_add_and_fetch(field, value);
}

static inline bool hdr_atomic_compare_exchange_64(volatile int64_t* field, int64_t* expected, int64_t desired)
{
    int64_t original;
    asm volatile( "lock; cmpxchgq %2, %1" : "=a"(original), "+m"(*field) : "q"(desired), "0"(*expected));
    return original == *expected;
}

#else

#error "Unable to determine atomic operations for your platform"

#endif

#endif /* HDR_ATOMIC_H__ */