diff --git a/Outputs/ScanTargets/BufferingScanTarget.cpp b/Outputs/ScanTargets/BufferingScanTarget.cpp index 1f977c06e..40577a975 100644 --- a/Outputs/ScanTargets/BufferingScanTarget.cpp +++ b/Outputs/ScanTargets/BufferingScanTarget.cpp @@ -33,7 +33,7 @@ uint8_t *BufferingScanTarget::begin_data(size_t required_length, size_t required assert(required_alignment); // Acquire the standard producer lock, nominally over write_pointers_. - std::lock_guard lock_guard(write_pointers_mutex_); + std::lock_guard lock_guard(producer_mutex_); // If allocation has already failed on this line, continue the trend. if(allocation_has_failed_) return nullptr; @@ -85,7 +85,7 @@ uint8_t *BufferingScanTarget::begin_data(size_t required_length, size_t required void BufferingScanTarget::end_data(size_t actual_length) { // Acquire the producer lock. - std::lock_guard lock_guard(write_pointers_mutex_); + std::lock_guard lock_guard(producer_mutex_); // Do nothing if no data write is actually ongoing. if(allocation_has_failed_ || !data_is_allocated_) return; @@ -117,7 +117,7 @@ void BufferingScanTarget::end_data(size_t actual_length) { // MARK: - Producer; scans. Outputs::Display::ScanTarget::Scan *BufferingScanTarget::begin_scan() { - std::lock_guard lock_guard(write_pointers_mutex_); + std::lock_guard lock_guard(producer_mutex_); // If there's already an allocation failure on this line, do no work. if(allocation_has_failed_) { @@ -148,7 +148,7 @@ Outputs::Display::ScanTarget::Scan *BufferingScanTarget::begin_scan() { } void BufferingScanTarget::end_scan() { - std::lock_guard lock_guard(write_pointers_mutex_); + std::lock_guard lock_guard(producer_mutex_); // Complete the scan only if one is afoot. if(vended_scan_) { @@ -174,7 +174,7 @@ void BufferingScanTarget::end_scan() { // MARK: - Producer; lines. void BufferingScanTarget::announce(Event event, bool is_visible, const Outputs::Display::ScanTarget::Scan::EndPoint &location, uint8_t composite_amplitude) { - std::lock_guard lock_guard(write_pointers_mutex_); + std::lock_guard lock_guard(producer_mutex_); // Forward the event to the display metrics tracker. display_metrics_.announce_event(event); @@ -277,7 +277,7 @@ const Outputs::Display::Metrics &BufferingScanTarget::display_metrics() { } void BufferingScanTarget::set_write_area(uint8_t *base) { - std::lock_guard lock_guard(write_pointers_mutex_); + std::lock_guard lock_guard(producer_mutex_); write_area_ = base; data_type_size_ = Outputs::Display::size_for_data_type(modals_.input_data_type); write_pointers_ = submit_pointers_ = read_pointers_ = PointerSet(); diff --git a/Outputs/ScanTargets/BufferingScanTarget.hpp b/Outputs/ScanTargets/BufferingScanTarget.hpp index ef6eeba1e..8fd8c5d70 100644 --- a/Outputs/ScanTargets/BufferingScanTarget.hpp +++ b/Outputs/ScanTargets/BufferingScanTarget.hpp @@ -201,10 +201,13 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget { /// This is used as a spinlock to guard `perform` calls. std::atomic_flag is_updating_; - /// A mutex for gettng access to write_pointers_; access to write_pointers_, - /// data_type_size_ or write_area_texture_ is almost never contended, so this - /// is cheap for the main use case. - std::mutex write_pointers_mutex_; + /// A mutex for gettng access to anything the producer modifies — i.e. the write_pointers_, + /// data_type_size_ and write_area_texture_, and all other state to do with capturing + /// data, scans and lines. + /// + /// This is almost never contended. The main collision is a user-prompted change of modals while the + /// emulation thread is running. + std::mutex producer_mutex_; /// A pointer to the next thing that should be provided to the caller for data. PointerSet write_pointers_;