thread.hpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. /*************************************************************************
  2. *
  3. * Copyright 2016 Realm Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. **************************************************************************/
  18. #ifndef REALM_UTIL_THREAD_HPP
  19. #define REALM_UTIL_THREAD_HPP
  20. #include <exception>
  21. #ifdef _WIN32
  22. #include <thread>
  23. #include <condition_variable> // for windows non-interprocess condvars we use std::condition_variable
  24. #include <Windows.h>
  25. #include <process.h> // _getpid()
  26. #else
  27. #include <pthread.h>
  28. #endif
  29. // Use below line to enable a thread bug detection tool. Note: Will make program execution slower.
  30. // #include <../test/pthread_test.hpp>
  31. #include <cerrno>
  32. #include <cstddef>
  33. #include <string>
  34. #include <realm/util/features.h>
  35. #include <realm/util/assert.hpp>
  36. #include <realm/util/terminate.hpp>
  37. #include <memory>
  38. #include <stdexcept>
  39. #include <atomic>
  40. namespace realm {
  41. namespace util {
  42. /// A separate thread of execution.
  43. ///
  44. /// This class is a C++03 compatible reproduction of a subset of std::thread
  45. /// from C++11 (when discounting Thread::start(), Thread::set_name(), and
  46. /// Thread::get_name()).
  47. class Thread {
  48. public:
  49. Thread();
  50. ~Thread() noexcept;
  51. template <class F>
  52. explicit Thread(F func);
  53. // Disable copying. It is an error to copy this Thread class.
  54. Thread(const Thread&) = delete;
  55. Thread& operator=(const Thread&) = delete;
  56. Thread(Thread&&) noexcept;
  57. /// This method is an extension of the API provided by
  58. /// std::thread. This method exists because proper move semantics
  59. /// is unavailable in C++03. If move semantics had been available,
  60. /// calling `start(func)` would have been equivalent to `*this =
  61. /// Thread(func)`. Please see std::thread::operator=() for
  62. /// details.
  63. template <class F>
  64. void start(F func);
  65. bool joinable() noexcept;
  66. void join();
  67. // If supported by the platform, set the name of the calling thread (mainly
  68. // for debugging purposes). The name will be silently clamped to whatever
  69. // limit the platform places on these names. Linux places a limit of 15
  70. // characters for these names.
  71. static void set_name(const std::string&);
  72. // If supported by the platform, this function assigns the name of the
  73. // calling thread to \a name, and returns true, otherwise it does nothing
  74. // and returns false.
  75. static bool get_name(std::string& name) noexcept;
  76. private:
  77. #ifdef _WIN32
  78. std::thread m_std_thread;
  79. #else
  80. pthread_t m_id;
  81. #endif
  82. bool m_joinable;
  83. typedef void* (*entry_func_type)(void*);
  84. void start(entry_func_type, void* arg);
  85. template <class>
  86. static void* entry_point(void*) noexcept;
  87. REALM_NORETURN static void create_failed(int);
  88. REALM_NORETURN static void join_failed(int);
  89. };
  90. /// Low-level mutual exclusion device.
  91. class Mutex {
  92. public:
  93. Mutex();
  94. ~Mutex() noexcept;
  95. struct process_shared_tag {
  96. };
  97. /// Initialize this mutex for use across multiple processes. When
  98. /// constructed this way, the instance may be placed in memory
  99. /// shared by multiple processes, as well as in a memory mapped
  100. /// file. Such a mutex remains valid even after the constructing
  101. /// process terminates. Deleting the instance (freeing the memory
  102. /// or deleting the file) without first calling the destructor is
  103. /// legal and will not cause any system resources to be leaked.
  104. Mutex(process_shared_tag);
  105. // Disable copying.
  106. Mutex(const Mutex&) = delete;
  107. Mutex& operator=(const Mutex&) = delete;
  108. friend class LockGuard;
  109. friend class UniqueLock;
  110. friend class InterprocessCondVar;
  111. void lock() noexcept;
  112. bool try_lock() noexcept;
  113. void unlock() noexcept;
  114. protected:
  115. #ifdef _WIN32
  116. // Used for non-process-shared mutex. We only know at runtime whether or not to use it, depending on if we call
  117. // Mutex::Mutex(process_shared_tag)
  118. CRITICAL_SECTION m_critical_section;
  119. #else
  120. pthread_mutex_t m_impl = PTHREAD_MUTEX_INITIALIZER;
  121. #endif
  122. struct no_init_tag {
  123. };
  124. Mutex(no_init_tag)
  125. {
  126. }
  127. void init_as_regular();
  128. void init_as_process_shared(bool robust_if_available);
  129. REALM_NORETURN static void init_failed(int);
  130. REALM_NORETURN static void attr_init_failed(int);
  131. REALM_NORETURN static void destroy_failed(int) noexcept;
  132. REALM_NORETURN static void lock_failed(int) noexcept;
  133. private:
  134. friend class CondVar;
  135. friend class RobustMutex;
  136. };
  137. /// A simple mutex ownership wrapper.
  138. class LockGuard {
  139. public:
  140. LockGuard(Mutex&) noexcept;
  141. ~LockGuard() noexcept;
  142. private:
  143. Mutex& m_mutex;
  144. friend class CondVar;
  145. };
  146. /// See UniqueLock.
  147. struct defer_lock_tag {
  148. };
  149. /// A general-purpose mutex ownership wrapper supporting deferred
  150. /// locking as well as repeated unlocking and relocking.
  151. class UniqueLock {
  152. public:
  153. UniqueLock(Mutex&) noexcept;
  154. UniqueLock(Mutex&, defer_lock_tag) noexcept;
  155. ~UniqueLock() noexcept;
  156. void lock() noexcept;
  157. void unlock() noexcept;
  158. bool holds_lock() noexcept;
  159. private:
  160. Mutex* m_mutex;
  161. bool m_is_locked;
  162. };
  163. /// A robust version of a process-shared mutex.
  164. ///
  165. /// A robust mutex is one that detects whether a thread (or process)
  166. /// has died while holding a lock on the mutex.
  167. ///
  168. /// When the present platform does not offer support for robust
  169. /// mutexes, this mutex class behaves as a regular process-shared
  170. /// mutex, which means that if a thread dies while holding a lock, any
  171. /// future attempt at locking will block indefinitely.
  172. class RobustMutex : private Mutex {
  173. public:
  174. RobustMutex();
  175. ~RobustMutex() noexcept;
  176. static bool is_robust_on_this_platform() noexcept;
  177. class NotRecoverable;
  178. /// \param recover_func If the present platform does not support
  179. /// robust mutexes, this function is never called. Otherwise it is
  180. /// called if, and only if a thread has died while holding a
  181. /// lock. The purpose of the function is to reestablish a
  182. /// consistent shared state. If it fails to do this by throwing an
  183. /// exception, the mutex enters the 'unrecoverable' state where
  184. /// any future attempt at locking it will fail and cause
  185. /// NotRecoverable to be thrown. This function is advised to throw
  186. /// NotRecoverable when it fails, but it may throw any exception.
  187. ///
  188. /// \throw NotRecoverable If thrown by the specified recover
  189. /// function, or if the mutex has entered the 'unrecoverable'
  190. /// state due to a different thread throwing from its recover
  191. /// function.
  192. template <class Func>
  193. void lock(Func recover_func);
  194. template <class Func>
  195. bool try_lock(Func recover_func);
  196. void unlock() noexcept;
  197. /// Low-level locking of robust mutex.
  198. ///
  199. /// If the present platform does not support robust mutexes, this
  200. /// function always returns true. Otherwise it returns false if,
  201. /// and only if a thread has died while holding a lock.
  202. ///
  203. /// \note Most application should never call this function
  204. /// directly. It is called automatically when using the ordinary
  205. /// lock() function.
  206. ///
  207. /// \throw NotRecoverable If this mutex has entered the "not
  208. /// recoverable" state. It enters this state if
  209. /// mark_as_consistent() is not called between a call to
  210. /// robust_lock() that returns false and the corresponding call to
  211. /// unlock().
  212. bool low_level_lock();
  213. /// Low-level try-lock of robust mutex
  214. ///
  215. /// If the present platform does not support robust mutexes, this
  216. /// function always returns 0 or 1. Otherwise it returns -1 if,
  217. /// and only if a thread has died while holding a lock.
  218. ///
  219. /// Returns 1 if the lock is succesfully obtained.
  220. /// Returns 0 if the lock is held by somebody else (not obtained)
  221. /// Returns -1 if a thread has died while holding a lock.
  222. ///
  223. /// \note Most application should never call this function
  224. /// directly. It is called automatically when using the ordinary
  225. /// lock() function.
  226. ///
  227. /// \throw NotRecoverable If this mutex has entered the "not
  228. /// recoverable" state. It enters this state if
  229. /// mark_as_consistent() is not called between a call to
  230. /// robust_lock() that returns false and the corresponding call to
  231. /// unlock().
  232. int try_low_level_lock();
  233. /// Pull this mutex out of the 'inconsistent' state.
  234. ///
  235. /// Must be called only after low_level_lock() has returned false.
  236. ///
  237. /// \note Most application should never call this function
  238. /// directly. It is called automatically when using the ordinary
  239. /// lock() function.
  240. void mark_as_consistent() noexcept;
  241. /// Attempt to check if this mutex is a valid object.
  242. ///
  243. /// This attempts to trylock() the mutex, and if that fails returns false if
  244. /// the return value indicates that the low-level mutex is invalid (which is
  245. /// distinct from 'inconsistent'). Although pthread_mutex_trylock() may
  246. /// return EINVAL if the argument is not an initialized mutex object, merely
  247. /// attempting to check if an arbitrary blob of memory is a mutex object may
  248. /// involve undefined behavior, so it is only safe to assume that this
  249. /// function will run correctly when it is known that the mutex object is
  250. /// valid.
  251. bool is_valid() noexcept;
  252. friend class CondVar;
  253. };
  254. class RobustMutex::NotRecoverable : public std::exception {
  255. public:
  256. const char* what() const noexcept override
  257. {
  258. return "Failed to recover consistent state of shared memory";
  259. }
  260. };
  261. /// A simple robust mutex ownership wrapper.
  262. class RobustLockGuard {
  263. public:
  264. /// \param m the mutex to guard
  265. /// \param func See RobustMutex::lock().
  266. template <class TFunc>
  267. RobustLockGuard(RobustMutex& m, TFunc func);
  268. ~RobustLockGuard() noexcept;
  269. private:
  270. RobustMutex& m_mutex;
  271. friend class CondVar;
  272. };
  273. /// Condition variable for use in synchronization monitors.
  274. class CondVar {
  275. public:
  276. CondVar();
  277. ~CondVar() noexcept;
  278. struct process_shared_tag {
  279. };
  280. /// Initialize this condition variable for use across multiple
  281. /// processes. When constructed this way, the instance may be
  282. /// placed in memory shared by multimple processes, as well as in
  283. /// a memory mapped file. Such a condition variable remains valid
  284. /// even after the constructing process terminates. Deleting the
  285. /// instance (freeing the memory or deleting the file) without
  286. /// first calling the destructor is legal and will not cause any
  287. /// system resources to be leaked.
  288. CondVar(process_shared_tag);
  289. /// Wait for another thread to call notify() or notify_all().
  290. void wait(LockGuard& l) noexcept;
  291. template <class Func>
  292. void wait(RobustMutex& m, Func recover_func, const struct timespec* tp = nullptr);
  293. /// If any threads are wating for this condition, wake up at least
  294. /// one.
  295. void notify() noexcept;
  296. /// Wake up every thread that is currently wating on this
  297. /// condition.
  298. void notify_all() noexcept;
  299. private:
  300. #ifdef _WIN32
  301. CONDITION_VARIABLE m_condvar = CONDITION_VARIABLE_INIT;
  302. #else
  303. pthread_cond_t m_impl;
  304. #endif
  305. REALM_NORETURN static void init_failed(int);
  306. REALM_NORETURN static void attr_init_failed(int);
  307. REALM_NORETURN static void destroy_failed(int) noexcept;
  308. void handle_wait_error(int error);
  309. };
  310. class RaceDetector {
  311. std::atomic<bool> busy;
  312. public:
  313. RaceDetector()
  314. {
  315. busy.store(false);
  316. }
  317. void enter()
  318. {
  319. bool already_busy = busy.exchange(true, std::memory_order_acq_rel);
  320. if (already_busy)
  321. throw std::runtime_error("Race detected - critical section busy on entry");
  322. }
  323. void leave()
  324. {
  325. busy.store(false, std::memory_order_release);
  326. }
  327. friend class CriticalSection;
  328. };
  329. class CriticalSection {
  330. RaceDetector& rd;
  331. public:
  332. CriticalSection(RaceDetector& race)
  333. : rd(race)
  334. {
  335. rd.enter();
  336. }
  337. ~CriticalSection()
  338. {
  339. rd.leave();
  340. }
  341. };
  342. // Implementation:
  343. inline Thread::Thread()
  344. : m_joinable(false)
  345. {
  346. }
  347. template <class F>
  348. inline Thread::Thread(F func)
  349. : m_joinable(true)
  350. {
  351. std::unique_ptr<F> func2(new F(func)); // Throws
  352. start(&Thread::entry_point<F>, func2.get()); // Throws
  353. func2.release();
  354. }
  355. inline Thread::Thread(Thread&& thread) noexcept
  356. {
  357. #ifndef _WIN32
  358. m_id = thread.m_id;
  359. m_joinable = thread.m_joinable;
  360. thread.m_joinable = false;
  361. #endif
  362. }
  363. template <class F>
  364. inline void Thread::start(F func)
  365. {
  366. if (m_joinable)
  367. std::terminate();
  368. std::unique_ptr<F> func2(new F(func)); // Throws
  369. start(&Thread::entry_point<F>, func2.get()); // Throws
  370. func2.release();
  371. m_joinable = true;
  372. }
  373. inline Thread::~Thread() noexcept
  374. {
  375. if (m_joinable)
  376. REALM_TERMINATE("Destruction of joinable thread");
  377. }
  378. inline bool Thread::joinable() noexcept
  379. {
  380. return m_joinable;
  381. }
  382. inline void Thread::start(entry_func_type entry_func, void* arg)
  383. {
  384. #ifdef _WIN32
  385. m_std_thread = std::thread(entry_func, arg);
  386. #else
  387. const pthread_attr_t* attr = nullptr; // Use default thread attributes
  388. int r = pthread_create(&m_id, attr, entry_func, arg);
  389. if (REALM_UNLIKELY(r != 0))
  390. create_failed(r); // Throws
  391. #endif
  392. }
  393. template <class F>
  394. inline void* Thread::entry_point(void* cookie) noexcept
  395. {
  396. std::unique_ptr<F> func(static_cast<F*>(cookie));
  397. try {
  398. (*func)();
  399. }
  400. catch (...) {
  401. std::terminate();
  402. }
  403. return 0;
  404. }
  405. inline Mutex::Mutex()
  406. {
  407. init_as_regular();
  408. }
  409. inline Mutex::Mutex(process_shared_tag)
  410. {
  411. bool robust_if_available = false;
  412. init_as_process_shared(robust_if_available);
  413. }
  414. inline Mutex::~Mutex() noexcept
  415. {
  416. #ifndef _WIN32
  417. int r = pthread_mutex_destroy(&m_impl);
  418. if (REALM_UNLIKELY(r != 0))
  419. destroy_failed(r);
  420. #else
  421. DeleteCriticalSection(&m_critical_section);
  422. #endif
  423. }
  424. inline void Mutex::init_as_regular()
  425. {
  426. #ifndef _WIN32
  427. int r = pthread_mutex_init(&m_impl, 0);
  428. if (REALM_UNLIKELY(r != 0))
  429. init_failed(r);
  430. #else
  431. InitializeCriticalSection(&m_critical_section);
  432. #endif
  433. }
  434. inline void Mutex::lock() noexcept
  435. {
  436. #ifdef _WIN32
  437. EnterCriticalSection(&m_critical_section);
  438. #else
  439. int r = pthread_mutex_lock(&m_impl);
  440. if (REALM_LIKELY(r == 0))
  441. return;
  442. lock_failed(r);
  443. #endif
  444. }
  445. inline bool Mutex::try_lock() noexcept
  446. {
  447. #ifdef _WIN32
  448. return TryEnterCriticalSection(&m_critical_section);
  449. #else
  450. int r = pthread_mutex_trylock(&m_impl);
  451. if (r == EBUSY) {
  452. return false;
  453. }
  454. else if (r == 0) {
  455. return true;
  456. }
  457. lock_failed(r);
  458. #endif
  459. }
  460. inline void Mutex::unlock() noexcept
  461. {
  462. #ifdef _WIN32
  463. LeaveCriticalSection(&m_critical_section);
  464. #else
  465. int r = pthread_mutex_unlock(&m_impl);
  466. REALM_ASSERT(r == 0);
  467. #endif
  468. }
  469. inline LockGuard::LockGuard(Mutex& m) noexcept
  470. : m_mutex(m)
  471. {
  472. m_mutex.lock();
  473. }
  474. inline LockGuard::~LockGuard() noexcept
  475. {
  476. m_mutex.unlock();
  477. }
  478. inline UniqueLock::UniqueLock(Mutex& m) noexcept
  479. : m_mutex(&m)
  480. {
  481. m_mutex->lock();
  482. m_is_locked = true;
  483. }
  484. inline UniqueLock::UniqueLock(Mutex& m, defer_lock_tag) noexcept
  485. : m_mutex(&m)
  486. {
  487. m_is_locked = false;
  488. }
  489. inline UniqueLock::~UniqueLock() noexcept
  490. {
  491. if (m_is_locked)
  492. m_mutex->unlock();
  493. }
  494. inline bool UniqueLock::holds_lock() noexcept
  495. {
  496. return m_is_locked;
  497. }
  498. inline void UniqueLock::lock() noexcept
  499. {
  500. m_mutex->lock();
  501. m_is_locked = true;
  502. }
  503. inline void UniqueLock::unlock() noexcept
  504. {
  505. m_mutex->unlock();
  506. m_is_locked = false;
  507. }
  508. template <typename TFunc>
  509. inline RobustLockGuard::RobustLockGuard(RobustMutex& m, TFunc func)
  510. : m_mutex(m)
  511. {
  512. m_mutex.lock(func);
  513. }
  514. inline RobustLockGuard::~RobustLockGuard() noexcept
  515. {
  516. m_mutex.unlock();
  517. }
  518. inline RobustMutex::RobustMutex()
  519. : Mutex(no_init_tag())
  520. {
  521. bool robust_if_available = true;
  522. init_as_process_shared(robust_if_available);
  523. }
  524. inline RobustMutex::~RobustMutex() noexcept
  525. {
  526. }
  527. template <class Func>
  528. inline void RobustMutex::lock(Func recover_func)
  529. {
  530. bool no_thread_has_died = low_level_lock(); // Throws
  531. if (REALM_LIKELY(no_thread_has_died))
  532. return;
  533. try {
  534. recover_func(); // Throws
  535. mark_as_consistent();
  536. // If we get this far, the protected memory has been
  537. // brought back into a consistent state, and the mutex has
  538. // been notified about this. This means that we can safely
  539. // enter the applications critical section.
  540. }
  541. catch (...) {
  542. // Unlocking without first calling mark_as_consistent()
  543. // means that the mutex enters the "not recoverable"
  544. // state, which will cause all future attempts at locking
  545. // to fail.
  546. unlock();
  547. throw;
  548. }
  549. }
  550. template <class Func>
  551. inline bool RobustMutex::try_lock(Func recover_func)
  552. {
  553. int lock_result = try_low_level_lock(); // Throws
  554. if (lock_result == 0) return false;
  555. bool no_thread_has_died = lock_result == 1;
  556. if (REALM_LIKELY(no_thread_has_died))
  557. return true;
  558. try {
  559. recover_func(); // Throws
  560. mark_as_consistent();
  561. // If we get this far, the protected memory has been
  562. // brought back into a consistent state, and the mutex has
  563. // been notified aboit this. This means that we can safely
  564. // enter the applications critical section.
  565. }
  566. catch (...) {
  567. // Unlocking without first calling mark_as_consistent()
  568. // means that the mutex enters the "not recoverable"
  569. // state, which will cause all future attempts at locking
  570. // to fail.
  571. unlock();
  572. throw;
  573. }
  574. return true;
  575. }
  576. inline void RobustMutex::unlock() noexcept
  577. {
  578. Mutex::unlock();
  579. }
  580. inline CondVar::CondVar()
  581. {
  582. #ifndef _WIN32
  583. int r = pthread_cond_init(&m_impl, 0);
  584. if (REALM_UNLIKELY(r != 0))
  585. init_failed(r);
  586. #endif
  587. }
  588. inline CondVar::~CondVar() noexcept
  589. {
  590. #ifndef _WIN32
  591. int r = pthread_cond_destroy(&m_impl);
  592. if (REALM_UNLIKELY(r != 0))
  593. destroy_failed(r);
  594. #endif
  595. }
  596. inline void CondVar::wait(LockGuard& l) noexcept
  597. {
  598. #ifdef _WIN32
  599. SleepConditionVariableCS(&m_condvar, &l.m_mutex.m_critical_section, INFINITE);
  600. #else
  601. int r = pthread_cond_wait(&m_impl, &l.m_mutex.m_impl);
  602. if (REALM_UNLIKELY(r != 0))
  603. REALM_TERMINATE("pthread_cond_wait() failed");
  604. #endif
  605. }
  606. template <class Func>
  607. inline void CondVar::wait(RobustMutex& m, Func recover_func, const struct timespec* tp)
  608. {
  609. int r;
  610. if (!tp) {
  611. #ifdef _WIN32
  612. if (!SleepConditionVariableCS(&m_condvar, &m.m_critical_section, INFINITE))
  613. r = GetLastError();
  614. else
  615. r = 0;
  616. #else
  617. r = pthread_cond_wait(&m_impl, &m.m_impl);
  618. #endif
  619. }
  620. else {
  621. #ifdef _WIN32
  622. if (!SleepConditionVariableCS(&m_condvar, &m.m_critical_section, tp->tv_sec / 1000)) {
  623. r = GetLastError();
  624. if (r == ERROR_TIMEOUT)
  625. return;
  626. } else {
  627. r = 0;
  628. }
  629. #else
  630. r = pthread_cond_timedwait(&m_impl, &m.m_impl, tp);
  631. if (r == ETIMEDOUT)
  632. return;
  633. #endif
  634. }
  635. if (REALM_LIKELY(r == 0))
  636. return;
  637. handle_wait_error(r);
  638. try {
  639. recover_func(); // Throws
  640. m.mark_as_consistent();
  641. // If we get this far, the protected memory has been
  642. // brought back into a consistent state, and the mutex has
  643. // been notified aboit this. This means that we can safely
  644. // enter the applications critical section.
  645. }
  646. catch (...) {
  647. // Unlocking without first calling mark_as_consistent()
  648. // means that the mutex enters the "not recoverable"
  649. // state, which will cause all future attempts at locking
  650. // to fail.
  651. m.unlock();
  652. throw;
  653. }
  654. }
  655. inline void CondVar::notify() noexcept
  656. {
  657. #ifdef _WIN32
  658. WakeConditionVariable(&m_condvar);
  659. #else
  660. int r = pthread_cond_signal(&m_impl);
  661. REALM_ASSERT(r == 0);
  662. #endif
  663. }
  664. inline void CondVar::notify_all() noexcept
  665. {
  666. #ifdef _WIN32
  667. WakeAllConditionVariable(&m_condvar);
  668. #else
  669. int r = pthread_cond_broadcast(&m_impl);
  670. REALM_ASSERT(r == 0);
  671. #endif
  672. }
  673. // helpers which can ensure atomic access to memory which has not itself been declared atomic.
  674. // This can be used to e.g. ensure atomic access to members of a vector. Vectors does not
  675. // fully allow atomic members because operations on vector may relocate the underlying memory.
  676. // use with care!
  677. template <typename T>
  678. T load_atomic(T& t_ref, std::memory_order order)
  679. {
  680. std::atomic<T>* t_ptr = reinterpret_cast<std::atomic<T>*>(&t_ref);
  681. T t = atomic_load_explicit(t_ptr, order);
  682. return t;
  683. }
  684. template <typename T>
  685. void store_atomic(T& t_ref, T value, std::memory_order order)
  686. {
  687. std::atomic<T>* t_ptr = reinterpret_cast<std::atomic<T>*>(&t_ref);
  688. atomic_store_explicit(t_ptr, value, order);
  689. }
  690. } // namespace util
  691. } // namespace realm
  692. #endif // REALM_UTIL_THREAD_HPP