1/*
2 * Copyright 2008-2018 Aerospike, Inc.
3 *
4 * Portions may be licensed to Aerospike, Inc. under one or more contributor
5 * license agreements.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8 * use this file except in compliance with the License. You may obtain a copy of
9 * the License at http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17#pragma once
18
19/**
20 * SYNOPSIS
21 * Atomic memory operations
22 * Memory barriers
23 *
24 * cf_atomicX_add
25 * Atomic addition: add a value b into an atomic integer a, and return the result
26 **/
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
32// Concurrency kit needs to be under extern "C" when compiling C++.
33#include <aerospike/ck/ck_pr.h>
34
35/******************************************************************************
36 * TYPES
37 *****************************************************************************/
38
39#define SIZEOF_ATOMIC_INT 8
40typedef volatile uint64_t cf_atomic64;
41typedef volatile uint32_t cf_atomic32;
42typedef volatile uint64_t cf_atomic_p;
43typedef volatile uint64_t cf_atomic_int;
44typedef uint64_t cf_atomic_int_t; // the point here is a type of the same size as cf_atomic_int but isn't atomic
45
46/******************************************************************************
47 * MACROS
48 *****************************************************************************/
49
50#define cf_atomic32_get(a) (a)
51#define cf_atomic32_set(a, b) (*(a) = (b))
52#define cf_atomic32_sub(a,b) (cf_atomic32_add((a), (0 - (b))))
53#define cf_atomic32_incr(a) (cf_atomic32_add((a), 1))
54#define cf_atomic32_decr(a) (cf_atomic32_add((a), -1))
55
56#define cf_atomic64_get(a) (a)
57#define cf_atomic64_set(a, b) (*(a) = (b))
58#define cf_atomic64_sub(a,b) (cf_atomic64_add((a), (0 - (b))))
59#define cf_atomic64_incr(a) (cf_atomic64_add((a), 1))
60#define cf_atomic64_decr(a) (cf_atomic64_add((a), -1))
61
62#define cf_atomic_p_get(_a) cf_atomic64_get(_a)
63#define cf_atomic_p_set(_a, _b) cf_atomic64_set(_a, _b)
64#define cf_atomic_p_add(_a, _b) cf_atomic64_add(_a, _b)
65#define cf_atomic_p_incr(_a) cf_atomic64_add((_a), 1)
66#define cf_atomic_p_decr(_a) cf_atomic64_add((_a), -1)
67
68#define cf_atomic_int_get(_a) cf_atomic64_get(_a)
69#define cf_atomic_int_set(_a, _b) cf_atomic64_set(_a, _b)
70#define cf_atomic_int_add(_a, _b) cf_atomic64_add(_a, _b)
71#define cf_atomic_int_sub(_a, _b) cf_atomic64_sub(_a, _b)
72#define cf_atomic_int_incr(_a) cf_atomic64_add((_a), 1)
73#define cf_atomic_int_decr(_a) cf_atomic64_add((_a), -1)
74
75/******************************************************************************
76 * LINUX FUNCTIONS
77 *****************************************************************************/
78
79#define cf_atomic_int_setmax(_a, _x) cf_atomic64_setmax(_a, _x)
80
81#define smb_mb() ck_pr_fence_memory()
82
83static inline int64_t cf_atomic64_add(cf_atomic64 *a, int64_t b) {
84 return ck_pr_faa_64((uint64_t*)a, b) + b;
85 //int64_t i = b;
86 //__asm__ __volatile__ ("lock; xaddq %0, %1" : "+r" (b), "+m" (*a) : : "memory");
87 //return(b + i);
88}
89
90static inline bool cf_atomic64_setmax(cf_atomic64 *a, int64_t x) {
91 uint64_t prior;
92
93 // Get the current value of the atomic integer.
94 int64_t cur = cf_atomic64_get(*a);
95
96 while (x > cur) {
97 // Proposed value is larger than current - attempt compare-and-swap.
98 if (ck_pr_cas_64_value((uint64_t*)a, cur, x, &prior)) {
99 // Current value was unchanged, proposed value swapped in.
100 return true;
101 }
102
103 // Current value had changed, set cur to prior and go around again.
104 cur = prior;
105 }
106
107 // Proposed value not swapped in as new maximum.
108 return false;
109}
110
111static inline int32_t cf_atomic32_add(cf_atomic32 *a, int32_t b){
112 return ck_pr_faa_32((uint32_t*)a, b) + b;
113 //int32_t i = b;
114 //__asm__ __volatile__ ("lock; xadd %0, %1" : "+r" (b), "+m" (*a) : : "memory");
115 //return(b + i);
116}
117
118static inline bool cf_atomic32_setmax(cf_atomic32 *a, int32_t x) {
119 uint32_t prior;
120
121 // Get the current value of the atomic integer.
122 int32_t cur = cf_atomic32_get(*a);
123
124 while (x > cur) {
125 // Proposed value is larger than current - attempt compare-and-swap.
126 if (ck_pr_cas_32_value((uint32_t*)a, cur, x, &prior)) {
127 return true;
128 }
129
130 // Current value had changed, set cur to prior and go around again.
131 cur = prior;
132 }
133
134 // Proposed value not swapped in as new maximum.
135 return false;
136}
137
138#ifdef __cplusplus
139} // end extern "C"
140#endif
141