diff --git a/Concurrency/BestEffortUpdater.cpp b/Concurrency/BestEffortUpdater.cpp deleted file mode 100644 index 68ee39f97..000000000 --- a/Concurrency/BestEffortUpdater.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// -// BestEffortUpdater.cpp -// Clock Signal -// -// Created by Thomas Harte on 04/10/2017. -// Copyright 2017 Thomas Harte. All rights reserved. -// - -#include "BestEffortUpdater.hpp" - -#include - -using namespace Concurrency; - -BestEffortUpdater::BestEffortUpdater() : - update_thread_([this]() { - this->update_loop(); - }) {} - -BestEffortUpdater::~BestEffortUpdater() { - // Sever the delegate now, as soon as possible, then wait for any - // pending tasks to finish. - set_delegate(nullptr); - flush(); - - // Wind up the update thread. - should_quit_ = true; - update(); - update_thread_.join(); -} - -void BestEffortUpdater::update(int flags) { - // Bump the requested target time and set the update requested flag. - { - std::lock_guard lock(update_mutex_); - has_skipped_ = update_requested_; - update_requested_ = true; - flags_ |= flags; - target_time_ = std::chrono::high_resolution_clock::now().time_since_epoch().count(); - } - update_condition_.notify_one(); -} - -void BestEffortUpdater::update_loop() { - while(true) { - std::unique_lock lock(update_mutex_); - is_updating_ = false; - - // Wait to be signalled. - update_condition_.wait(lock, [this]() -> bool { - return update_requested_; - }); - - // Possibly this signalling really means 'quit'. - if(should_quit_) return; - - // Note update started, crib the target time. - auto target_time = target_time_; - update_requested_ = false; - - // If this was actually the first update request, silently swallow it. - if(!has_previous_time_point_) { - has_previous_time_point_ = true; - previous_time_point_ = target_time; - continue; - } - - // Release the lock on requesting new updates. - is_updating_ = true; - const int flags = flags_; - flags_ = 0; - lock.unlock(); - - // Invoke the delegate, if supplied, in order to run. - const int64_t integer_duration = std::max(target_time - previous_time_point_, int64_t(0)); - const auto delegate = delegate_.load(); - if(delegate) { - // Cap running at 1/5th of a second, to avoid doing a huge amount of work after any - // brief system interruption. - const double duration = std::min(double(integer_duration) / 1e9, 0.2); - const double elapsed_duration = delegate->update(this, duration, has_skipped_, flags); - - previous_time_point_ += int64_t(elapsed_duration * 1e9); - has_skipped_ = false; - } - } -} - -void BestEffortUpdater::flush() { - // Spin lock; this is allowed to be slow. - while(true) { - std::lock_guard lock(update_mutex_); - if(!is_updating_) return; - } -} - -void BestEffortUpdater::set_delegate(Delegate *const delegate) { - delegate_.store(delegate); -} - diff --git a/Concurrency/BestEffortUpdater.hpp b/Concurrency/BestEffortUpdater.hpp deleted file mode 100644 index edf92edb7..000000000 --- a/Concurrency/BestEffortUpdater.hpp +++ /dev/null @@ -1,82 +0,0 @@ -// -// BestEffortUpdater.hpp -// Clock Signal -// -// Created by Thomas Harte on 04/10/2017. -// Copyright 2017 Thomas Harte. All rights reserved. -// - -#ifndef BestEffortUpdater_hpp -#define BestEffortUpdater_hpp - -#include -#include -#include -#include -#include - -#include "../ClockReceiver/TimeTypes.hpp" - -namespace Concurrency { - -/*! - Accepts timing cues from multiple threads and ensures that a delegate receives calls to total - a certain number of cycles per second, that those calls are strictly serialised, and that no - backlog of calls accrues. - - No guarantees about the thread that the delegate will be called on are made. -*/ -class BestEffortUpdater { - public: - BestEffortUpdater(); - ~BestEffortUpdater(); - - /// A delegate receives timing cues. - struct Delegate { - /*! - Instructs the delegate to run for at least @c duration, providing hints as to whether multiple updates were requested before the previous had completed - (as @c did_skip_previous_update) and providing the union of any flags supplied to @c update. - - @returns The amount of time actually run for. - */ - virtual Time::Seconds update(BestEffortUpdater *updater, Time::Seconds duration, bool did_skip_previous_update, int flags) = 0; - }; - - /// Sets the current delegate. - void set_delegate(Delegate *); - - /*! - If the delegate is not currently in the process of an `update` call, calls it now to catch up to the current time. - The call is asynchronous; this method will return immediately. - */ - void update(int flags = 0); - - /// Blocks until any ongoing update is complete; may spin. - void flush(); - - private: - std::atomic should_quit_; - std::atomic is_updating_; - - int64_t target_time_; - int flags_ = 0; - bool update_requested_; - std::mutex update_mutex_; - std::condition_variable update_condition_; - - decltype(target_time_) previous_time_point_; - bool has_previous_time_point_ = false; - std::atomic has_skipped_ = false; - - std::atomicdelegate_ = nullptr; - - void update_loop(); - - // This is deliberately at the bottom, to ensure it constructs after the various - // mutexs, conditions, etc, that it'll depend upon. - std::thread update_thread_; -}; - -} - -#endif /* BestEffortUpdater_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 4f7c5eadf..059d3e6d3 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 4B055A7A1FAE78A00060FFFF /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B055A771FAE78210060FFFF /* SDL2.framework */; }; 4B055A7E1FAE84AA0060FFFF /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B055A7C1FAE84A50060FFFF /* main.cpp */; }; 4B055A8D1FAE85920060FFFF /* AsyncTaskQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3940E51DA83C8300427841 /* AsyncTaskQueue.cpp */; }; - 4B055A8E1FAE85920060FFFF /* BestEffortUpdater.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B80ACFE1F85CAC900176895 /* BestEffortUpdater.cpp */; }; 4B055A8F1FAE85A90060FFFF /* FileHolder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B5FADB81DE3151600AEC565 /* FileHolder.cpp */; }; 4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; }; 4B055A911FAE85B50060FFFF /* Cartridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEE0A6A1D72496600532C7B /* Cartridge.cpp */; }; @@ -384,7 +383,6 @@ 4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; }; 4B7F1897215486A200388727 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F1896215486A100388727 /* StaticAnalyser.cpp */; }; 4B7F1898215486A200388727 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F1896215486A100388727 /* StaticAnalyser.cpp */; }; - 4B80AD001F85CACA00176895 /* BestEffortUpdater.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B80ACFE1F85CAC900176895 /* BestEffortUpdater.cpp */; }; 4B8318B022D3E531006DB630 /* AppleII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE0050227CE8CA000CA200 /* AppleII.cpp */; }; 4B8318B122D3E53A006DB630 /* DiskIICard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004E227CE8CA000CA200 /* DiskIICard.cpp */; }; 4B8318B222D3E53C006DB630 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCE004D227CE8CA000CA200 /* Video.cpp */; }; @@ -1218,8 +1216,6 @@ 4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = ""; }; 4B7F1896215486A100388727 /* StaticAnalyser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StaticAnalyser.cpp; sourceTree = ""; }; 4B80214322EE7C3E00068002 /* JustInTime.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = JustInTime.hpp; sourceTree = ""; }; - 4B80ACFE1F85CAC900176895 /* BestEffortUpdater.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BestEffortUpdater.cpp; path = ../../Concurrency/BestEffortUpdater.cpp; sourceTree = ""; }; - 4B80ACFF1F85CACA00176895 /* BestEffortUpdater.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = BestEffortUpdater.hpp; path = ../../Concurrency/BestEffortUpdater.hpp; sourceTree = ""; }; 4B8334811F5D9FF70097E338 /* PartialMachineCycle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PartialMachineCycle.cpp; sourceTree = ""; }; 4B8334831F5DA0360097E338 /* Z80Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Z80Storage.cpp; sourceTree = ""; }; 4B8334851F5DA3780097E338 /* 6502Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6502Storage.cpp; sourceTree = ""; }; @@ -2219,8 +2215,6 @@ children = ( 4B3940E51DA83C8300427841 /* AsyncTaskQueue.cpp */, 4B3940E61DA83C8300427841 /* AsyncTaskQueue.hpp */, - 4B80ACFE1F85CAC900176895 /* BestEffortUpdater.cpp */, - 4B80ACFF1F85CACA00176895 /* BestEffortUpdater.hpp */, ); name = Concurrency; sourceTree = ""; @@ -4410,7 +4404,6 @@ 4B055AC31FAE9AE80060FFFF /* AmstradCPC.cpp in Sources */, 4B055A9E1FAE85DA0060FFFF /* G64.cpp in Sources */, 4B055AB81FAE860F0060FFFF /* ZX80O81P.cpp in Sources */, - 4B055A8E1FAE85920060FFFF /* BestEffortUpdater.cpp in Sources */, 4B055AB01FAE86070060FFFF /* PulseQueuedTape.cpp in Sources */, 4B055AAC1FAE85FD0060FFFF /* PCMSegment.cpp in Sources */, 4BB307BC235001C300457D33 /* 6850.cpp in Sources */, @@ -4663,7 +4656,6 @@ 4B4518821F75E91A00926311 /* PCMSegment.cpp in Sources */, 4B74CF812312FA9C00500CE8 /* HFV.cpp in Sources */, 4B17B58B20A8A9D9007CCA8F /* StringSerialiser.cpp in Sources */, - 4B80AD001F85CACA00176895 /* BestEffortUpdater.cpp in Sources */, 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */, 4B3940E71DA83C8300427841 /* AsyncTaskQueue.cpp in Sources */, 4B0E04FA1FC9FA3100F43484 /* 9918.cpp in Sources */,