From 49309b419f47d7acd4ba3ab2c6d1923df875587f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 20 Jan 2020 13:28:58 +0100 Subject: [PATCH] Partition: add a local idle_monitor Make idle events per-partition, but leave Instance::EmitIdle() and its underlying idle_monitor which broadcasts idle events to all partitions. --- src/Instance.cxx | 9 +++------ src/Instance.hxx | 4 ++++ src/Partition.cxx | 19 +++++++++++++------ src/Partition.hxx | 15 ++++++++++++--- src/client/List.cxx | 9 --------- src/client/List.hxx | 2 -- 6 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/Instance.cxx b/src/Instance.cxx index fd2bbac55..bcb8502f9 100644 --- a/src/Instance.cxx +++ b/src/Instance.cxx @@ -180,10 +180,7 @@ Instance::OnRemoteTag(const char *uri, const Tag &tag) noexcept void Instance::OnIdle(unsigned flags) noexcept { - /* send "idle" notifications to all subscribed - clients */ - client_list->IdleAdd(flags); - - if (flags & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT)) - OnStateModified(); + /* broadcast to all partitions */ + for (auto &partition : partitions) + partition.EmitIdle(flags); } diff --git a/src/Instance.hxx b/src/Instance.hxx index dec733630..2b72c4521 100644 --- a/src/Instance.hxx +++ b/src/Instance.hxx @@ -101,6 +101,10 @@ struct Instance final std::unique_ptr input_cache; + /** + * Monitor for global idle events to be broadcasted to all + * partitions. + */ MaskMonitor idle_monitor; #ifdef ENABLE_NEIGHBOR_PLUGINS diff --git a/src/Partition.cxx b/src/Partition.cxx index 2e8525a75..36dcf4c3c 100644 --- a/src/Partition.cxx +++ b/src/Partition.cxx @@ -40,6 +40,7 @@ Partition::Partition(Instance &_instance, :instance(_instance), name(_name), listener(new ClientListener(instance.event_loop, *this)), + idle_monitor(instance.event_loop, BIND_THIS_METHOD(OnIdleMonitor)), global_events(instance.event_loop, BIND_THIS_METHOD(OnGlobalEvent)), playlist(max_length, *this), outputs(*this), @@ -60,12 +61,6 @@ Partition::BeginShutdown() noexcept listener.reset(); } -void -Partition::EmitIdle(unsigned mask) noexcept -{ - instance.EmitIdle(mask); -} - static void PrefetchSong(InputCacheManager &cache, const char *uri) noexcept { @@ -215,6 +210,18 @@ Partition::OnMixerVolumeChanged(Mixer &, int) noexcept EmitIdle(IDLE_MIXER); } +void +Partition::OnIdleMonitor(unsigned mask) noexcept +{ + /* send "idle" notifications to all subscribed + clients */ + for (auto &client : clients) + client.IdleAdd(mask); + + if (mask & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT)) + instance.OnStateModified(); +} + void Partition::OnGlobalEvent(unsigned mask) noexcept { diff --git a/src/Partition.hxx b/src/Partition.hxx index 3ee2702ca..794ab01ef 100644 --- a/src/Partition.hxx +++ b/src/Partition.hxx @@ -63,6 +63,11 @@ struct Partition final : QueueListener, PlayerListener, MixerListener { boost::intrusive::link_mode>>, boost::intrusive::constant_time_size> clients; + /** + * Monitor for idle events local to this partition. + */ + MaskMonitor idle_monitor; + MaskMonitor global_events; struct playlist playlist; @@ -91,10 +96,11 @@ struct Partition final : QueueListener, PlayerListener, MixerListener { /** * Emit an "idle" event to all clients of this partition. * - * This method is not thread-safe and may only be called from - * the main thread. + * This method can be called from any thread. */ - void EmitIdle(unsigned mask) noexcept; + void EmitIdle(unsigned mask) noexcept { + idle_monitor.OrMask(mask); + } /** * Populate the #InputCacheManager with soon-to-be-played song @@ -282,6 +288,9 @@ private: /* virtual methods from class MixerListener */ void OnMixerVolumeChanged(Mixer &mixer, int volume) noexcept override; + /* callback for #idle_monitor */ + void OnIdleMonitor(unsigned mask) noexcept; + /* callback for #global_events */ void OnGlobalEvent(unsigned mask) noexcept; }; diff --git a/src/client/List.cxx b/src/client/List.cxx index 64fcd4c47..bc1f60487 100644 --- a/src/client/List.cxx +++ b/src/client/List.cxx @@ -34,12 +34,3 @@ ClientList::Remove(Client &client) noexcept list.erase(list.iterator_to(client)); } - -void -ClientList::IdleAdd(unsigned flags) noexcept -{ - assert(flags != 0); - - for (auto &client : list) - client.IdleAdd(flags); -} diff --git a/src/client/List.hxx b/src/client/List.hxx index f62322d33..d82ec889f 100644 --- a/src/client/List.hxx +++ b/src/client/List.hxx @@ -56,8 +56,6 @@ public: } void Remove(Client &client) noexcept; - - void IdleAdd(unsigned flags) noexcept; }; #endif