From 7886c2df7abae474733620ef73b80a938fe7821e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 7 Jul 2022 10:48:42 -0400 Subject: [PATCH] Start experimenting with a more event-based approach to timing. --- Concurrency/AsyncUpdater.hpp | 77 +++++++++++++++++++ .../Clock Signal.xcodeproj/project.pbxproj | 2 + .../Mac/Clock Signal/Machine/CSMachine.mm | 9 +++ 3 files changed, 88 insertions(+) create mode 100644 Concurrency/AsyncUpdater.hpp diff --git a/Concurrency/AsyncUpdater.hpp b/Concurrency/AsyncUpdater.hpp new file mode 100644 index 000000000..5596a1dcd --- /dev/null +++ b/Concurrency/AsyncUpdater.hpp @@ -0,0 +1,77 @@ +// +// AsyncUpdater.h +// Clock Signal +// +// Created by Thomas Harte on 06/07/2022. +// Copyright © 2022 Thomas Harte. All rights reserved. +// + +#ifndef AsyncUpdater_hpp +#define AsyncUpdater_hpp + +#include +#include +#include + +#include "../ClockReceiver/TimeTypes.hpp" + +namespace Concurrency { + +template class AsyncUpdater { + public: + template AsyncUpdater(Args&&... args) + : performer_(std::forward(args)...), + performer_thread_{ + [this] { + Time::Nanos last_fired = Time::nanos_now(); + + while(!should_quit) { + // Wait for a new action to be signalled, and grab it. + std::unique_lock lock(condition_mutex_); + while(actions_.empty()) { + condition_.wait(lock); + } + auto action = actions_.pop_back(); + lock.unlock(); + + // Update to now. + auto time_now = Time::nanos_now(); + performer_.perform(time_now - last_fired); + last_fired = time_now; + + // Perform the action. + action(); + } + } + } {} + + /// Run the performer up to 'now' and then perform @c post_action. + /// + /// @c post_action will be performed asynchronously, on the same + /// thread as the performer. + void update(const std::function &post_action) { + std::lock_guard guard(condition_mutex_); + actions_.push_back(post_action); + condition_.notify_all(); + } + + ~AsyncUpdater() { + should_quit = true; + update([] {}); + performer_thread_.join(); + } + + private: + Performer performer_; + + std::thread performer_thread_; + std::mutex condition_mutex_; + std::condition_variable condition_; + std::vector> actions_; + std::atomic should_quit = false; +}; + + +} + +#endif /* AsyncUpdater_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 3311a4686..87026c868 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -2138,6 +2138,7 @@ 4BDCC5F81FB27A5E001220C5 /* ROMMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ROMMachine.hpp; sourceTree = ""; }; 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Z80MachineCycleTests.swift; sourceTree = ""; }; 4BE0151C286A8C8E00EA42E9 /* MemorySwitches.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MemorySwitches.hpp; sourceTree = ""; }; + 4BE0151E28766ECF00EA42E9 /* AsyncUpdater.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AsyncUpdater.hpp; sourceTree = ""; }; 4BE0A3EC237BB170002AB46F /* ST.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ST.cpp; sourceTree = ""; }; 4BE0A3ED237BB170002AB46F /* ST.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ST.hpp; sourceTree = ""; }; 4BE211DD253E4E4800435408 /* 65C02_no_Rockwell_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 65C02_no_Rockwell_test.bin; path = "Klaus Dormann/65C02_no_Rockwell_test.bin"; sourceTree = ""; }; @@ -2754,6 +2755,7 @@ children = ( 4B3940E51DA83C8300427841 /* AsyncTaskQueue.cpp */, 4B3940E61DA83C8300427841 /* AsyncTaskQueue.hpp */, + 4BE0151E28766ECF00EA42E9 /* AsyncUpdater.hpp */, ); name = Concurrency; path = ../../Concurrency; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 61206bd56..214aa280c 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -24,6 +24,7 @@ #include "../../../../ClockReceiver/TimeTypes.hpp" #include "../../../../ClockReceiver/ScanSynchroniser.hpp" +#include "../../../../Concurrency/AsyncUpdater.hpp" #import "CSStaticAnalyser+TargetVector.h" #import "NSBundle+DataResource.h" @@ -34,6 +35,14 @@ #include #include +namespace { + +struct Updater {}; + +Concurrency::AsyncUpdater updater(); + +} + @interface CSMachine() - (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length; - (void)speakerDidChangeInputClock:(Outputs::Speaker::Speaker *)speaker;