Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/cubeb/src/cubeb_triple_buffer.h
4246 views
1
/*
2
* Copyright © 2022 Mozilla Foundation
3
*
4
* This program is made available under an ISC-style license. See the
5
* accompanying file LICENSE for details.
6
*/
7
8
/**
9
* Adapted and ported to C++ from https://crates.io/crates/triple_buffer
10
*/
11
12
#ifndef CUBEB_TRIPLE_BUFFER
13
#define CUBEB_TRIPLE_BUFFER
14
15
#include <atomic>
16
17
// Single producer / single consumer wait-free triple buffering
18
// implementation, for when a producer wants to publish data to a consumer
19
// without blocking, but when a queue is wastefull, because it's OK for the
20
// consumer to miss data updates.
21
template <typename T> class triple_buffer {
22
public:
23
// Write a new value into the triple buffer. Returns true if a value was
24
// overwritten.
25
// Producer-side only.
26
bool write(T & input)
27
{
28
storage[input_idx] = input;
29
return publish();
30
}
31
// Get the latest value from the triple buffer.
32
// Consumer-side only.
33
T & read()
34
{
35
update();
36
return storage[output_idx];
37
}
38
// Returns true if a new value has been published by the consumer without
39
// having been consumed yet.
40
// Consumer-side only.
41
bool updated()
42
{
43
return (shared_state.load(std::memory_order_relaxed) & BACK_DIRTY_BIT) != 0;
44
}
45
// Reset state and indices to initial values.
46
void invalidate()
47
{
48
shared_state.store(0, std::memory_order_release);
49
input_idx = 1;
50
output_idx = 2;
51
}
52
53
private:
54
// Publish a value to the consumer. Returns true if the data was overwritten
55
// without having been read.
56
bool publish()
57
{
58
auto former_back_idx = shared_state.exchange(input_idx | BACK_DIRTY_BIT,
59
std::memory_order_acq_rel);
60
input_idx = former_back_idx & BACK_INDEX_MASK;
61
return (former_back_idx & BACK_DIRTY_BIT) != 0;
62
}
63
// Get a new value from the producer, if a new value has been produced.
64
bool update()
65
{
66
bool was_updated = updated();
67
if (was_updated) {
68
auto former_back_idx =
69
shared_state.exchange(output_idx, std::memory_order_acq_rel);
70
output_idx = former_back_idx & BACK_INDEX_MASK;
71
}
72
return was_updated;
73
}
74
T storage[3];
75
// Mask used to extract back-buffer index
76
const uint8_t BACK_INDEX_MASK = 0b11;
77
// Bit set by producer to signal updates
78
const uint8_t BACK_DIRTY_BIT = 0b100;
79
// Shared state: a dirty bit, and an index.
80
std::atomic<uint8_t> shared_state = {0};
81
// Output index, private to the consumer.
82
uint8_t output_idx = 1;
83
// Input index, private to the producer.
84
uint8_t input_idx = 2;
85
};
86
87
#endif // CUBEB_TRIPLE_BUFFER
88
89