-
Notifications
You must be signed in to change notification settings - Fork 80
/
lockfree.h
68 lines (59 loc) · 2.04 KB
/
lockfree.h
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
#pragma once
#include "common.h"
#define HAS_ACQ(mo) ((mo) != __ATOMIC_RELAXED && (mo) != __ATOMIC_RELEASE)
#define HAS_RLS(mo) \
((mo) == __ATOMIC_RELEASE || (mo) == __ATOMIC_ACQ_REL || \
(mo) == __ATOMIC_SEQ_CST)
#define MO_LOAD(mo) (HAS_ACQ((mo)) ? __ATOMIC_ACQUIRE : __ATOMIC_RELAXED)
#define MO_STORE(mo) (HAS_RLS((mo)) ? __ATOMIC_RELEASE : __ATOMIC_RELAXED)
#include <stdbool.h>
union u128 {
struct {
uint64_t lo, hi;
} s;
__int128 ui;
};
ALWAYS_INLINE
static inline bool cmpxchg16b(__int128 *src, union u128 *cmp, union u128 with)
{
bool result;
__asm__ __volatile__("lock cmpxchg16b %1\n\tsetz %0"
: "=q"(result), "+m"(*src), "+d"(cmp->s.hi),
"+a"(cmp->s.lo)
: "c"(with.s.hi), "b"(with.s.lo)
: "cc", "memory");
return result;
}
ALWAYS_INLINE
static inline bool lockfree_compare_exchange_16(register __int128 *var,
__int128 *exp,
__int128 neu,
bool weak,
int mo_success,
int mo_failure)
{
(void) weak;
(void) mo_success;
(void) mo_failure;
union u128 cmp = {.ui = *exp}, with = {.ui = neu};
bool ret = cmpxchg16b(var, &cmp, with);
if (UNLIKELY(!ret))
*exp = cmp.ui;
return ret;
}
#define lockfree_compare_exchange_pp lockfree_compare_exchange_16
ALWAYS_INLINE
static inline uint32_t lockfree_fetch_umax_4(uint32_t *var,
uint32_t val,
int mo)
{
uint32_t old = __atomic_load_n(var, __ATOMIC_RELAXED);
do {
if (val <= old) {
return old;
}
} while (!__atomic_compare_exchange_n(
var, &old, val,
/*weak=*/true, MO_LOAD(mo) | MO_STORE(mo), MO_LOAD(mo)));
return old;
}