From 77165ae552a0ad508c3934c4d51f07dec1f9de44 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 16 Sep 2026 13:55:38 -0400 Subject: [PATCH 1/3] Use std::atomic_flag::wait. --- .../Implementation/MultiProducer.cpp | 21 +++++++------------ Concurrency/AsyncTaskQueue.hpp | 13 ++++-------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp index 2136498d3..ebca26b7c 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp @@ -8,8 +8,7 @@ #include "MultiProducer.hpp" -#include -#include +#include using namespace Analyser::Dynamic; @@ -19,28 +18,24 @@ template void MultiInterface::perform_parallel(const std::function &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_flag finished = false; { - std::lock_guard machines_lock(machines_mutex_); - std::lock_guard lock(mutex); - outstanding_machines = machines_.size(); + std::size_t outstanding_machines = machines_.size(); for(std::size_t index = 0; index < machines_.size(); ++index) { const auto machine = ::Machine::get(*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) { +// finished.test_and_set(); + } }); } } - std::unique_lock lock(mutex); - condition.wait(lock, [&outstanding_machines] { return !outstanding_machines; }); + finished.wait(false, std::memory_order_relaxed); } template diff --git a/Concurrency/AsyncTaskQueue.hpp b/Concurrency/AsyncTaskQueue.hpp index 9a05e8702..414eef60b 100644 --- a/Concurrency/AsyncTaskQueue.hpp +++ b/Concurrency/AsyncTaskQueue.hpp @@ -144,22 +144,17 @@ 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_all(); + enqueue([&flushed] () { + flushed.test_and_set(); }); if constexpr (!perform_automatically) { perform(); } - flush_condition.wait(lock, [&has_run] { return has_run; }); + flushed.wait(false, std::memory_order::relaxed); } /// Schedules any remaining unscheduled work, then spins From a45d38a9cca43a1e4afaf7894e8ae7278abfab80 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 6 Oct 2026 22:56:53 -0400 Subject: [PATCH 2/3] Fix notify semantics. --- .../MultiMachine/Implementation/MultiProducer.cpp | 13 ++++++------- Concurrency/AsyncTaskQueue.hpp | 5 +++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp index ebca26b7c..409732cb9 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.cpp @@ -18,24 +18,23 @@ template void MultiInterface::perform_parallel(const std::function &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::atomic_flag finished = false; + std::atomic outstanding_machines = int(machines_.size()); + std::atomic_flag finished{}; { - std::size_t outstanding_machines = machines_.size(); - for(std::size_t index = 0; index < machines_.size(); ++index) { const auto machine = ::Machine::get(*machines_[index].get()); queues_[index].enqueue([&finished, machine, function, &outstanding_machines]() { if(machine) function(machine); - --outstanding_machines; - if(!outstanding_machines) { -// finished.test_and_set(); + if(outstanding_machines.fetch_sub(1, std::memory_order::relaxed) == 1) { + finished.test_and_set(std::memory_order::release); + finished.notify_one(); } }); } } - finished.wait(false, std::memory_order_relaxed); + finished.wait(false, std::memory_order::acquire); } template diff --git a/Concurrency/AsyncTaskQueue.hpp b/Concurrency/AsyncTaskQueue.hpp index 10b053ad1..78cd9dacf 100644 --- a/Concurrency/AsyncTaskQueue.hpp +++ b/Concurrency/AsyncTaskQueue.hpp @@ -150,14 +150,15 @@ public: std::atomic_flag flushed = false; enqueue([&flushed] () { - flushed.test_and_set(); + flushed.test_and_set(std::memory_order::release); + flushed.notify_one(); }); if constexpr (!perform_automatically) { perform(); } - flushed.wait(false, std::memory_order::relaxed); + flushed.wait(false, std::memory_order::acquire); } /// Schedules any remaining unscheduled work, then spins From 6b160810b1664012550b1f3e9a973d4f0b3e5387 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 6 Oct 2026 22:59:25 -0400 Subject: [PATCH 3/3] Use more rational std::memory_order::. --- .../Implementation/MultiSpeaker.cpp | 6 +-- Components/uPD7002/uPD7002.cpp | 4 +- Concurrency/AsyncTaskQueue.hpp | 4 +- Concurrency/SpinLock.hpp | 4 +- Machines/Amiga/Audio.cpp | 8 ++-- Machines/Apple/ADB/Mouse.cpp | 6 +-- Machines/Apple/AppleIIgs/Sound.cpp | 12 ++--- Machines/Apple/Macintosh/Audio.cpp | 4 +- Machines/Commodore/Vic-20/Vic20.cpp | 4 +- Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp | 8 ++-- .../Mac/Clock Signal/Machine/CSMachine.mm | 22 ++++----- Outputs/CRT/CRT.cpp | 2 +- Outputs/CRT/CRT.hpp | 2 +- Outputs/OpenGL/ScanTarget.cpp | 4 +- Outputs/ScanTargets/BufferingScanTarget.cpp | 48 +++++++++---------- .../Speaker/Implementation/LowpassSpeaker.hpp | 4 +- Outputs/Speaker/Speaker.hpp | 6 +-- 17 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp index 6c46e749e..da3120469 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiSpeaker.cpp @@ -61,7 +61,7 @@ void MultiSpeaker::set_output_volume(const float volume) { } void MultiSpeaker::speaker_did_complete_samples(Speaker &speaker, const std::vector &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); } diff --git a/Components/uPD7002/uPD7002.cpp b/Components/uPD7002/uPD7002.cpp index 0f0673fc7..3166f55df 100644 --- a/Components/uPD7002/uPD7002.cpp +++ b/Components/uPD7002/uPD7002.cpp @@ -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); } diff --git a/Concurrency/AsyncTaskQueue.hpp b/Concurrency/AsyncTaskQueue.hpp index 78cd9dacf..79f458925 100644 --- a/Concurrency/AsyncTaskQueue.hpp +++ b/Concurrency/AsyncTaskQueue.hpp @@ -191,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(); diff --git a/Concurrency/SpinLock.hpp b/Concurrency/SpinLock.hpp index b65ce2928..5809a7e5c 100644 --- a/Concurrency/SpinLock.hpp +++ b/Concurrency/SpinLock.hpp @@ -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_; diff --git a/Machines/Amiga/Audio.cpp b/Machines/Amiga/Audio.cpp index 0ce046b82..e963d8930 100644 --- a/Machines/Amiga/Audio.cpp +++ b/Machines/Amiga/Audio.cpp @@ -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; diff --git a/Machines/Apple/ADB/Mouse.cpp b/Machines/Apple/ADB/Mouse.cpp index d7f431308..ea83f6334 100644 --- a/Machines/Apple/ADB/Mouse.cpp +++ b/Machines/Apple/ADB/Mouse.cpp @@ -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; diff --git a/Machines/Apple/AppleIIgs/Sound.cpp b/Machines/Apple/AppleIIgs/Sound.cpp index f1add706d..f33e70f6c 100644 --- a/Machines/Apple/AppleIIgs/Sound.cpp +++ b/Machines/Apple/AppleIIgs/Sound.cpp @@ -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(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 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); } } diff --git a/Machines/Apple/Macintosh/Audio.cpp b/Machines/Apple/Macintosh/Audio.cpp index bfeaed483..2f9147b6b 100644 --- a/Machines/Apple/Macintosh/Audio.cpp +++ b/Machines/Apple/Macintosh/Audio.cpp @@ -27,7 +27,7 @@ Audio::Audio(Concurrency::AsyncTaskQueue &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(target, target + cycles_left_in_sample, output_level); target += cycles_left_in_sample; diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index 29f7e6e25..4b22fb637 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -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 ); } diff --git a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp index d035296e7..a2cf047fc 100644 --- a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp +++ b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp @@ -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: diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index ab8b7a856..86a58ea25 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -197,12 +197,12 @@ struct ActivityObserver: public Activity::Observer { _machine->scan_producer()->set_scan_target(_view.scanTarget.scanTarget); _ownedUpdater = std::make_unique(); - 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; } diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 3f78b0109..4b99fd6d4 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -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, diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index 3ac4252a7..4c31d982d 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -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_; diff --git a/Outputs/OpenGL/ScanTarget.cpp b/Outputs/OpenGL/ScanTarget.cpp index ab3a21757..b144c0b9d 100644 --- a/Outputs/OpenGL/ScanTarget.cpp +++ b/Outputs/OpenGL/ScanTarget.cpp @@ -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); } diff --git a/Outputs/ScanTargets/BufferingScanTarget.cpp b/Outputs/ScanTargets/BufferingScanTarget.cpp index e77a340b0..2058325b8 100644 --- a/Outputs/ScanTargets/BufferingScanTarget.cpp +++ b/Outputs/ScanTargets/BufferingScanTarget.cpp @@ -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); } diff --git a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp index 04b2bc56d..e75fc71c6 100644 --- a/Outputs/Speaker/Implementation/LowpassSpeaker.hpp +++ b/Outputs/Speaker/Implementation/LowpassSpeaker.hpp @@ -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(this)->get_scale(); @@ -301,7 +301,7 @@ private: std::atomic 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; diff --git a/Outputs/Speaker/Speaker.hpp b/Outputs/Speaker/Speaker.hpp index 01a560bae..f56ad7d34 100644 --- a/Outputs/Speaker/Speaker.hpp +++ b/Outputs/Speaker/Speaker.hpp @@ -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 &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_;