1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_BASE_ATOMIC_PAIR_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_BASE_ATOMIC_PAIR_H_
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include <atomic>
23*795d594fSAndroid Build Coastguard Worker #include <type_traits>
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker // Implement 16-byte atomic pair using the seq-lock synchronization algorithm.
30*795d594fSAndroid Build Coastguard Worker // This is currently only used for DexCache.
31*795d594fSAndroid Build Coastguard Worker //
32*795d594fSAndroid Build Coastguard Worker // This uses top 4-bytes of the key as version counter and lock bit,
33*795d594fSAndroid Build Coastguard Worker // which means the stored pair key can not use those bytes.
34*795d594fSAndroid Build Coastguard Worker //
35*795d594fSAndroid Build Coastguard Worker // This allows us to read the cache without exclusive access to the cache line.
36*795d594fSAndroid Build Coastguard Worker //
37*795d594fSAndroid Build Coastguard Worker // The 8-byte atomic pair uses the normal single-instruction implementation.
38*795d594fSAndroid Build Coastguard Worker //
39*795d594fSAndroid Build Coastguard Worker static constexpr uint64_t kSeqMask = (0xFFFFFFFFull << 32);
40*795d594fSAndroid Build Coastguard Worker static constexpr uint64_t kSeqLock = (0x80000000ull << 32);
41*795d594fSAndroid Build Coastguard Worker static constexpr uint64_t kSeqIncr = (0x00000001ull << 32);
42*795d594fSAndroid Build Coastguard Worker
43*795d594fSAndroid Build Coastguard Worker // std::pair<> is not trivially copyable and as such it is unsuitable for atomic operations.
44*795d594fSAndroid Build Coastguard Worker template <typename IntType>
45*795d594fSAndroid Build Coastguard Worker struct PACKED(2 * sizeof(IntType)) AtomicPair {
46*795d594fSAndroid Build Coastguard Worker static_assert(std::is_integral_v<IntType>);
47*795d594fSAndroid Build Coastguard Worker
AtomicPairAtomicPair48*795d594fSAndroid Build Coastguard Worker AtomicPair(IntType f, IntType s) : key(f), val(s) {}
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker IntType key;
51*795d594fSAndroid Build Coastguard Worker IntType val;
52*795d594fSAndroid Build Coastguard Worker };
53*795d594fSAndroid Build Coastguard Worker
54*795d594fSAndroid Build Coastguard Worker template <typename IntType>
AtomicPairLoadAcquire(AtomicPair<IntType> * pair)55*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE static inline AtomicPair<IntType> AtomicPairLoadAcquire(AtomicPair<IntType>* pair) {
56*795d594fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<AtomicPair<IntType>>::value);
57*795d594fSAndroid Build Coastguard Worker auto* target = reinterpret_cast<std::atomic<AtomicPair<IntType>>*>(pair);
58*795d594fSAndroid Build Coastguard Worker return target->load(std::memory_order_acquire);
59*795d594fSAndroid Build Coastguard Worker }
60*795d594fSAndroid Build Coastguard Worker
61*795d594fSAndroid Build Coastguard Worker template <typename IntType>
AtomicPairStoreRelease(AtomicPair<IntType> * pair,AtomicPair<IntType> value)62*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE static inline void AtomicPairStoreRelease(AtomicPair<IntType>* pair,
63*795d594fSAndroid Build Coastguard Worker AtomicPair<IntType> value) {
64*795d594fSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<AtomicPair<IntType>>::value);
65*795d594fSAndroid Build Coastguard Worker auto* target = reinterpret_cast<std::atomic<AtomicPair<IntType>>*>(pair);
66*795d594fSAndroid Build Coastguard Worker target->store(value, std::memory_order_release);
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker
AtomicPairLoadAcquire(AtomicPair<uint64_t> * pair)69*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE static inline AtomicPair<uint64_t> AtomicPairLoadAcquire(AtomicPair<uint64_t>* pair) {
70*795d594fSAndroid Build Coastguard Worker auto* key_ptr = reinterpret_cast<std::atomic_uint64_t*>(&pair->key);
71*795d594fSAndroid Build Coastguard Worker auto* val_ptr = reinterpret_cast<std::atomic_uint64_t*>(&pair->val);
72*795d594fSAndroid Build Coastguard Worker while (true) {
73*795d594fSAndroid Build Coastguard Worker uint64_t key0 = key_ptr->load(std::memory_order_acquire);
74*795d594fSAndroid Build Coastguard Worker uint64_t val = val_ptr->load(std::memory_order_acquire);
75*795d594fSAndroid Build Coastguard Worker uint64_t key1 = key_ptr->load(std::memory_order_relaxed);
76*795d594fSAndroid Build Coastguard Worker uint64_t key = key0 & ~kSeqMask;
77*795d594fSAndroid Build Coastguard Worker if (LIKELY((key0 & kSeqLock) == 0 && key0 == key1)) {
78*795d594fSAndroid Build Coastguard Worker return {key, val};
79*795d594fSAndroid Build Coastguard Worker }
80*795d594fSAndroid Build Coastguard Worker }
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker
AtomicPairStoreRelease(AtomicPair<uint64_t> * pair,AtomicPair<uint64_t> value)83*795d594fSAndroid Build Coastguard Worker ALWAYS_INLINE static inline void AtomicPairStoreRelease(AtomicPair<uint64_t>* pair,
84*795d594fSAndroid Build Coastguard Worker AtomicPair<uint64_t> value) {
85*795d594fSAndroid Build Coastguard Worker DCHECK((value.key & kSeqMask) == 0) << "Key=0x" << std::hex << value.key;
86*795d594fSAndroid Build Coastguard Worker auto* key_ptr = reinterpret_cast<std::atomic_uint64_t*>(&pair->key);
87*795d594fSAndroid Build Coastguard Worker auto* val_ptr = reinterpret_cast<std::atomic_uint64_t*>(&pair->val);
88*795d594fSAndroid Build Coastguard Worker uint64_t key = key_ptr->load(std::memory_order_relaxed);
89*795d594fSAndroid Build Coastguard Worker do {
90*795d594fSAndroid Build Coastguard Worker key &= ~kSeqLock; // Ensure that the CAS below fails if the lock bit is already set.
91*795d594fSAndroid Build Coastguard Worker } while (!key_ptr->compare_exchange_weak(key, key | kSeqLock));
92*795d594fSAndroid Build Coastguard Worker key = (((key & kSeqMask) + kSeqIncr) & ~kSeqLock) | (value.key & ~kSeqMask);
93*795d594fSAndroid Build Coastguard Worker val_ptr->store(value.val, std::memory_order_release);
94*795d594fSAndroid Build Coastguard Worker key_ptr->store(key, std::memory_order_release);
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker } // namespace art
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker #endif // ART_RUNTIME_BASE_ATOMIC_PAIR_H_
100