33 m_MissedPublications(),
35 for (
size_t line = 0; line < LineCount; ++line) {
36 for (
size_t bank = 0; bank < BankCount; ++bank) {
37 m_Banks[line][bank].line =
static_cast<uint8_t
>(line);
39 m_Publications[line] =
static_cast<size_t>(1) << BankBits;
45 if (line >= LineCount) {
49 size_t expectedAdmission = 0;
50 if (!__atomic_compare_exchange_n(&m_WriterAdmissions[line], &expectedAdmission,
51 static_cast<size_t>(1),
false, __ATOMIC_ACQUIRE,
57 const size_t publication = __atomic_load_n(&m_Publications[line], __ATOMIC_ACQUIRE);
58 const size_t activeBank = publication & BankMask;
59 for (
size_t offset = 1; offset < BankCount; ++offset) {
60 const size_t candidate = (activeBank + offset) % BankCount;
61 size_t expectedClaim = 0;
62 if (__atomic_compare_exchange_n(&m_BankClaims[line][candidate], &expectedClaim, WriterClaim,
63 false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
64 targetBank = candidate;
65 return &m_Banks[line][candidate];
69 __atomic_store_n(&m_WriterAdmissions[line],
static_cast<size_t>(0), __ATOMIC_RELEASE);
76 if (line >= LineCount || targetBank >= BankCount) {
80 const size_t current = __atomic_load_n(&m_Publications[line], __ATOMIC_RELAXED);
81 size_t generation = (current >> BankBits) + 1;
88 __atomic_store_n(&m_BankClaims[line][targetBank],
static_cast<size_t>(0), __ATOMIC_RELEASE);
89 __atomic_store_n(&m_Publications[line], (generation << BankBits) | targetBank,
91 __atomic_store_n(&m_WriterAdmissions[line],
static_cast<size_t>(0), __ATOMIC_RELEASE);
96 if (line >= LineCount) {
100 for (
size_t attempt = 0; attempt < SnapshotAttempts; ++attempt) {
101 const size_t publication = __atomic_load_n(&m_Publications[line], __ATOMIC_ACQUIRE);
102 const size_t bank = publication & BankMask;
103 if (bank >= BankCount) {
107 size_t claim = __atomic_load_n(&m_BankClaims[line][bank], __ATOMIC_ACQUIRE);
108 if (claim & WriterClaim) {
111 if (!__atomic_compare_exchange_n(&m_BankClaims[line][bank], &claim, claim + 1,
false,
112 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
116 if (__atomic_load_n(&m_Publications[line], __ATOMIC_ACQUIRE) != publication) {
117 __atomic_fetch_sub(&m_BankClaims[line][bank],
static_cast<size_t>(1), __ATOMIC_RELEASE);
121 out = m_Banks[line][bank];
122 out.snapshotGeneration = publication >> BankBits;
123 __atomic_fetch_sub(&m_BankClaims[line][bank],
static_cast<size_t>(1), __ATOMIC_RELEASE);
129#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
132 bool claimPublishedBankForTest(
size_t line,
size_t& bank)
const {
133 if (line >= LineCount) {
137 const size_t publication = __atomic_load_n(&m_Publications[line], __ATOMIC_ACQUIRE);
138 bank = publication & BankMask;
139 if (bank >= BankCount) {
143 size_t claim = __atomic_load_n(&m_BankClaims[line][bank], __ATOMIC_ACQUIRE);
144 if ((claim & WriterClaim) ||
145 !__atomic_compare_exchange_n(&m_BankClaims[line][bank], &claim, claim + 1,
false,
146 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
150 if (__atomic_load_n(&m_Publications[line], __ATOMIC_ACQUIRE) != publication) {
151 __atomic_fetch_sub(&m_BankClaims[line][bank],
static_cast<size_t>(1), __ATOMIC_RELEASE);
157 void releasePublishedBankForTest(
size_t line,
size_t bank)
const {
158 if (line < LineCount && bank < BankCount) {
159 __atomic_fetch_sub(&m_BankClaims[line][bank],
static_cast<size_t>(1), __ATOMIC_RELEASE);
164 size_t missedPublications(
size_t line)
const {
165 return line < LineCount ? __atomic_load_n(&m_MissedPublications[line], __ATOMIC_RELAXED) : 0;
170 if (line < LineCount) {
177 return line < LineCount &&
178 __atomic_exchange_n(&m_Dirty[line],
static_cast<size_t>(0), __ATOMIC_ACQ_REL) != 0;
182 static constexpr size_t BankCount = 3;
183 static constexpr size_t BankBits = 2;
184 static constexpr size_t BankMask = (1U << BankBits) - 1;
185 static constexpr size_t SnapshotAttempts = 4;
186 static constexpr size_t WriterClaim =
static_cast<size_t>(1) << ((
sizeof(
size_t) * 8) - 1);
188 void missed(
size_t line) {
189 __atomic_store_n(&m_Dirty[line],
static_cast<size_t>(1), __ATOMIC_RELEASE);
190 __atomic_add_fetch(&m_MissedPublications[line],
static_cast<size_t>(1), __ATOMIC_RELAXED);
194 size_t m_Publications[LineCount];
195 mutable size_t m_BankClaims[LineCount][BankCount];
196 size_t m_WriterAdmissions[LineCount];
197 size_t m_MissedPublications[LineCount];
198 size_t m_Dirty[LineCount];