Skip to content

Commit

Permalink
Ensure scheduler is not deleted until callback has been done
Browse files Browse the repository at this point in the history
This is fixing a problem introduced in 14210d1

The issue was discovered in realm-js, where async open would
hang because the scheduler was deleted before the callback was done on the
main thread. Beforehand the EventLoopDispatcher has a State member that
would retain the scheduler until the invocations were done.
  • Loading branch information
jedelbo committed Mar 4, 2022
1 parent 2879c7b commit 19420d5
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Wrong error code returned from C-API on MacOS ([#5233](https://github.com/realm/realm-core/issues/5233), since v10.0.0)
* Mixed::compare() used inconsistent rounding for comparing a Decimal128 to a float, giving different results from comparing those values directly ([#5270](https://github.com/realm/realm-core/pull/5270)).
* Calling Realm::async_begin_transaction() from within a write transaction while the async state was idle would hit an assertion failure (since v11.10.0).
* Fix issue with scheduler being deleted on wrong thread. This caused async open to hang in eg. realm-js. ([#5287](https://github.com/realm/realm-core/pull/5287), Since v11.10.0)

### Breaking changes
* None.
Expand Down
9 changes: 6 additions & 3 deletions src/realm/object-store/util/event_loop_dispatcher.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@ class EventLoopDispatcher<void(Args...)> {
(*m_func)(std::forward<Args>(args)...);
return;
}
m_scheduler->invoke([func = m_func, args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
std::apply(*func, std::move(args));
});
m_scheduler->invoke(
[scheduler = m_scheduler, func = m_func, args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
std::apply(*func, std::move(args));
// Each invocation block will retain the scheduler, so the scheduler
// will not be released until all blocks are called
});
}
};

Expand Down
10 changes: 5 additions & 5 deletions test/object-store/realm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <realm/object-store/schema.hpp>
#include <realm/object-store/thread_safe_reference.hpp>
#include <realm/object-store/util/scheduler.hpp>
#include <realm/object-store/util/event_loop_dispatcher.hpp>

#if REALM_ENABLE_SYNC
#include <realm/object-store/sync/async_open_task.hpp>
Expand Down Expand Up @@ -616,16 +617,15 @@ TEST_CASE("Get Realm using Async Open", "[asyncOpen]") {
std::mutex mutex;
SECTION("can open synced Realms that don't already exist") {
ThreadSafeReference realm_ref;
std::atomic<bool> called{false};
bool called = false;
auto task = Realm::get_synchronized_realm(config);
task->start([&](auto ref, auto error) {
std::lock_guard<std::mutex> lock(mutex);
task->start(realm::util::EventLoopDispatcher([&](ThreadSafeReference&& ref, std::exception_ptr error) {
REQUIRE(!error);
called = true;
realm_ref = std::move(ref);
});
}));
util::EventLoop::main().run_until([&] {
return called.load();
return called;
});
std::lock_guard<std::mutex> lock(mutex);
REQUIRE(called);
Expand Down

0 comments on commit 19420d5

Please sign in to comment.