Skip to content

Commit caf01fa

Browse files
committed
Merge #130: refactor: Add CleanupRun function to dedup clean list code
700085f refactor: Add CleanupRun function to dedup clean list code (Ryan Ofsky) Pull request description: Add CleanupRun function to dedup clean list code. Also rename "cleanup" variables to distinguish between cleanup iterators and cleanup callback functions. These changes were originally part of #126 which was closed for other reasons, but I think they are still helpful and make code easier to navigate. Since this renames a public struct member, it will require a change to bitcoin core when the depends version is bumped: ```c++ diff --git a/src/ipc/capnp/protocol.cpp b/src/ipc/capnp/protocol.cpp index 4b67a5bd1e36..691bdf5f9242 100644 --- a/src/ipc/capnp/protocol.cpp +++ b/src/ipc/capnp/protocol.cpp @@ -73,7 +73,7 @@ public: } void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override { - mp::ProxyTypeRegister::types().at(type)(iface).cleanup.emplace_back(std::move(cleanup)); + mp::ProxyTypeRegister::types().at(type)(iface).cleanup_fns.emplace_back(std::move(cleanup)); } Context& context() override { return m_context; } void startLoop(const char* exe_name) ``` Top commit has no ACKs. Tree-SHA512: 04ca403f80ddc2d0bf6ba5b0aa5cee651f0c509dcf67137789c744a1ae63bed32a4e34510ba21f2ed9797c46ace640b49e2db67659e03ea4ad2cca18491cabef
2 parents 72f6669 + 700085f commit caf01fa

File tree

4 files changed

+33
-29
lines changed

4 files changed

+33
-29
lines changed

include/mp/proxy-io.h

+11-18
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,16 @@ struct ProxyClient<Thread> : public ProxyClientBase<Thread, ::capnp::Void>
6363
ProxyClient(const ProxyClient&) = delete;
6464
~ProxyClient();
6565

66-
void setCleanup(std::function<void()> cleanup);
66+
void setCleanup(std::function<void()> fn);
6767

6868
//! Cleanup function to run when the connection is closed. If the Connection
6969
//! gets destroyed before this ProxyClient<Thread> object, this cleanup
7070
//! callback lets it destroy this object and remove its entry in the
7171
//! thread's request_threads or callback_threads map (after resetting
72-
//! m_cleanup so the destructor does not try to access it). But if this
72+
//! m_cleanup_it so the destructor does not try to access it). But if this
7373
//! object gets destroyed before the Connection, there's no need to run the
7474
//! cleanup function and the destructor will unregister it.
75-
std::optional<CleanupIt> m_cleanup;
75+
std::optional<CleanupIt> m_cleanup_it;
7676
};
7777

7878
template <>
@@ -381,7 +381,7 @@ ProxyClientBase<Interface, Impl>::ProxyClientBase(typename Interface::Client cli
381381
}
382382

383383
// Handler for the connection getting destroyed before this client object.
384-
auto cleanup = m_context.connection->addSyncCleanup([this]() {
384+
auto cleanup_it = m_context.connection->addSyncCleanup([this]() {
385385
// Release client capability by move-assigning to temporary.
386386
{
387387
typename Interface::Client(std::move(m_client));
@@ -404,11 +404,11 @@ ProxyClientBase<Interface, Impl>::ProxyClientBase(typename Interface::Client cli
404404
// The first case is handled here when m_context.connection is not null. The
405405
// second case is handled by the cleanup function, which sets m_context.connection to
406406
// null so nothing happens here.
407-
m_context.cleanup.emplace_front([this, destroy_connection, cleanup]{
407+
m_context.cleanup_fns.emplace_front([this, destroy_connection, cleanup_it]{
408408
if (m_context.connection) {
409409
// Remove cleanup callback so it doesn't run and try to access
410410
// this object after it's already destroyed.
411-
m_context.connection->removeSyncCleanup(cleanup);
411+
m_context.connection->removeSyncCleanup(cleanup_it);
412412

413413
// If the capnp interface defines a destroy method, call it to destroy
414414
// the remote object, waiting for it to be deleted server side. If the
@@ -440,9 +440,7 @@ ProxyClientBase<Interface, Impl>::ProxyClientBase(typename Interface::Client cli
440440
template <typename Interface, typename Impl>
441441
ProxyClientBase<Interface, Impl>::~ProxyClientBase() noexcept
442442
{
443-
for (auto& cleanup : m_context.cleanup) {
444-
cleanup();
445-
}
443+
CleanupRun(m_context.cleanup_fns);
446444
}
447445

448446
template <typename Interface, typename Impl>
@@ -479,14 +477,12 @@ ProxyServerBase<Interface, Impl>::~ProxyServerBase()
479477
// connection is broken). Probably some refactoring of the destructor
480478
// and invokeDestroy function is possible to make this cleaner and more
481479
// consistent.
482-
m_context.connection->addAsyncCleanup([impl=std::move(m_impl), c=std::move(m_context.cleanup)]() mutable {
480+
m_context.connection->addAsyncCleanup([impl=std::move(m_impl), fns=std::move(m_context.cleanup_fns)]() mutable {
483481
impl.reset();
484-
for (auto& cleanup : c) {
485-
cleanup();
486-
}
482+
CleanupRun(fns);
487483
});
488484
}
489-
assert(m_context.cleanup.size() == 0);
485+
assert(m_context.cleanup_fns.size() == 0);
490486
std::unique_lock<std::mutex> lock(m_context.connection->m_loop.m_mutex);
491487
m_context.connection->m_loop.removeClient(lock);
492488
}
@@ -512,10 +508,7 @@ template <typename Interface, typename Impl>
512508
void ProxyServerBase<Interface, Impl>::invokeDestroy()
513509
{
514510
m_impl.reset();
515-
for (auto& cleanup : m_context.cleanup) {
516-
cleanup();
517-
}
518-
m_context.cleanup.clear();
511+
CleanupRun(m_context.cleanup_fns);
519512
}
520513

521514
using ConnThreads = std::map<Connection*, ProxyClient<Thread>>;

include/mp/proxy.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,19 @@ struct ProxyType;
3939
using CleanupList = std::list<std::function<void()>>;
4040
using CleanupIt = typename CleanupList::iterator;
4141

42+
inline void CleanupRun(CleanupList& fns) {
43+
while (!fns.empty()) {
44+
auto fn = std::move(fns.front());
45+
fns.pop_front();
46+
fn();
47+
}
48+
}
49+
4250
//! Context data associated with proxy client and server classes.
4351
struct ProxyContext
4452
{
4553
Connection* connection;
46-
std::list<std::function<void()>> cleanup;
54+
CleanupList cleanup_fns;
4755

4856
ProxyContext(Connection* connection) : connection(connection) {}
4957
};
@@ -147,7 +155,7 @@ struct ProxyServerBase : public virtual Interface_::Server
147155
//! state can be destroyed without blocking, because ProxyServer destructors are
148156
//! called from the EventLoop thread, and if they block, it could deadlock the
149157
//! program. One way to do avoid blocking is to clean up the state by pushing
150-
//! cleanup callbacks to the m_context.cleanup list, which run after the server
158+
//! cleanup callbacks to the m_context.cleanup_fns list, which run after the server
151159
//! m_impl object is destroyed on the same thread destroying it (which will
152160
//! either be an IPC worker thread if the ProxyServer is being explicitly
153161
//! destroyed by a client calling a destroy() method with a Context argument and

src/mp/proxy.cpp

+11-8
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,9 @@ std::tuple<ConnThread, bool> SetThread(ConnThreads& threads, std::mutex& mutex,
294294
// destructor unregisters the cleanup.
295295

296296
// Connection is being destroyed before thread client is, so reset
297-
// thread client m_cleanup member so thread client destructor does not
297+
// thread client m_cleanup_it member so thread client destructor does not
298298
// try unregister this callback after connection is destroyed.
299-
thread->second.m_cleanup.reset();
299+
thread->second.m_cleanup_it.reset();
300300
// Remove connection pointer about to be destroyed from the map
301301
std::unique_lock<std::mutex> lock(mutex);
302302
threads.erase(thread);
@@ -306,16 +306,19 @@ std::tuple<ConnThread, bool> SetThread(ConnThreads& threads, std::mutex& mutex,
306306

307307
ProxyClient<Thread>::~ProxyClient()
308308
{
309-
if (m_cleanup) {
310-
m_context.connection->removeSyncCleanup(*m_cleanup);
309+
// If thread is being destroyed before connection is destroyed, remove the
310+
// cleanup callback that was registered to handle the connection being
311+
// destroyed before the thread being destroyed.
312+
if (m_cleanup_it) {
313+
m_context.connection->removeSyncCleanup(*m_cleanup_it);
311314
}
312315
}
313316

314-
void ProxyClient<Thread>::setCleanup(std::function<void()> cleanup)
317+
void ProxyClient<Thread>::setCleanup(std::function<void()> fn)
315318
{
316-
assert(cleanup);
317-
assert(!m_cleanup);
318-
m_cleanup = m_context.connection->addSyncCleanup(cleanup);
319+
assert(fn);
320+
assert(!m_cleanup_it);
321+
m_cleanup_it = m_context.connection->addSyncCleanup(fn);
319322
}
320323

321324
ProxyServer<Thread>::ProxyServer(ThreadContext& thread_context, std::thread&& thread)

test/mp/test/test.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ KJ_TEST("Call FooInterface methods")
122122
thread.join();
123123

124124
bool destroyed = false;
125-
foo->m_context.cleanup.emplace_front([&destroyed]{ destroyed = true; });
125+
foo->m_context.cleanup_fns.emplace_front([&destroyed]{ destroyed = true; });
126126
foo.reset();
127127
KJ_EXPECT(destroyed);
128128
}

0 commit comments

Comments
 (0)