diff options
author | Max Kellermann <max@duempel.org> | 2014-11-25 10:42:52 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-11-25 13:31:18 +0100 |
commit | 3cef348f30ad8a018b1c46f257d3e719be3f96b0 (patch) | |
tree | 707c23f63f63838a5f7b4f895ae260a4e8bda48c /src/lib/nfs/Manager.hxx | |
parent | b293b160079fd19cfc675fa86c2b99695aac171f (diff) | |
download | mpd-3cef348f30ad8a018b1c46f257d3e719be3f96b0.tar.gz mpd-3cef348f30ad8a018b1c46f257d3e719be3f96b0.tar.xz mpd-3cef348f30ad8a018b1c46f257d3e719be3f96b0.zip |
lib/nfs/Manager: defer NfsConnection destruction
Avoids a crash that occurs when NfsConnection::OnSocketReady()
dereferences itself before returning.
Diffstat (limited to 'src/lib/nfs/Manager.hxx')
-rw-r--r-- | src/lib/nfs/Manager.hxx | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx index 612b01f9c..130c81aca 100644 --- a/src/lib/nfs/Manager.hxx +++ b/src/lib/nfs/Manager.hxx @@ -23,14 +23,16 @@ #include "check.h" #include "Connection.hxx" #include "Compiler.h" +#include "event/IdleMonitor.hxx" #include <boost/intrusive/set.hpp> +#include <boost/intrusive/slist.hpp> /** * A manager for NFS connections. Handles multiple connections to * multiple NFS servers. */ -class NfsManager { +class NfsManager final : IdleMonitor { struct LookupKey { const char *server; const char *export_name; @@ -38,6 +40,7 @@ class NfsManager { class ManagedConnection final : public NfsConnection, + public boost::intrusive::slist_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>, public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> { NfsManager &manager; @@ -63,8 +66,6 @@ class NfsManager { const LookupKey b) const; }; - EventLoop &loop; - /** * Maps server and export_name to #ManagedConnection. */ @@ -74,9 +75,18 @@ class NfsManager { Map connections; + typedef boost::intrusive::slist<ManagedConnection> List; + + /** + * A list of "garbage" connection objects. Their destruction + * is postponed because they were thrown into the garbage list + * when callers on the stack were still using them. + */ + List garbage; + public: NfsManager(EventLoop &_loop) - :loop(_loop) {} + :IdleMonitor(_loop) {} /** * Must be run from EventLoop's thread. @@ -86,6 +96,21 @@ public: gcc_pure NfsConnection &GetConnection(const char *server, const char *export_name); + +private: + void ScheduleDelete(ManagedConnection &c) { + connections.erase(connections.iterator_to(c)); + garbage.push_front(c); + IdleMonitor::Schedule(); + } + + /** + * Delete all connections on the #garbage list. + */ + void CollectGarbage(); + + /* virtual methods from IdleMonitor */ + void OnIdle() override; }; #endif |