blob: 9de84cdd20bcf972f81bde24f3e8daa65810b491 [file] [log] [blame]
Elliott Hughes5ea047b2011-09-13 14:38:18 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
David Sehrc431b9d2018-03-02 12:01:51 -080017#ifndef ART_LIBARTBASE_BASE_ATOMIC_H_
18#define ART_LIBARTBASE_BASE_ATOMIC_H_
Elliott Hughes5ea047b2011-09-13 14:38:18 -070019
Elliott Hughes7c6169d2012-05-02 16:11:48 -070020#include <stdint.h>
Ian Rogers3e5cf302014-05-20 16:40:37 -070021#include <atomic>
Ian Rogers3e5cf302014-05-20 16:40:37 -070022#include <limits>
Ian Rogersb122a4b2013-11-19 18:00:50 -080023#include <vector>
Elliott Hughes7c6169d2012-05-02 16:11:48 -070024
Andreas Gampe57943812017-12-06 21:39:13 -080025#include <android-base/logging.h>
26
David Sehr1979c642018-04-26 14:41:18 -070027#include "macros.h"
Elliott Hughes5ea047b2011-09-13 14:38:18 -070028
29namespace art {
30
Mathieu Chartier42c2e502018-06-19 12:30:56 -070031enum class CASMode {
32 kStrong,
33 kWeak,
34};
35
Hans Boehm30359612014-05-21 17:46:23 -070036template<typename T>
Dan Albertaab0f862014-08-11 16:38:02 -070037class PACKED(sizeof(T)) Atomic : public std::atomic<T> {
Hans Boehm30359612014-05-21 17:46:23 -070038 public:
Mathieu Chartier1a088d42017-07-18 11:43:57 -070039 Atomic<T>() : std::atomic<T>(T()) { }
Hans Boehm30359612014-05-21 17:46:23 -070040
41 explicit Atomic<T>(T value) : std::atomic<T>(value) { }
42
Orion Hodson88591fe2018-03-06 13:35:43 +000043 // Load data from an atomic variable with Java data memory order semantics.
44 //
45 // Promises memory access semantics of ordinary Java data.
46 // Does not order other memory accesses.
47 // Long and double accesses may be performed 32 bits at a time.
48 // There are no "cache coherence" guarantees; e.g. loads from the same location may be reordered.
49 // In contrast to normal C++ accesses, racing accesses are allowed.
Hans Boehm30359612014-05-21 17:46:23 -070050 T LoadJavaData() const {
51 return this->load(std::memory_order_relaxed);
52 }
53
Orion Hodson88591fe2018-03-06 13:35:43 +000054 // Store data in an atomic variable with Java data memory ordering semantics.
55 //
56 // Promises memory access semantics of ordinary Java data.
57 // Does not order other memory accesses.
58 // Long and double accesses may be performed 32 bits at a time.
59 // There are no "cache coherence" guarantees; e.g. loads from the same location may be reordered.
60 // In contrast to normal C++ accesses, racing accesses are allowed.
Orion Hodson4131d102018-01-03 14:04:42 +000061 void StoreJavaData(T desired_value) {
62 this->store(desired_value, std::memory_order_relaxed);
Hans Boehm30359612014-05-21 17:46:23 -070063 }
64
Orion Hodson4131d102018-01-03 14:04:42 +000065 // Atomically replace the value with desired_value if it matches the expected_value.
Hans Boehm30359612014-05-21 17:46:23 -070066 // Participates in total ordering of atomic operations.
Orion Hodson4557b382018-01-03 11:47:54 +000067 bool CompareAndSetStrongSequentiallyConsistent(T expected_value, T desired_value) {
Hans Boehm30359612014-05-21 17:46:23 -070068 return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_seq_cst);
69 }
70
71 // The same, except it may fail spuriously.
Orion Hodson4557b382018-01-03 11:47:54 +000072 bool CompareAndSetWeakSequentiallyConsistent(T expected_value, T desired_value) {
Hans Boehm30359612014-05-21 17:46:23 -070073 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_seq_cst);
74 }
75
Orion Hodson4131d102018-01-03 14:04:42 +000076 // Atomically replace the value with desired_value if it matches the expected_value. Doesn't
Hans Boehm30359612014-05-21 17:46:23 -070077 // imply ordering or synchronization constraints.
Orion Hodson4557b382018-01-03 11:47:54 +000078 bool CompareAndSetStrongRelaxed(T expected_value, T desired_value) {
Hans Boehm30359612014-05-21 17:46:23 -070079 return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_relaxed);
80 }
81
Orion Hodson4131d102018-01-03 14:04:42 +000082 // Atomically replace the value with desired_value if it matches the expected_value. Prior writes
Mathieu Chartierfdd513d2017-06-01 11:26:50 -070083 // to other memory locations become visible to the threads that do a consume or an acquire on the
84 // same location.
Orion Hodson4557b382018-01-03 11:47:54 +000085 bool CompareAndSetStrongRelease(T expected_value, T desired_value) {
Mathieu Chartierfdd513d2017-06-01 11:26:50 -070086 return this->compare_exchange_strong(expected_value, desired_value, std::memory_order_release);
87 }
88
Hans Boehm30359612014-05-21 17:46:23 -070089 // The same, except it may fail spuriously.
Orion Hodson4557b382018-01-03 11:47:54 +000090 bool CompareAndSetWeakRelaxed(T expected_value, T desired_value) {
Hans Boehm30359612014-05-21 17:46:23 -070091 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_relaxed);
92 }
93
Orion Hodson4131d102018-01-03 14:04:42 +000094 // Atomically replace the value with desired_value if it matches the expected_value. Prior writes
Hans Boehm30359612014-05-21 17:46:23 -070095 // made to other memory locations by the thread that did the release become visible in this
96 // thread.
Orion Hodson4557b382018-01-03 11:47:54 +000097 bool CompareAndSetWeakAcquire(T expected_value, T desired_value) {
Hans Boehm30359612014-05-21 17:46:23 -070098 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_acquire);
99 }
100
Orion Hodson4131d102018-01-03 14:04:42 +0000101 // Atomically replace the value with desired_value if it matches the expected_value. Prior writes
Hans Boehm30359612014-05-21 17:46:23 -0700102 // to other memory locations become visible to the threads that do a consume or an acquire on the
103 // same location.
Orion Hodson4557b382018-01-03 11:47:54 +0000104 bool CompareAndSetWeakRelease(T expected_value, T desired_value) {
Hans Boehm30359612014-05-21 17:46:23 -0700105 return this->compare_exchange_weak(expected_value, desired_value, std::memory_order_release);
106 }
107
Mathieu Chartier42c2e502018-06-19 12:30:56 -0700108 bool CompareAndSet(T expected_value,
109 T desired_value,
110 CASMode mode,
111 std::memory_order memory_order) {
112 return mode == CASMode::kStrong
113 ? this->compare_exchange_strong(expected_value, desired_value, memory_order)
114 : this->compare_exchange_weak(expected_value, desired_value, memory_order);
115 }
116
Orion Hodson88591fe2018-03-06 13:35:43 +0000117 // Returns the address of the current atomic variable. This is only used by futex() which is
118 // declared to take a volatile address (see base/mutex-inl.h).
Hans Boehm30359612014-05-21 17:46:23 -0700119 volatile T* Address() {
120 return reinterpret_cast<T*>(this);
121 }
122
123 static T MaxValue() {
124 return std::numeric_limits<T>::max();
125 }
Hans Boehm30359612014-05-21 17:46:23 -0700126};
127
Hans Boehm30359612014-05-21 17:46:23 -0700128typedef Atomic<int32_t> AtomicInteger;
129
Andreas Gampe575e78c2014-11-03 23:41:03 -0800130static_assert(sizeof(AtomicInteger) == sizeof(int32_t), "Weird AtomicInteger size");
131static_assert(alignof(AtomicInteger) == alignof(int32_t),
132 "AtomicInteger alignment differs from that of underlyingtype");
133static_assert(sizeof(Atomic<int64_t>) == sizeof(int64_t), "Weird Atomic<int64> size");
Dan Albertaab0f862014-08-11 16:38:02 -0700134
135// Assert the alignment of 64-bit integers is 64-bit. This isn't true on certain 32-bit
136// architectures (e.g. x86-32) but we know that 64-bit integers here are arranged to be 8-byte
137// aligned.
Hans Boehm2f4a2ed2014-06-06 18:17:43 -0700138#if defined(__LP64__)
Andreas Gampe575e78c2014-11-03 23:41:03 -0800139 static_assert(alignof(Atomic<int64_t>) == alignof(int64_t),
140 "Atomic<int64> alignment differs from that of underlying type");
Hans Boehm2f4a2ed2014-06-06 18:17:43 -0700141#endif
Ian Rogers3e5cf302014-05-20 16:40:37 -0700142
Elliott Hughes5ea047b2011-09-13 14:38:18 -0700143} // namespace art
144
David Sehrc431b9d2018-03-02 12:01:51 -0800145#endif // ART_LIBARTBASE_BASE_ATOMIC_H_