Fix startup race in example#315
Open
xyzconstant wants to merge 2 commits into
Open
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline and AI policy for information on the review process.
If your review is incorrectly listed, please copy-paste |
xyzconstant
force-pushed
the
fix-race-in-mpexample
branch
from
July 22, 2026 03:59
b031c1f to
ff9f84c
Compare
Contributor
Author
|
failed CI job seems unrelated |
Since bitcoin-core#274, connection setup has been split into two calls: `MakeStream` followed by `ConnectStream`. Between these calls, the event loop's reference count can temporarily drop to zero, allowing `EventLoop::loop()` to exit before `ConnectStream` posts its work, crashing the example on startup. Keep an `EventLoopRef` alive in main() so the loop stays running while it is in use.
`EventLoop::loop()` exits when the last `EventLoopRef` is released, so code making multiple calls against the loop needs to hold its own reference. State this in the `EventLoopRef` comment and usage.md.
xyzconstant
force-pushed
the
fix-race-in-mpexample
branch
from
July 22, 2026 04:19
ff9f84c to
f2fabf6
Compare
allibmb1997-collab
approved these changes
Jul 22, 2026
allibmb1997-collab
approved these changes
Jul 22, 2026
ViniciusCestarii
left a comment
Contributor
There was a problem hiding this comment.
tACK f2fabf6 nice catch! I was able to reproduce on linux and it also intermittently fails without this fix. I liked the doc explanation too.
nit: a more surgical fix for against against master could look like:
+#include "mp/proxy.h"
#include <init.capnp.h>
#include <init.capnp.proxy.h>
int main(int argc, char** argv)
loop.loop();
});
mp::EventLoop* loop = promise.get_future().get();
+ mp::EventLoopRef loop_ref{*loop};
auto [printer_init, printer_pid] = Spawn(*loop, argv[0], "mpprinter");
auto [calc_init, calc_pid] = Spawn(*loop, argv[0], "mpcalculator");
int main(int argc, char** argv)
mp::WaitProcess(calc_pid);
printer_init.reset();
mp::WaitProcess(printer_pid);
+ loop_ref.reset();
loop_thread.join();
std::cout << "Bye!" << std::endl;
return 0;
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Since #274, connection setup has been split into two calls:
MakeStreamfollowed byConnectStream. Between these calls, the event loop's reference count can temporarily drop to zero, allowingEventLoop::loop()to exit (and the EventLoop to be destroyed) beforeConnectStreamposts its work. This crashes mpexample on startup.Fix this by keeping an
EventLoopRefalive in main() so the loop stays running while it is in use. This same pattern is already used in Bitcoin Core (m_loop_refmember ofCapnpProtocol).A second commit documents the reference-counted EventLoop lifetime in the
EventLoopRefclass comment and indoc/usage.md.NOTE: On macOS, mpexample was crashing intermittently on startup (sometimes failing the m_post_fn == nullptr assert in the EventLoop destructor, sometimes with a mutex lock failure), depending on timing. With this change, the crashes are gone.