Merge pull request #1894 from TomHarte/NoMoreConditionVariable
Use std::atomic_flag::wait.
This commit is contained in:
18 files changed
+88
-98
No files matched your search
@@ -8,8 +8,7 @@
|
||||
|
||||
#include "MultiProducer.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
using namespace Analyser::Dynamic;
|
||||
|
||||
@@ -19,28 +18,23 @@ template <typename MachineType>
|
||||
void MultiInterface<MachineType>::perform_parallel(const std::function<void(MachineType *)> &function) {
|
||||
// Apply a blunt force parallelisation of the machines; each run_for is dispatched
|
||||
// to a separate queue and this queue will block until all are done.
|
||||
std::size_t outstanding_machines;
|
||||
std::condition_variable condition;
|
||||
std::mutex mutex;
|
||||
std::atomic<int> outstanding_machines = int(machines_.size());
|
||||
std::atomic_flag finished{};
|
||||
{
|
||||
std::lock_guard machines_lock(machines_mutex_);
|
||||
std::lock_guard lock(mutex);
|
||||
outstanding_machines = machines_.size();
|
||||
|
||||
for(std::size_t index = 0; index < machines_.size(); ++index) {
|
||||
const auto machine = ::Machine::get<MachineType>(*machines_[index].get());
|
||||
queues_[index].enqueue([&mutex, &condition, machine, function, &outstanding_machines]() {
|
||||
queues_[index].enqueue([&finished, machine, function, &outstanding_machines]() {
|
||||
if(machine) function(machine);
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
--outstanding_machines;
|
||||
condition.notify_all();
|
||||
if(outstanding_machines.fetch_sub(1, std::memory_order::relaxed) == 1) {
|
||||
finished.test_and_set(std::memory_order::release);
|
||||
finished.notify_one();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock lock(mutex);
|
||||
condition.wait(lock, [&outstanding_machines] { return !outstanding_machines; });
|
||||
finished.wait(false, std::memory_order::acquire);
|
||||
}
|
||||
|
||||
template <typename MachineType>
|
||||
|
||||
@@ -61,7 +61,7 @@ void MultiSpeaker::set_output_volume(const float volume) {
|
||||
}
|
||||
|
||||
void MultiSpeaker::speaker_did_complete_samples(Speaker &speaker, const std::vector<int16_t> &buffer) {
|
||||
auto delegate = delegate_.load(std::memory_order_relaxed);
|
||||
auto delegate = delegate_.load(std::memory_order::relaxed);
|
||||
if(!delegate) return;
|
||||
{
|
||||
std::lock_guard lock_guard(front_speaker_mutex_);
|
||||
@@ -71,7 +71,7 @@ void MultiSpeaker::speaker_did_complete_samples(Speaker &speaker, const std::vec
|
||||
}
|
||||
|
||||
void MultiSpeaker::speaker_did_change_input_clock(Speaker &speaker) {
|
||||
auto delegate = delegate_.load(std::memory_order_relaxed);
|
||||
auto delegate = delegate_.load(std::memory_order::relaxed);
|
||||
if(!delegate) return;
|
||||
{
|
||||
std::lock_guard lock_guard(front_speaker_mutex_);
|
||||
@@ -85,7 +85,7 @@ void MultiSpeaker::set_new_front_machine(::Machine::DynamicMachine *const machin
|
||||
std::lock_guard lock_guard(front_speaker_mutex_);
|
||||
front_speaker_ = machine->audio_producer()->get_speaker();
|
||||
}
|
||||
auto delegate = delegate_.load(std::memory_order_relaxed);
|
||||
auto delegate = delegate_.load(std::memory_order::relaxed);
|
||||
if(delegate) {
|
||||
delegate->speaker_did_change_input_clock(*this);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ void uPD7002::run_for(const HalfCycles count) {
|
||||
if(count >= conversion_time_remaining_) {
|
||||
conversion_time_remaining_ = HalfCycles(0);
|
||||
result_ = uint16_t(
|
||||
inputs_[channel_].load(std::memory_order_relaxed) * 65535.0f) & (high_precision_ ? 0xfff0 : 0xff00
|
||||
inputs_[channel_].load(std::memory_order::relaxed) * 65535.0f) & (high_precision_ ? 0xfff0 : 0xff00
|
||||
);
|
||||
set_interrupt(true);
|
||||
return;
|
||||
@@ -83,5 +83,5 @@ void uPD7002::set_interrupt(const bool value) {
|
||||
}
|
||||
|
||||
void uPD7002::set_input(const int channel, const float value) {
|
||||
inputs_[channel].store(value, std::memory_order_relaxed);
|
||||
inputs_[channel].store(value, std::memory_order::relaxed);
|
||||
}
|
||||
@@ -147,22 +147,18 @@ public:
|
||||
/// Schedules any remaining unscheduled work, then blocks synchronously
|
||||
/// until all scheduled work has been performed.
|
||||
void lock_flush() {
|
||||
std::mutex flush_mutex;
|
||||
std::condition_variable flush_condition;
|
||||
bool has_run = false;
|
||||
std::unique_lock lock(flush_mutex);
|
||||
std::atomic_flag flushed = false;
|
||||
|
||||
enqueue([&flush_mutex, &flush_condition, &has_run] () {
|
||||
std::unique_lock inner_lock(flush_mutex);
|
||||
has_run = true;
|
||||
flush_condition.notify_one();
|
||||
enqueue([&flushed] () {
|
||||
flushed.test_and_set(std::memory_order::release);
|
||||
flushed.notify_one();
|
||||
});
|
||||
|
||||
if constexpr (!perform_automatically) {
|
||||
perform();
|
||||
}
|
||||
|
||||
flush_condition.wait(lock, [&has_run] { return has_run; });
|
||||
flushed.wait(false, std::memory_order::acquire);
|
||||
}
|
||||
|
||||
/// Schedules any remaining unscheduled work, then spins
|
||||
@@ -195,11 +191,11 @@ private:
|
||||
ActionVector actions;
|
||||
|
||||
// Continue until told to quit.
|
||||
while(!should_quit_.test(std::memory_order_relaxed)) {
|
||||
while(!should_quit_.test(std::memory_order::relaxed)) {
|
||||
// Wait for new actions to be signalled, and grab them.
|
||||
std::unique_lock lock(condition_mutex_);
|
||||
condition_.wait(lock, [&] {
|
||||
return !actions_.empty() || should_quit_.test(std::memory_order_relaxed);
|
||||
return !actions_.empty() || should_quit_.test(std::memory_order::relaxed);
|
||||
});
|
||||
std::swap(actions, actions_);
|
||||
lock.unlock();
|
||||
|
||||
@@ -36,9 +36,9 @@ public:
|
||||
|
||||
private:
|
||||
static constexpr auto LockMemoryOrder =
|
||||
type == Barrier::Relaxed ? std::memory_order_relaxed : std::memory_order_acquire;
|
||||
type == Barrier::Relaxed ? std::memory_order::relaxed : std::memory_order::acquire;
|
||||
static constexpr auto UnlockMemoryOrder =
|
||||
type == Barrier::Relaxed ? std::memory_order_relaxed : std::memory_order_release;
|
||||
type == Barrier::Relaxed ? std::memory_order::relaxed : std::memory_order::release;
|
||||
|
||||
// Note to self: this is guaranteed to construct in a clear state since C++20.
|
||||
std::atomic_flag flag_;
|
||||
|
||||
@@ -20,7 +20,7 @@ Audio::Audio(Chipset &chipset, uint16_t *ram, size_t word_size, float output_rat
|
||||
|
||||
// Mark all buffers as available.
|
||||
for(auto &flag: buffer_available_) {
|
||||
flag.store(true, std::memory_order_relaxed);
|
||||
flag.store(true, std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
speaker_.set_input_rate(output_rate);
|
||||
@@ -130,7 +130,7 @@ void Audio::output() {
|
||||
// Spin until the next buffer is available if just entering it for the first time.
|
||||
// Contention here should be essentially non-existent.
|
||||
if(!sample_pointer_) {
|
||||
while(!buffer_available_[buffer_pointer_].load(std::memory_order_relaxed));
|
||||
while(!buffer_available_[buffer_pointer_].load(std::memory_order::relaxed));
|
||||
}
|
||||
|
||||
// Left.
|
||||
@@ -155,10 +155,10 @@ void Audio::output() {
|
||||
const auto &buffer = buffer_[buffer_pointer_];
|
||||
auto &flag = buffer_available_[buffer_pointer_];
|
||||
|
||||
flag.store(false, std::memory_order_release);
|
||||
flag.store(false, std::memory_order::release);
|
||||
queue_.enqueue([this, &buffer, &flag] {
|
||||
speaker_.push(buffer.data(), buffer.size() >> 1);
|
||||
flag.store(true, std::memory_order_relaxed);
|
||||
flag.store(true, std::memory_order::relaxed);
|
||||
});
|
||||
|
||||
buffer_pointer_ = (buffer_pointer_ + 1) % BufferCount;
|
||||
|
||||
@@ -25,15 +25,15 @@ void Mouse::perform_command(const Command &command) {
|
||||
// There's some small chance of creating negative feedback here — taking too much off delta_x_ or delta_y_
|
||||
// due to a change in the underlying value between the load and the arithmetic. But if that occurs it means
|
||||
// the user moved the mouse again in the interim, so it'll just play out as very slight latency.
|
||||
auto delta_x = delta_x_.load(std::memory_order_relaxed);
|
||||
auto delta_y = delta_y_.load(std::memory_order_relaxed);
|
||||
auto delta_x = delta_x_.load(std::memory_order::relaxed);
|
||||
auto delta_y = delta_y_.load(std::memory_order::relaxed);
|
||||
if(abs(delta_x) > max_delta || abs(delta_y) > max_delta) {
|
||||
int max = std::max(abs(delta_x), abs(delta_y));
|
||||
delta_x = delta_x * max_delta / max;
|
||||
delta_y = delta_y * max_delta / max;
|
||||
}
|
||||
|
||||
const int buttons = button_flags_.load(std::memory_order_relaxed);
|
||||
const int buttons = button_flags_.load(std::memory_order::relaxed);
|
||||
delta_x_ -= delta_x;
|
||||
delta_y_ -= delta_y;
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ void GLU::set_data(uint8_t data) {
|
||||
write.address = address_;
|
||||
write.value = data;
|
||||
write.time = pending_store_write_time_;
|
||||
pending_stores_[pending_store_write_].store(write, std::memory_order_release);
|
||||
pending_stores_[pending_store_write_].store(write, std::memory_order::release);
|
||||
|
||||
pending_store_write_ = (pending_store_write_ + 1) % (StoreBufferSize - 1);
|
||||
} else {
|
||||
@@ -174,15 +174,15 @@ template void GLU::apply_samples<Outputs::Speaker::Action::Ignore>(std::size_t,
|
||||
// skip_audio(remote_, number_of_samples);
|
||||
//
|
||||
// // Apply any pending stores.
|
||||
// std::atomic_thread_fence(std::memory_order_acquire);
|
||||
// std::atomic_thread_fence(std::memory_order::acquire);
|
||||
// const uint32_t final_time = pending_store_read_time_ + uint32_t(number_of_samples);
|
||||
// while(true) {
|
||||
// auto next_store = pending_stores_[pending_store_read_].load(std::memory_order_acquire);
|
||||
// auto next_store = pending_stores_[pending_store_read_].load(std::memory_order::acquire);
|
||||
// if(!next_store.enabled) break;
|
||||
// if(next_store.time >= final_time) break;
|
||||
// remote_.ram_[next_store.address] = next_store.value;
|
||||
// next_store.enabled = false;
|
||||
// pending_stores_[pending_store_read_].store(next_store, std::memory_order_relaxed);
|
||||
// pending_stores_[pending_store_read_].store(next_store, std::memory_order::relaxed);
|
||||
//
|
||||
// pending_store_read_ = (pending_store_read_ + 1) & (StoreBufferSize - 1);
|
||||
// }
|
||||
@@ -263,7 +263,7 @@ void GLU::skip_audio(EnsoniqState &state, size_t number_of_samples) {
|
||||
|
||||
template <Outputs::Speaker::Action action>
|
||||
void GLU::generate_audio(size_t number_of_samples, Outputs::Speaker::MonoSample *target) {
|
||||
auto next_store = pending_stores_[pending_store_read_].load(std::memory_order_acquire);
|
||||
auto next_store = pending_stores_[pending_store_read_].load(std::memory_order::acquire);
|
||||
uint8_t next_amplitude = 255;
|
||||
for(size_t sample = 0; sample < number_of_samples; sample++) {
|
||||
|
||||
@@ -344,7 +344,7 @@ void GLU::generate_audio(size_t number_of_samples, Outputs::Speaker::MonoSample
|
||||
if(next_store.time != pending_store_read_time_) continue;
|
||||
remote_.ram_[next_store.address] = next_store.value;
|
||||
next_store.enabled = false;
|
||||
pending_stores_[pending_store_read_].store(next_store, std::memory_order_relaxed);
|
||||
pending_stores_[pending_store_read_].store(next_store, std::memory_order::relaxed);
|
||||
pending_store_read_ = (pending_store_read_ + 1) & (StoreBufferSize - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ Audio::Audio(Concurrency::AsyncTaskQueue<false> &task_queue) : task_queue_(task_
|
||||
void Audio::post_sample(uint8_t sample) {
|
||||
// Store sample directly indexed by current write pointer; this ensures that collected samples
|
||||
// directly map to volume and enabled/disabled states.
|
||||
sample_queue_.buffer[sample_queue_.write_pointer].store(sample, std::memory_order_relaxed);
|
||||
sample_queue_.buffer[sample_queue_.write_pointer].store(sample, std::memory_order::relaxed);
|
||||
sample_queue_.write_pointer = (sample_queue_.write_pointer + 1) % sample_queue_.buffer.size();
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ void Audio::apply_samples(std::size_t number_of_samples, Outputs::Speaker::MonoS
|
||||
const auto cycles_left_in_sample = std::min(number_of_samples, sample_length - subcycle_offset_);
|
||||
|
||||
// Determine the output level, and output that many samples.
|
||||
const int16_t output_level = volume_multiplier_ * (int16_t(sample_queue_.buffer[sample_queue_.read_pointer].load(std::memory_order_relaxed)) - 128);
|
||||
const int16_t output_level = volume_multiplier_ * (int16_t(sample_queue_.buffer[sample_queue_.read_pointer].load(std::memory_order::relaxed)) - 128);
|
||||
Outputs::Speaker::fill<action>(target, target + cycles_left_in_sample, output_level);
|
||||
target += cycles_left_in_sample;
|
||||
|
||||
|
||||
@@ -524,7 +524,7 @@ public:
|
||||
value = result;
|
||||
|
||||
// Consider applying the fast tape hack.
|
||||
if(use_fast_tape_hack_.load(std::memory_order_relaxed) && operation == CPU::MOS6502Mk2::BusOperation::ReadOpcode) {
|
||||
if(use_fast_tape_hack_.load(std::memory_order::relaxed) && operation == CPU::MOS6502Mk2::BusOperation::ReadOpcode) {
|
||||
if(address == 0xf7b2) {
|
||||
// Address 0xf7b2 contains a JSR to 0xf8c0 ('RDTPBLKS') that will fill the tape buffer with the
|
||||
// next header. Skip that via a three-byte NOP and fill in the next header programmatically.
|
||||
@@ -796,7 +796,7 @@ private:
|
||||
void set_use_fast_tape() {
|
||||
use_fast_tape_hack_.store(
|
||||
!tape_is_sleeping_ && allow_fast_tape_hack_ && tape_->has_tape(),
|
||||
std::memory_order_relaxed
|
||||
std::memory_order::relaxed
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,11 +62,11 @@ public:
|
||||
void did_set_input(const Input &digital_input, bool is_active) final {
|
||||
const auto apply_kempston = [&](uint8_t mask) {
|
||||
if(is_active) write_kempston_ |= mask; else write_kempston_ &= ~mask;
|
||||
kempston_.store(write_kempston_, std::memory_order_relaxed);
|
||||
kempston_.store(write_kempston_, std::memory_order::relaxed);
|
||||
};
|
||||
const auto apply_sinclair = [&](uint16_t mask) {
|
||||
if(is_active) write_sinclair_ &= ~mask; else write_sinclair_ |= mask;
|
||||
sinclair_.store(write_sinclair_, std::memory_order_relaxed);
|
||||
sinclair_.store(write_sinclair_, std::memory_order::relaxed);
|
||||
};
|
||||
|
||||
switch(digital_input.type) {
|
||||
@@ -98,13 +98,13 @@ public:
|
||||
/// @returns The value that a Kempston joystick interface would report if this joystick
|
||||
/// were plugged into it.
|
||||
uint8_t get_kempston() {
|
||||
return kempston_.load(std::memory_order_relaxed);
|
||||
return kempston_.load(std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
/// @returns The value that a Sinclair interface would report if this joystick
|
||||
/// were plugged into it via @c port (which should be either 0 or 1, for ports 1 or 2).
|
||||
uint8_t get_sinclair(const int port) {
|
||||
return uint8_t(sinclair_.load(std::memory_order_relaxed) >> (port * 8));
|
||||
return uint8_t(sinclair_.load(std::memory_order::relaxed) >> (port * 8));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -197,12 +197,12 @@ struct ActivityObserver: public Activity::Observer {
|
||||
_machine->scan_producer()->set_scan_target(_view.scanTarget.scanTarget);
|
||||
|
||||
_ownedUpdater = std::make_unique<Updater>();
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
std::atomic_thread_fence(std::memory_order::release);
|
||||
_ownedUpdater->performer.machine = _machine.get();
|
||||
if(_ownedUpdater->performer.machine) {
|
||||
_ownedUpdater->start();
|
||||
}
|
||||
_updater.store(_ownedUpdater.get(), std::memory_order_relaxed);
|
||||
_updater.store(_ownedUpdater.get(), std::memory_order::relaxed);
|
||||
|
||||
_leds = [[NSMutableArray alloc] init];
|
||||
Activity::Source *const activity_source = _machine->activity_source();
|
||||
@@ -384,7 +384,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
}
|
||||
|
||||
- (void)applyMedia:(const Analyser::Static::Media &)media {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
|
||||
__weak CSMachine *weakSelf = self;
|
||||
@@ -565,7 +565,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
}
|
||||
|
||||
- (void)applyInputEvent:(dispatch_block_t)event {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
|
||||
updater->enqueue([event] {
|
||||
@@ -799,7 +799,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
- (void)audioQueueIsRunningDry:(nonnull CSAudioQueue *)audioQueue {
|
||||
__weak CSMachine *weakSelf = self;
|
||||
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
|
||||
updater->enqueue([weakSelf, updater] {
|
||||
@@ -817,7 +817,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
__weak CSMachine *weakSelf = self;
|
||||
const auto refreshPeriod = view.refreshPeriod;
|
||||
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
|
||||
updater->enqueue([weakSelf, refreshPeriod, updater] {
|
||||
@@ -870,7 +870,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
updater->stop();
|
||||
}
|
||||
@@ -880,7 +880,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
}
|
||||
|
||||
- (void)hardReset {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
|
||||
__weak CSMachine *weakSelf = self;
|
||||
@@ -894,13 +894,13 @@ struct ActivityObserver: public Activity::Observer {
|
||||
}
|
||||
|
||||
- (BOOL)canHardReset {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return NO;
|
||||
return updater->performer.machine->hard_resettable() != nullptr;
|
||||
}
|
||||
|
||||
- (void)softReset {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return;
|
||||
|
||||
__weak CSMachine *weakSelf = self;
|
||||
@@ -914,7 +914,7 @@ struct ActivityObserver: public Activity::Observer {
|
||||
}
|
||||
|
||||
- (BOOL)canSoftReset {
|
||||
const auto updater = _updater.load(std::memory_order_relaxed);
|
||||
const auto updater = _updater.load(std::memory_order::relaxed);
|
||||
if(!updater) return NO;
|
||||
return updater->performer.machine->soft_resettable() != nullptr;
|
||||
}
|
||||
|
||||
+1
-1
@@ -459,7 +459,7 @@ Outputs::Display::ScanTarget::Scan::EndPoint CRT::end_point(const uint16_t data_
|
||||
// Clamp the available range on endpoints. These will almost always be within range, but may go
|
||||
// out during times of resync.
|
||||
.x = uint16_t(std::min(horizontal_flywheel_.current_output_position(), 65535)),
|
||||
.y = preferences_.force_horizontal_scans.load(std::memory_order_relaxed) ?
|
||||
.y = preferences_.force_horizontal_scans.load(std::memory_order::relaxed) ?
|
||||
start_of_line_y_ : current_vertical_flywheel(),
|
||||
.data_offset = data_offset,
|
||||
|
||||
|
||||
+1
-1
@@ -468,7 +468,7 @@ private:
|
||||
void set(const Preferences &preferences) override {
|
||||
force_horizontal_scans.store(
|
||||
preferences.force_horizontal_scans.value_or(DefaultForceHorizontalScans),
|
||||
std::memory_order_relaxed
|
||||
std::memory_order::relaxed
|
||||
);
|
||||
}
|
||||
} preferences_;
|
||||
|
||||
@@ -611,7 +611,7 @@ void ScanTarget::output_scans(const OutputArea &area) {
|
||||
}
|
||||
|
||||
void ScanTarget::draw(const int output_width, const int output_height) {
|
||||
while(is_drawing_to_output_.test_and_set(std::memory_order_acquire));
|
||||
while(is_drawing_to_output_.test_and_set(std::memory_order::acquire));
|
||||
|
||||
test_gl([&]{ glBindFramebuffer(GL_FRAMEBUFFER, target_framebuffer_); });
|
||||
test_gl([&]{ glViewport(0, 0, (GLsizei)output_width, (GLsizei)output_height); });
|
||||
@@ -637,5 +637,5 @@ void ScanTarget::draw(const int output_width, const int output_height) {
|
||||
was_interlacing_ = is_interlacing_;
|
||||
}
|
||||
|
||||
is_drawing_to_output_.clear(std::memory_order_release);
|
||||
is_drawing_to_output_.clear(std::memory_order::release);
|
||||
}
|
||||
@@ -30,8 +30,8 @@ using namespace Outputs::Display;
|
||||
|
||||
BufferingScanTarget::BufferingScanTarget() {
|
||||
// Ensure proper initialisation of the two atomic pointer sets.
|
||||
read_pointers_.store(write_pointers_, std::memory_order_relaxed);
|
||||
submit_pointers_.store(write_pointers_, std::memory_order_relaxed);
|
||||
read_pointers_.store(write_pointers_, std::memory_order::relaxed);
|
||||
submit_pointers_.store(write_pointers_, std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
// MARK: - Producer; pixel data.
|
||||
@@ -68,7 +68,7 @@ uint8_t *BufferingScanTarget::begin_data(const size_t required_length, const siz
|
||||
// Check whether that steps over the read pointer; if so then the final address will be closer
|
||||
// to the write pointer than the old.
|
||||
const auto end_address = texture_address(end_x, output_y);
|
||||
const auto read_pointers = read_pointers_.load(std::memory_order_relaxed);
|
||||
const auto read_pointers = read_pointers_.load(std::memory_order::relaxed);
|
||||
|
||||
const auto end_distance = texture_address_sub(end_address, read_pointers.write_area);
|
||||
const auto previous_distance = texture_address_sub(write_pointers_.write_area, read_pointers.write_area);
|
||||
@@ -154,7 +154,7 @@ Outputs::Display::ScanTarget::Scan *BufferingScanTarget::begin_scan() {
|
||||
}
|
||||
|
||||
const auto result = &scan_buffer_[write_pointers_.scan];
|
||||
const auto read_pointers = read_pointers_.load(std::memory_order_relaxed);
|
||||
const auto read_pointers = read_pointers_.load(std::memory_order::relaxed);
|
||||
|
||||
// Advance the pointer.
|
||||
const auto next_write_pointer = decltype(write_pointers_.scan)((write_pointers_.scan + 1) % scan_buffer_size_);
|
||||
@@ -221,8 +221,8 @@ void BufferingScanTarget::announce(
|
||||
previous_frame_was_complete_ = frame_is_complete_;
|
||||
frame_is_complete_ = true;
|
||||
|
||||
auto write = frame_write_.load(std::memory_order_relaxed);
|
||||
const auto submit_pointers = submit_pointers_.load(std::memory_order_relaxed);
|
||||
auto write = frame_write_.load(std::memory_order::relaxed);
|
||||
const auto submit_pointers = submit_pointers_.load(std::memory_order::relaxed);
|
||||
auto &frame = frames_[size_t(write)];
|
||||
|
||||
frame.first_line = submit_pointers.line;
|
||||
@@ -233,12 +233,12 @@ void BufferingScanTarget::announce(
|
||||
|
||||
field_index_ ^= 1;
|
||||
++write;
|
||||
frame_write_.store(write, std::memory_order_release);
|
||||
frame_write_.store(write, std::memory_order::release);
|
||||
|
||||
auto read = frame_read_.load(std::memory_order_relaxed);
|
||||
auto read = frame_read_.load(std::memory_order::relaxed);
|
||||
if(read == write) {
|
||||
++read;
|
||||
frame_read_.store(read, std::memory_order_relaxed);
|
||||
frame_read_.store(read, std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
// Look for an even-odd pattern in start-of-frame line placement as an indication that
|
||||
@@ -275,7 +275,7 @@ void BufferingScanTarget::announce(
|
||||
#endif
|
||||
|
||||
if(is_visible) {
|
||||
const auto read_pointers = read_pointers_.load(std::memory_order_relaxed);
|
||||
const auto read_pointers = read_pointers_.load(std::memory_order::relaxed);
|
||||
|
||||
// Attempt to allocate a new line, noting allocation success or failure.
|
||||
const auto next_line = uint16_t((write_pointers_.line + 1) % line_buffer_size_);
|
||||
@@ -305,11 +305,11 @@ void BufferingScanTarget::announce(
|
||||
write_pointers_.line = uint16_t((write_pointers_.line + 1) % line_buffer_size_);
|
||||
|
||||
// Update the submit pointers with all lines, scans and data written during this line.
|
||||
submit_pointers_.store(write_pointers_, std::memory_order_release);
|
||||
submit_pointers_.store(write_pointers_, std::memory_order::release);
|
||||
} else {
|
||||
// Something failed, or there was nothing on the line anyway, so reset all pointers to where they
|
||||
// were before this line. Mark frame as incomplete if this was an allocation failure.
|
||||
write_pointers_ = submit_pointers_.load(std::memory_order_relaxed);
|
||||
write_pointers_ = submit_pointers_.load(std::memory_order::relaxed);
|
||||
frame_is_complete_ &= !allocation_has_failed_;
|
||||
}
|
||||
}
|
||||
@@ -347,7 +347,7 @@ size_t BufferingScanTarget::write_area_data_size() const {
|
||||
void BufferingScanTarget::set_modals(const Modals modals) {
|
||||
perform([&] {
|
||||
modals_ = modals;
|
||||
modals_are_dirty_.store(true, std::memory_order_relaxed);
|
||||
modals_are_dirty_.store(true, std::memory_order::relaxed);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -361,10 +361,10 @@ BufferingScanTarget::OutputArea BufferingScanTarget::get_output_area() {
|
||||
// The area to draw is that between the read pointers, representing wherever reading
|
||||
// last stopped, and the submit pointers, representing all the new data that has been
|
||||
// cleared for submission.
|
||||
const auto submit_pointers = submit_pointers_.load(std::memory_order_acquire);
|
||||
const auto read_ahead_pointers = read_ahead_pointers_.load(std::memory_order_relaxed);
|
||||
const auto frame_read = frame_read_.load(std::memory_order_relaxed);
|
||||
const auto frame_write = frame_write_.load(std::memory_order_relaxed);
|
||||
const auto submit_pointers = submit_pointers_.load(std::memory_order::acquire);
|
||||
const auto read_ahead_pointers = read_ahead_pointers_.load(std::memory_order::relaxed);
|
||||
const auto frame_read = frame_read_.load(std::memory_order::relaxed);
|
||||
const auto frame_write = frame_write_.load(std::memory_order::relaxed);
|
||||
|
||||
OutputArea area;
|
||||
|
||||
@@ -383,8 +383,8 @@ BufferingScanTarget::OutputArea BufferingScanTarget::get_output_area() {
|
||||
area.end.write_area_y = texture_address_get_y(submit_pointers.write_area);
|
||||
|
||||
// Update the read-ahead pointers.
|
||||
read_ahead_pointers_.store(submit_pointers, std::memory_order_relaxed);
|
||||
frame_read_.store(frame_write, std::memory_order_relaxed);
|
||||
read_ahead_pointers_.store(submit_pointers, std::memory_order::relaxed);
|
||||
frame_read_.store(frame_write, std::memory_order::relaxed);
|
||||
|
||||
#ifndef NDEBUG
|
||||
area.counter = output_area_counter_;
|
||||
@@ -399,7 +399,7 @@ void BufferingScanTarget::complete_output_area(const OutputArea &area) {
|
||||
new_read_pointers.line = uint16_t(area.end.line);
|
||||
new_read_pointers.scan = uint16_t(area.end.scan);
|
||||
new_read_pointers.write_area = texture_address(uint16_t(area.end.write_area_x), uint16_t(area.end.write_area_y));
|
||||
read_pointers_.store(new_read_pointers, std::memory_order_relaxed);
|
||||
read_pointers_.store(new_read_pointers, std::memory_order::relaxed);
|
||||
|
||||
#ifndef NDEBUG
|
||||
// This will fire if the caller is announcing completed output areas out of order.
|
||||
@@ -422,17 +422,17 @@ void BufferingScanTarget::set_line_buffer(
|
||||
}
|
||||
|
||||
const Outputs::Display::ScanTarget::Modals *BufferingScanTarget::new_modals() {
|
||||
const auto modals_are_dirty = modals_are_dirty_.load(std::memory_order_relaxed);
|
||||
const auto modals_are_dirty = modals_are_dirty_.load(std::memory_order::relaxed);
|
||||
if(!modals_are_dirty) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
modals_are_dirty_.store(false, std::memory_order_relaxed);
|
||||
modals_are_dirty_.store(false, std::memory_order::relaxed);
|
||||
|
||||
// MAJOR SHARP EDGE HERE: assume that because the new_modals have been fetched then the caller will
|
||||
// now ensure their texture buffer is appropriate and set the data size implied by the data type.
|
||||
std::lock_guard lock_guard(producer_lock_);
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
std::atomic_thread_fence(std::memory_order::acquire);
|
||||
data_type_size_ = Outputs::Display::size_for_data_type(modals_.input_data_type);
|
||||
assert((data_type_size_ == 1) || (data_type_size_ == 2) || (data_type_size_ == 4));
|
||||
|
||||
@@ -444,5 +444,5 @@ const Outputs::Display::ScanTarget::Modals &BufferingScanTarget::modals() const
|
||||
}
|
||||
|
||||
bool BufferingScanTarget::has_new_modals() const {
|
||||
return modals_are_dirty_.load(std::memory_order_relaxed);
|
||||
return modals_are_dirty_.load(std::memory_order::relaxed);
|
||||
}
|
||||
@@ -239,7 +239,7 @@ private:
|
||||
|
||||
protected:
|
||||
bool process(size_t length) {
|
||||
const auto delegate = delegate_.load(std::memory_order_relaxed);
|
||||
const auto delegate = delegate_.load(std::memory_order::relaxed);
|
||||
if(!delegate) return false;
|
||||
|
||||
const int scale = static_cast<ConcreteT *>(this)->get_scale();
|
||||
@@ -301,7 +301,7 @@ private:
|
||||
|
||||
std::atomic<int> scale_ = 65536;
|
||||
int get_scale() const {
|
||||
return scale_.load(std::memory_order_relaxed);
|
||||
return scale_.load(std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
const int16_t *buffer_ = nullptr;
|
||||
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
void copy_output_rate(const Speaker &rhs) {
|
||||
output_cycles_per_second_ = rhs.output_cycles_per_second_;
|
||||
output_buffer_size_ = rhs.output_buffer_size_;
|
||||
stereo_output_.store(rhs.stereo_output_.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
||||
stereo_output_.store(rhs.stereo_output_.load(std::memory_order::relaxed), std::memory_order::relaxed);
|
||||
compute_output_rate();
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
virtual void speaker_did_change_input_clock(Speaker &) {}
|
||||
};
|
||||
virtual void set_delegate(Delegate *delegate) {
|
||||
delegate_.store(delegate, std::memory_order_relaxed);
|
||||
delegate_.store(delegate, std::memory_order::relaxed);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
protected:
|
||||
void did_complete_samples(Speaker *, const std::vector<int16_t> &buffer, bool is_stereo) {
|
||||
// Test the delegate for existence again, as it may have changed.
|
||||
const auto delegate = delegate_.load(std::memory_order_relaxed);
|
||||
const auto delegate = delegate_.load(std::memory_order::relaxed);
|
||||
if(!delegate) return;
|
||||
|
||||
++completed_sample_sets_;
|
||||
|
||||
Reference in new issue
Block a user