@@ -222,7 +222,8 @@ class SessionWrapper final : public util::AtomicRefCountBase, DB::CommitListener
222222
223223 bool m_suspended = false ;
224224
225- // Set when the session has been abandoned, but before it's been finalized.
225+ // Set when the session has been abandoned. After this point none of the
226+ // public API functions should be called again.
226227 bool m_abandoned = false ;
227228 // Has the SessionWrapper been finalized?
228229 bool m_finalized = false ;
@@ -439,7 +440,7 @@ bool ClientImpl::wait_for_session_terminations_or_client_stopped()
439440 // Thread safety required
440441
441442 {
442- std::lock_guard lock{m_mutex};
443+ util::CheckedLockGuard lock{m_mutex};
443444 m_sessions_terminated = false ;
444445 }
445446
@@ -466,16 +467,19 @@ bool ClientImpl::wait_for_session_terminations_or_client_stopped()
466467 else if (!status.is_ok ())
467468 throw Exception (status);
468469
469- std::lock_guard lock{m_mutex};
470- m_sessions_terminated = true ;
470+ {
471+ util::CheckedLockGuard lock{m_mutex};
472+ m_sessions_terminated = true ;
473+ }
471474 m_wait_or_client_stopped_cond.notify_all ();
472475 }); // Throws
473476
474477 bool completion_condition_was_satisfied;
475478 {
476- std::unique_lock lock{m_mutex};
477- while (!m_sessions_terminated && !m_stopped)
478- m_wait_or_client_stopped_cond.wait (lock);
479+ util::CheckedUniqueLock lock{m_mutex};
480+ m_wait_or_client_stopped_cond.wait (lock.native_handle (), [&]() REQUIRES (m_mutex) {
481+ return m_sessions_terminated || m_stopped;
482+ });
479483 completion_condition_was_satisfied = !m_stopped;
480484 }
481485 return completion_condition_was_satisfied;
@@ -510,13 +514,13 @@ void ClientImpl::drain_connections_on_loop()
510514void ClientImpl::shutdown_and_wait ()
511515{
512516 shutdown ();
513- std::unique_lock lock{m_drain_mutex};
517+ util::CheckedUniqueLock lock{m_drain_mutex};
514518 if (m_drained) {
515519 return ;
516520 }
517521
518522 logger.debug (" Waiting for %1 connections to drain" , m_num_connections);
519- m_drain_cv.wait (lock, [&] {
523+ m_drain_cv.wait (lock. native_handle () , [&]() REQUIRES (m_drain_mutex) {
520524 return m_num_connections == 0 && m_outstanding_posts == 0 ;
521525 });
522526
@@ -526,12 +530,12 @@ void ClientImpl::shutdown_and_wait()
526530void ClientImpl::shutdown () noexcept
527531{
528532 {
529- std::lock_guard lock{m_mutex};
533+ util::CheckedLockGuard lock{m_mutex};
530534 if (m_stopped)
531535 return ;
532536 m_stopped = true ;
533- m_wait_or_client_stopped_cond.notify_all ();
534537 }
538+ m_wait_or_client_stopped_cond.notify_all ();
535539
536540 drain_connections_on_loop ();
537541}
@@ -541,7 +545,7 @@ void ClientImpl::register_unactualized_session_wrapper(SessionWrapper* wrapper,
541545{
542546 // Thread safety required.
543547 {
544- std::lock_guard lock{m_mutex};
548+ util::CheckedLockGuard lock{m_mutex};
545549 REALM_ASSERT (m_actualize_and_finalize);
546550 wrapper->mark_initiated ();
547551 m_unactualized_session_wrappers.emplace (wrapper, std::move (endpoint)); // Throws
@@ -554,7 +558,7 @@ void ClientImpl::register_abandoned_session_wrapper(util::bind_ptr<SessionWrappe
554558{
555559 // Thread safety required.
556560 {
557- std::lock_guard lock{m_mutex};
561+ util::CheckedLockGuard lock{m_mutex};
558562 REALM_ASSERT (m_actualize_and_finalize);
559563 wrapper->mark_abandoned ();
560564
@@ -581,7 +585,7 @@ void ClientImpl::actualize_and_finalize_session_wrappers()
581585 SessionWrapperStack abandoned_session_wrappers;
582586 bool stopped;
583587 {
584- std::lock_guard lock{m_mutex};
588+ util::CheckedLockGuard lock{m_mutex};
585589 swap (m_unactualized_session_wrappers, unactualized_session_wrappers);
586590 swap (m_abandoned_session_wrappers, abandoned_session_wrappers);
587591 stopped = m_stopped;
@@ -643,7 +647,7 @@ ClientImpl::Connection& ClientImpl::get_connection(ServerEndpoint endpoint,
643647 m_prev_connection_ident = ident;
644648 was_created = true ;
645649 {
646- std::lock_guard lk (m_drain_mutex);
650+ util::CheckedLockGuard lk (m_drain_mutex);
647651 ++m_num_connections;
648652 }
649653 return conn;
@@ -671,10 +675,13 @@ void ClientImpl::remove_connection(ClientImpl::Connection& conn) noexcept
671675 server_slot.alt_connections .erase (j);
672676 }
673677
678+ bool notify;
674679 {
675- std::lock_guard lk (m_drain_mutex);
680+ util::CheckedLockGuard lk (m_drain_mutex);
676681 REALM_ASSERT (m_num_connections);
677- --m_num_connections;
682+ notify = --m_num_connections <= 0 ;
683+ }
684+ if (notify) {
678685 m_drain_cv.notify_all ();
679686 }
680687}
@@ -1480,7 +1487,7 @@ bool SessionWrapper::wait_for_upload_complete_or_client_stopped()
14801487
14811488 std::int_fast64_t target_mark;
14821489 {
1483- std::lock_guard lock{m_client.m_mutex };
1490+ util::CheckedLockGuard lock{m_client.m_mutex };
14841491 target_mark = ++m_target_upload_mark;
14851492 }
14861493
@@ -1508,9 +1515,10 @@ bool SessionWrapper::wait_for_upload_complete_or_client_stopped()
15081515
15091516 bool completion_condition_was_satisfied;
15101517 {
1511- std::unique_lock lock{m_client.m_mutex };
1512- while (m_reached_upload_mark < target_mark && !m_client.m_stopped )
1513- m_client.m_wait_or_client_stopped_cond .wait (lock);
1518+ util::CheckedUniqueLock lock{m_client.m_mutex };
1519+ m_client.m_wait_or_client_stopped_cond .wait (lock.native_handle (), [&]() REQUIRES (m_client.m_mutex ) {
1520+ return m_reached_upload_mark >= target_mark || m_client.m_stopped ;
1521+ });
15141522 completion_condition_was_satisfied = !m_client.m_stopped ;
15151523 }
15161524 return completion_condition_was_satisfied;
@@ -1525,7 +1533,7 @@ bool SessionWrapper::wait_for_download_complete_or_client_stopped()
15251533
15261534 std::int_fast64_t target_mark;
15271535 {
1528- std::lock_guard lock{m_client.m_mutex };
1536+ util::CheckedLockGuard lock{m_client.m_mutex };
15291537 target_mark = ++m_target_download_mark;
15301538 }
15311539
@@ -1553,9 +1561,10 @@ bool SessionWrapper::wait_for_download_complete_or_client_stopped()
15531561
15541562 bool completion_condition_was_satisfied;
15551563 {
1556- std::unique_lock lock{m_client.m_mutex };
1557- while (m_reached_download_mark < target_mark && !m_client.m_stopped )
1558- m_client.m_wait_or_client_stopped_cond .wait (lock);
1564+ util::CheckedUniqueLock lock{m_client.m_mutex };
1565+ m_client.m_wait_or_client_stopped_cond .wait (lock.native_handle (), [&]() REQUIRES (m_client.m_mutex ) {
1566+ return m_reached_download_mark >= target_mark || m_client.m_stopped ;
1567+ });
15591568 completion_condition_was_satisfied = !m_client.m_stopped ;
15601569 }
15611570 return completion_condition_was_satisfied;
@@ -1688,6 +1697,10 @@ void SessionWrapper::force_close()
16881697}
16891698
16901699// Must be called from event loop thread
1700+ //
1701+ // `m_client.m_mutex` is not held while this is called, but it is guaranteed to
1702+ // have been acquired at some point in between the final read or write ever made
1703+ // from a different thread and when this is called.
16911704void SessionWrapper::finalize ()
16921705{
16931706 REALM_ASSERT (m_actualized);
@@ -1780,7 +1793,7 @@ void SessionWrapper::on_upload_completion()
17801793 m_download_completion_handlers.push_back (std::move (handler)); // Throws
17811794 m_sync_completion_handlers.pop_back ();
17821795 }
1783- std::lock_guard lock{m_client.m_mutex };
1796+ util::CheckedLockGuard lock{m_client.m_mutex };
17841797 if (m_staged_upload_mark > m_reached_upload_mark) {
17851798 m_reached_upload_mark = m_staged_upload_mark;
17861799 m_client.m_wait_or_client_stopped_cond .notify_all ();
@@ -1808,7 +1821,7 @@ void SessionWrapper::on_download_completion()
18081821 m_flx_pending_mark_version = SubscriptionSet::EmptyVersion;
18091822 }
18101823
1811- std::lock_guard lock{m_client.m_mutex };
1824+ util::CheckedLockGuard lock{m_client.m_mutex };
18121825 if (m_staged_download_mark > m_reached_download_mark) {
18131826 m_reached_download_mark = m_staged_download_mark;
18141827 m_client.m_wait_or_client_stopped_cond .notify_all ();
0 commit comments