diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.hpp index b03aa9401..02e27c4df 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiProducer.hpp @@ -47,7 +47,7 @@ template class MultiInterface { std::recursive_mutex &machines_mutex_; private: - std::vector> queues_; + std::vector> queues_; }; class MultiTimedMachine: public MultiInterface, public MachineTypes::TimedMachine { diff --git a/ClockReceiver/JustInTime.hpp b/ClockReceiver/JustInTime.hpp index a7c80e735..040b26e4d 100644 --- a/ClockReceiver/JustInTime.hpp +++ b/ClockReceiver/JustInTime.hpp @@ -315,7 +315,7 @@ template task_queue_; + Concurrency::AsyncTaskQueue task_queue_; }; #endif /* JustInTime_h */ diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 5a87e34a7..3ca2b145f 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -12,7 +12,7 @@ using namespace MOS::MOS6560; -AudioGenerator::AudioGenerator(Concurrency::TaskQueue &audio_queue) : +AudioGenerator::AudioGenerator(Concurrency::AsyncTaskQueue &audio_queue) : audio_queue_(audio_queue) {} diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 3facb0065..1ebd3e6e8 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -21,7 +21,7 @@ namespace MOS6560 { // audio state class AudioGenerator: public ::Outputs::Speaker::SampleSource { public: - AudioGenerator(Concurrency::TaskQueue &audio_queue); + AudioGenerator(Concurrency::AsyncTaskQueue &audio_queue); void set_volume(uint8_t volume); void set_control(int channel, uint8_t value); @@ -33,7 +33,7 @@ class AudioGenerator: public ::Outputs::Speaker::SampleSource { static constexpr bool get_is_stereo() { return false; } private: - Concurrency::TaskQueue &audio_queue_; + Concurrency::AsyncTaskQueue &audio_queue_; unsigned int counters_[4] = {2, 1, 0, 0}; // create a slight phase offset for the three channels unsigned int shift_registers_[4] = {0, 0, 0, 0}; @@ -433,7 +433,7 @@ template class MOS6560 { BusHandler &bus_handler_; Outputs::CRT::CRT crt_; - Concurrency::TaskQueue audio_queue_; + Concurrency::AsyncTaskQueue audio_queue_; AudioGenerator audio_generator_; Outputs::Speaker::PullLowpass speaker_; diff --git a/Components/AY38910/AY38910.cpp b/Components/AY38910/AY38910.cpp index 535b1947f..f02048469 100644 --- a/Components/AY38910/AY38910.cpp +++ b/Components/AY38910/AY38910.cpp @@ -16,7 +16,7 @@ using namespace GI::AY38910; template -AY38910::AY38910(Personality personality, Concurrency::TaskQueue &task_queue) : task_queue_(task_queue) { +AY38910::AY38910(Personality personality, Concurrency::AsyncTaskQueue &task_queue) : task_queue_(task_queue) { // Don't use the low bit of the envelope position if this is an AY. envelope_position_mask_ |= personality == Personality::AY38910; diff --git a/Components/AY38910/AY38910.hpp b/Components/AY38910/AY38910.hpp index 22da85b21..b06a92b2b 100644 --- a/Components/AY38910/AY38910.hpp +++ b/Components/AY38910/AY38910.hpp @@ -71,7 +71,7 @@ enum class Personality { template class AY38910: public ::Outputs::Speaker::SampleSource { public: /// Creates a new AY38910. - AY38910(Personality, Concurrency::TaskQueue &); + AY38910(Personality, Concurrency::AsyncTaskQueue &); /// Sets the value the AY would read from its data lines if it were not outputting. void set_data_input(uint8_t r); @@ -114,7 +114,7 @@ template class AY38910: public ::Outputs::Speaker::SampleSource static constexpr bool get_is_stereo() { return is_stereo; } private: - Concurrency::TaskQueue &task_queue_; + Concurrency::AsyncTaskQueue &task_queue_; int selected_register_ = 0; uint8_t registers_[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; diff --git a/Components/AudioToggle/AudioToggle.cpp b/Components/AudioToggle/AudioToggle.cpp index f9a3164c7..7188badd9 100644 --- a/Components/AudioToggle/AudioToggle.cpp +++ b/Components/AudioToggle/AudioToggle.cpp @@ -10,7 +10,7 @@ using namespace Audio; -Audio::Toggle::Toggle(Concurrency::TaskQueue &audio_queue) : +Audio::Toggle::Toggle(Concurrency::AsyncTaskQueue &audio_queue) : audio_queue_(audio_queue) {} void Toggle::get_samples(std::size_t number_of_samples, std::int16_t *target) { diff --git a/Components/AudioToggle/AudioToggle.hpp b/Components/AudioToggle/AudioToggle.hpp index 4d67c5b67..4390361c6 100644 --- a/Components/AudioToggle/AudioToggle.hpp +++ b/Components/AudioToggle/AudioToggle.hpp @@ -19,7 +19,7 @@ namespace Audio { */ class Toggle: public Outputs::Speaker::SampleSource { public: - Toggle(Concurrency::TaskQueue &audio_queue); + Toggle(Concurrency::AsyncTaskQueue &audio_queue); void get_samples(std::size_t number_of_samples, std::int16_t *target); void set_sample_volume_range(std::int16_t range); @@ -31,7 +31,7 @@ class Toggle: public Outputs::Speaker::SampleSource { private: // Accessed on the calling thread. bool is_enabled_ = false; - Concurrency::TaskQueue &audio_queue_; + Concurrency::AsyncTaskQueue &audio_queue_; // Accessed on the audio thread. int16_t level_ = 0, volume_ = 0; diff --git a/Components/KonamiSCC/KonamiSCC.cpp b/Components/KonamiSCC/KonamiSCC.cpp index c87dd89c6..81a2af502 100644 --- a/Components/KonamiSCC/KonamiSCC.cpp +++ b/Components/KonamiSCC/KonamiSCC.cpp @@ -12,7 +12,7 @@ using namespace Konami; -SCC::SCC(Concurrency::TaskQueue &task_queue) : +SCC::SCC(Concurrency::AsyncTaskQueue &task_queue) : task_queue_(task_queue) {} bool SCC::is_zero_level() const { diff --git a/Components/KonamiSCC/KonamiSCC.hpp b/Components/KonamiSCC/KonamiSCC.hpp index 6aa04d8f7..b1db2b17d 100644 --- a/Components/KonamiSCC/KonamiSCC.hpp +++ b/Components/KonamiSCC/KonamiSCC.hpp @@ -24,7 +24,7 @@ namespace Konami { class SCC: public ::Outputs::Speaker::SampleSource { public: /// Creates a new SCC. - SCC(Concurrency::TaskQueue &task_queue); + SCC(Concurrency::AsyncTaskQueue &task_queue); /// As per ::SampleSource; provides a broadphase test for silence. bool is_zero_level() const; @@ -41,7 +41,7 @@ class SCC: public ::Outputs::Speaker::SampleSource { uint8_t read(uint16_t address); private: - Concurrency::TaskQueue &task_queue_; + Concurrency::AsyncTaskQueue &task_queue_; // State from here on down is accessed ony from the audio thread. int master_divider_ = 0; diff --git a/Components/OPx/Implementation/OPLBase.hpp b/Components/OPx/Implementation/OPLBase.hpp index 5409b7cb2..8183d4287 100644 --- a/Components/OPx/Implementation/OPLBase.hpp +++ b/Components/OPx/Implementation/OPLBase.hpp @@ -26,9 +26,9 @@ template class OPLBase: public ::Outputs::Speaker::SampleSource } protected: - OPLBase(Concurrency::TaskQueue &task_queue) : task_queue_(task_queue) {} + OPLBase(Concurrency::AsyncTaskQueue &task_queue) : task_queue_(task_queue) {} - Concurrency::TaskQueue &task_queue_; + Concurrency::AsyncTaskQueue &task_queue_; private: uint8_t selected_register_ = 0; diff --git a/Components/OPx/OPLL.cpp b/Components/OPx/OPLL.cpp index 7f86c80c1..f5d8feddd 100644 --- a/Components/OPx/OPLL.cpp +++ b/Components/OPx/OPLL.cpp @@ -12,7 +12,7 @@ using namespace Yamaha::OPL; -OPLL::OPLL(Concurrency::TaskQueue &task_queue, int audio_divider, bool is_vrc7): +OPLL::OPLL(Concurrency::AsyncTaskQueue &task_queue, int audio_divider, bool is_vrc7): OPLBase(task_queue), audio_divider_(audio_divider), is_vrc7_(is_vrc7) { // Due to the way that sound mixing works on the OPLL, the audio divider may not // be larger than 4. diff --git a/Components/OPx/OPLL.hpp b/Components/OPx/OPLL.hpp index 07072ff41..530d84e77 100644 --- a/Components/OPx/OPLL.hpp +++ b/Components/OPx/OPLL.hpp @@ -24,7 +24,7 @@ namespace OPL { class OPLL: public OPLBase { public: /// Creates a new OPLL or VRC7. - OPLL(Concurrency::TaskQueue &task_queue, int audio_divider = 1, bool is_vrc7 = false); + OPLL(Concurrency::AsyncTaskQueue &task_queue, int audio_divider = 1, bool is_vrc7 = false); /// As per ::SampleSource; provides audio output. void get_samples(std::size_t number_of_samples, std::int16_t *target); diff --git a/Components/SN76489/SN76489.cpp b/Components/SN76489/SN76489.cpp index a413b143c..8705b24c7 100644 --- a/Components/SN76489/SN76489.cpp +++ b/Components/SN76489/SN76489.cpp @@ -13,7 +13,7 @@ using namespace TI; -SN76489::SN76489(Personality personality, Concurrency::TaskQueue &task_queue, int additional_divider) : task_queue_(task_queue) { +SN76489::SN76489(Personality personality, Concurrency::AsyncTaskQueue &task_queue, int additional_divider) : task_queue_(task_queue) { set_sample_volume_range(0); switch(personality) { diff --git a/Components/SN76489/SN76489.hpp b/Components/SN76489/SN76489.hpp index 43da90661..877c71354 100644 --- a/Components/SN76489/SN76489.hpp +++ b/Components/SN76489/SN76489.hpp @@ -23,7 +23,7 @@ class SN76489: public Outputs::Speaker::SampleSource { }; /// Creates a new SN76489. - SN76489(Personality personality, Concurrency::TaskQueue &task_queue, int additional_divider = 1); + SN76489(Personality personality, Concurrency::AsyncTaskQueue &task_queue, int additional_divider = 1); /// Writes a new value to the SN76489. void write(uint8_t value); @@ -41,7 +41,7 @@ class SN76489: public Outputs::Speaker::SampleSource { void evaluate_output_volume(); int volumes_[16]; - Concurrency::TaskQueue &task_queue_; + Concurrency::AsyncTaskQueue &task_queue_; struct ToneChannel { // Programmatically-set state; updated by the processor. diff --git a/Concurrency/AsyncTaskQueue.hpp b/Concurrency/AsyncTaskQueue.hpp index a9510abf7..7a8452734 100644 --- a/Concurrency/AsyncTaskQueue.hpp +++ b/Concurrency/AsyncTaskQueue.hpp @@ -17,11 +17,6 @@ #include "../ClockReceiver/TimeTypes.hpp" -#if defined(__APPLE__) && !defined(IGNORE_APPLE) -#include -#define USE_GCD -#endif - namespace Concurrency { /// An implementation detail; provides the time-centric part of a TaskQueue with a real Performer. @@ -52,22 +47,27 @@ template <> struct TaskQueueStorage { }; /*! - A task queue allows a caller to enqueue void(void) functions. Those functions are guaranteed + A task queue allows a caller to enqueue @c void(void) functions. Those functions are guaranteed to be performed serially and asynchronously from the caller. If @c perform_automatically is true, functions will be performed as soon as is possible, at the cost of thread synchronisation. - If @c perform_automatically is false, functions will be queued up and not dispatched + If @c perform_automatically is false, functions will be queued up but not dispatched until a call to perform(). If a @c Performer type is supplied then a public member, @c performer will be constructed - with the arguments supplied to TaskQueue's constructor, and that class will receive calls of the - form @c .perform(nanos) to update it to every batch of new actions. + with the arguments supplied to TaskQueue's constructor. That instance will receive calls of the + form @c .perform(nanos) before every batch of new actions, indicating how much time has + passed since the previous @c perform. + + @note Even if @c perform_automatically is true, actions may be batched, when a long-running + action occupies the asynchronous thread for long enough. So it is not true that @c perform will be + called once per action. */ -template class TaskQueue: public TaskQueueStorage { +template class AsyncTaskQueue: public TaskQueueStorage { public: - template TaskQueue(Args&&... args) : + template AsyncTaskQueue(Args&&... args) : TaskQueueStorage(std::forward(args)...), thread_{ [this] { @@ -157,7 +157,7 @@ template class TaskQueue flush_condition.wait(lock, [&has_run] { return has_run; }); } - ~TaskQueue() { + ~AsyncTaskQueue() { stop(); } diff --git a/Machines/Amiga/Audio.hpp b/Machines/Amiga/Audio.hpp index 41b414f65..78681d8e8 100644 --- a/Machines/Amiga/Audio.hpp +++ b/Machines/Amiga/Audio.hpp @@ -149,7 +149,7 @@ class Audio: public DMADevice<4> { // Transient output state, and its destination. Outputs::Speaker::PushLowpass speaker_; - Concurrency::TaskQueue queue_; + Concurrency::AsyncTaskQueue queue_; using AudioBuffer = std::array; static constexpr int BufferCount = 3; diff --git a/Machines/AmstradCPC/AmstradCPC.cpp b/Machines/AmstradCPC/AmstradCPC.cpp index ca41eb1b2..bcffa6f3c 100644 --- a/Machines/AmstradCPC/AmstradCPC.cpp +++ b/Machines/AmstradCPC/AmstradCPC.cpp @@ -156,7 +156,7 @@ class AYDeferrer { } private: - Concurrency::TaskQueue audio_queue_; + Concurrency::AsyncTaskQueue audio_queue_; GI::AY38910::AY38910 ay_; Outputs::Speaker::PullLowpass> speaker_; HalfCycles cycles_since_update_; diff --git a/Machines/Apple/AppleII/AppleII.cpp b/Machines/Apple/AppleII/AppleII.cpp index fbbc623d3..e6d986ea8 100644 --- a/Machines/Apple/AppleII/AppleII.cpp +++ b/Machines/Apple/AppleII/AppleII.cpp @@ -95,7 +95,7 @@ template class ConcreteMachine: uint8_t ram_[65536], aux_ram_[65536]; std::vector rom_; - Concurrency::TaskQueue audio_queue_; + Concurrency::AsyncTaskQueue audio_queue_; Audio::Toggle audio_toggle_; Outputs::Speaker::PullLowpass speaker_; Cycles cycles_since_audio_update_; diff --git a/Machines/Apple/AppleIIgs/AppleIIgs.cpp b/Machines/Apple/AppleIIgs/AppleIIgs.cpp index 7037af170..d0fe468fb 100644 --- a/Machines/Apple/AppleIIgs/AppleIIgs.cpp +++ b/Machines/Apple/AppleIIgs/AppleIIgs.cpp @@ -1150,7 +1150,7 @@ class ConcreteMachine: Apple::Disk::DiskIIDrive drives525_[2]; // The audio parts. - Concurrency::TaskQueue audio_queue_; + Concurrency::AsyncTaskQueue audio_queue_; Apple::IIgs::Sound::GLU sound_glu_; Audio::Toggle audio_toggle_; using AudioSource = Outputs::Speaker::CompoundSource; diff --git a/Machines/Apple/AppleIIgs/Sound.cpp b/Machines/Apple/AppleIIgs/Sound.cpp index 942746257..f1599b1eb 100644 --- a/Machines/Apple/AppleIIgs/Sound.cpp +++ b/Machines/Apple/AppleIIgs/Sound.cpp @@ -16,7 +16,7 @@ using namespace Apple::IIgs::Sound; -GLU::GLU(Concurrency::TaskQueue &audio_queue) : audio_queue_(audio_queue) { +GLU::GLU(Concurrency::AsyncTaskQueue &audio_queue) : audio_queue_(audio_queue) { // Reset all pending stores. MemoryWrite disabled_write; disabled_write.enabled = false; diff --git a/Machines/Apple/AppleIIgs/Sound.hpp b/Machines/Apple/AppleIIgs/Sound.hpp index 7b822c3da..942a94b7d 100644 --- a/Machines/Apple/AppleIIgs/Sound.hpp +++ b/Machines/Apple/AppleIIgs/Sound.hpp @@ -21,7 +21,7 @@ namespace Sound { class GLU: public Outputs::Speaker::SampleSource { public: - GLU(Concurrency::TaskQueue &audio_queue); + GLU(Concurrency::AsyncTaskQueue &audio_queue); void set_control(uint8_t); uint8_t get_control(); @@ -42,7 +42,7 @@ class GLU: public Outputs::Speaker::SampleSource { void skip_samples(const std::size_t number_of_samples); private: - Concurrency::TaskQueue &audio_queue_; + Concurrency::AsyncTaskQueue &audio_queue_; uint16_t address_ = 0; diff --git a/Machines/Apple/Macintosh/Audio.cpp b/Machines/Apple/Macintosh/Audio.cpp index 076c2b857..d24497990 100644 --- a/Machines/Apple/Macintosh/Audio.cpp +++ b/Machines/Apple/Macintosh/Audio.cpp @@ -18,7 +18,7 @@ const std::size_t sample_length = 352 / 2; } -Audio::Audio(Concurrency::TaskQueue &task_queue) : task_queue_(task_queue) {} +Audio::Audio(Concurrency::AsyncTaskQueue &task_queue) : task_queue_(task_queue) {} // MARK: - Inputs diff --git a/Machines/Apple/Macintosh/Audio.hpp b/Machines/Apple/Macintosh/Audio.hpp index 5bb4b7057..bdf0ebd40 100644 --- a/Machines/Apple/Macintosh/Audio.hpp +++ b/Machines/Apple/Macintosh/Audio.hpp @@ -27,7 +27,7 @@ namespace Macintosh { */ class Audio: public ::Outputs::Speaker::SampleSource { public: - Audio(Concurrency::TaskQueue &task_queue); + Audio(Concurrency::AsyncTaskQueue &task_queue); /*! Macintosh audio is (partly) sourced by the same scanning @@ -58,7 +58,7 @@ class Audio: public ::Outputs::Speaker::SampleSource { constexpr static bool get_is_stereo() { return false; } private: - Concurrency::TaskQueue &task_queue_; + Concurrency::AsyncTaskQueue &task_queue_; // A queue of fetched samples; read from by one thread, // written to by another. diff --git a/Machines/Apple/Macintosh/DeferredAudio.hpp b/Machines/Apple/Macintosh/DeferredAudio.hpp index fe0ebdb3a..9277e1569 100644 --- a/Machines/Apple/Macintosh/DeferredAudio.hpp +++ b/Machines/Apple/Macintosh/DeferredAudio.hpp @@ -16,7 +16,7 @@ namespace Apple { namespace Macintosh { struct DeferredAudio { - Concurrency::TaskQueue queue; + Concurrency::AsyncTaskQueue queue; Audio audio; Outputs::Speaker::PullLowpass