blob: 5aaa6b6babb65cec41f5e32e744794f8c514fafa [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_STL_MUTEX_H_
2#define AOS_STL_MUTEX_H_
Brian Silvermanb073f242014-09-08 16:29:57 -04003
4#include <mutex>
5
Philipp Schrader790cb542023-07-05 21:06:52 -07006#include "glog/logging.h"
7
John Park398c74a2018-10-20 21:17:39 -07008#include "aos/ipc_lib/aos_sync.h"
John Park33858a32018-09-28 23:05:48 -07009#include "aos/macros.h"
Brian Silvermanb073f242014-09-08 16:29:57 -040010
11namespace aos {
12
13// A mutex with the same API and semantics as ::std::mutex, with the addition of
14// methods for checking if the previous owner died and a constexpr default
15// constructor.
16// Definitely safe to put in SHM.
17// This uses the pthread_mutex semantics for owner-died: once somebody dies with
18// the lock held, anybody else who takes it will see true for owner_died() until
19// one of them calls consistent(). It is an error to call unlock() when
20// owner_died() returns true.
21class stl_mutex {
22 public:
23 constexpr stl_mutex() : native_handle_() {}
24
25 void lock() {
26 const int ret = mutex_grab(&native_handle_);
27 switch (ret) {
28 case 0:
29 break;
30 case 1:
31 owner_died_ = true;
32 break;
33 default:
Austin Schuha0c41ba2020-09-10 22:59:14 -070034 LOG(FATAL) << "mutex_grab(" << &native_handle_ << ") failed: " << ret;
Brian Silvermanb073f242014-09-08 16:29:57 -040035 }
36 }
37
38 bool try_lock() {
39 const int ret = mutex_trylock(&native_handle_);
40 switch (ret) {
41 case 0:
42 return true;
43 case 1:
44 owner_died_ = true;
45 return true;
46 case 4:
47 return false;
48 default:
Austin Schuha0c41ba2020-09-10 22:59:14 -070049 LOG(FATAL) << "mutex_trylock(" << &native_handle_
50 << ") failed: " << ret;
Brian Silvermanb073f242014-09-08 16:29:57 -040051 }
52 }
53
54 void unlock() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070055 CHECK(!owner_died_);
Brian Silvermanb073f242014-09-08 16:29:57 -040056 mutex_unlock(&native_handle_);
57 }
58
59 typedef aos_mutex *native_handle_type;
60 native_handle_type native_handle() { return &native_handle_; }
61
62 bool owner_died() const { return owner_died_; }
63 void consistent() { owner_died_ = false; }
64
Austin Schuh3054f5f2021-07-21 15:38:01 -070065 // Returns whether this mutex is locked by the current thread. This is very
66 // hard to use reliably, please think very carefully before using it for
67 // anything beyond probabilistic assertion checks.
68 bool is_locked() const { return mutex_islocked(&native_handle_); }
69
Brian Silvermanb073f242014-09-08 16:29:57 -040070 private:
71 aos_mutex native_handle_;
72
73 bool owner_died_ = false;
74
75 DISALLOW_COPY_AND_ASSIGN(stl_mutex);
76};
77
78// A mutex with the same API and semantics as ::std::recursive_mutex, with the
79// addition of methods for checking if the previous owner died and a constexpr
80// default constructor.
81// Definitely safe to put in SHM.
82// This uses the pthread_mutex semantics for owner-died: once somebody dies with
83// the lock held, anybody else who takes it will see true for owner_died() until
84// one of them calls consistent(). It is an error to call unlock() or lock()
85// again when owner_died() returns true.
86class stl_recursive_mutex {
87 public:
88 constexpr stl_recursive_mutex() {}
89
90 void lock() {
Austin Schuh3054f5f2021-07-21 15:38:01 -070091 if (mutex_.is_locked()) {
Austin Schuha0c41ba2020-09-10 22:59:14 -070092 CHECK(!owner_died());
Brian Silvermanb073f242014-09-08 16:29:57 -040093 ++recursive_locks_;
94 } else {
95 mutex_.lock();
96 if (mutex_.owner_died()) {
97 recursive_locks_ = 0;
98 } else {
Austin Schuha0c41ba2020-09-10 22:59:14 -070099 CHECK_EQ(0, recursive_locks_);
Brian Silvermanb073f242014-09-08 16:29:57 -0400100 }
101 }
102 }
103 bool try_lock() {
Austin Schuh3054f5f2021-07-21 15:38:01 -0700104 if (mutex_.is_locked()) {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700105 CHECK(!owner_died());
Brian Silvermanb073f242014-09-08 16:29:57 -0400106 ++recursive_locks_;
107 return true;
108 } else {
109 if (mutex_.try_lock()) {
110 if (mutex_.owner_died()) {
111 recursive_locks_ = 0;
112 } else {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700113 CHECK_EQ(0, recursive_locks_);
Brian Silvermanb073f242014-09-08 16:29:57 -0400114 }
115 return true;
116 } else {
117 return false;
118 }
119 }
120 }
121 void unlock() {
122 if (recursive_locks_ == 0) {
123 mutex_.unlock();
124 } else {
125 --recursive_locks_;
126 }
127 }
128
129 typedef stl_mutex::native_handle_type native_handle_type;
130 native_handle_type native_handle() { return mutex_.native_handle(); }
131
132 bool owner_died() const { return mutex_.owner_died(); }
133 void consistent() { mutex_.consistent(); }
134
135 private:
136 stl_mutex mutex_;
137 int recursive_locks_ = 0;
138
139 DISALLOW_COPY_AND_ASSIGN(stl_recursive_mutex);
140};
141
142// Convenient typedefs for various types of locking objects.
143typedef ::std::lock_guard<stl_mutex> mutex_lock_guard;
144typedef ::std::lock_guard<stl_recursive_mutex> recursive_lock_guard;
145typedef ::std::unique_lock<stl_mutex> mutex_unique_lock;
146typedef ::std::unique_lock<stl_recursive_mutex> recursive_unique_lock;
147
148} // namespace aos
149
John Park33858a32018-09-28 23:05:48 -0700150#endif // AOS_STL_MUTEX_H_