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