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 |
29 | extern "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 |
40 | typedef volatile uint64_t cf_atomic64; |
41 | typedef volatile uint32_t cf_atomic32; |
42 | typedef volatile uint64_t cf_atomic_p; |
43 | typedef volatile uint64_t cf_atomic_int; |
44 | typedef 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 | |
83 | static 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 | |
90 | static 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 | |
111 | static 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 | |
118 | static 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 | |