blob: e3a930ec5450ee73d06811f088bdb5268184cd27 [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
John Park398c74a2018-10-20 21:17:39 -07006#include "aos/ipc_lib/aos_sync.h"
John Park33858a32018-09-28 23:05:48 -07007#include "aos/macros.h"
Austin Schuha0c41ba2020-09-10 22:59:14 -07008#include "glog/logging.h"
Brian Silvermanb073f242014-09-08 16:29:57 -04009
10namespace aos {
11
12// A mutex with the same API and semantics as ::std::mutex, with the addition of
13// methods for checking if the previous owner died and a constexpr default
14// constructor.
15// Definitely safe to put in SHM.
16// This uses the pthread_mutex semantics for owner-died: once somebody dies with
17// the lock held, anybody else who takes it will see true for owner_died() until
18// one of them calls consistent(). It is an error to call unlock() when
19// owner_died() returns true.
20class stl_mutex {
21 public:
22 constexpr stl_mutex() : native_handle_() {}
23
24 void lock() {
25 const int ret = mutex_grab(&native_handle_);
26 switch (ret) {
27 case 0:
28 break;
29 case 1:
30 owner_died_ = true;
31 break;
32 default:
Austin Schuha0c41ba2020-09-10 22:59:14 -070033 LOG(FATAL) << "mutex_grab(" << &native_handle_ << ") failed: " << ret;
Brian Silvermanb073f242014-09-08 16:29:57 -040034 }
35 }
36
37 bool try_lock() {
38 const int ret = mutex_trylock(&native_handle_);
39 switch (ret) {
40 case 0:
41 return true;
42 case 1:
43 owner_died_ = true;
44 return true;
45 case 4:
46 return false;
47 default:
Austin Schuha0c41ba2020-09-10 22:59:14 -070048 LOG(FATAL) << "mutex_trylock(" << &native_handle_
49 << ") failed: " << ret;
Brian Silvermanb073f242014-09-08 16:29:57 -040050 }
51 }
52
53 void unlock() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070054 CHECK(!owner_died_);
Brian Silvermanb073f242014-09-08 16:29:57 -040055 mutex_unlock(&native_handle_);
56 }
57
58 typedef aos_mutex *native_handle_type;
59 native_handle_type native_handle() { return &native_handle_; }
60
61 bool owner_died() const { return owner_died_; }
62 void consistent() { owner_died_ = false; }
63
Austin Schuh3054f5f2021-07-21 15:38:01 -070064 // Returns whether this mutex is locked by the current thread. This is very
65 // hard to use reliably, please think very carefully before using it for
66 // anything beyond probabilistic assertion checks.
67 bool is_locked() const { return mutex_islocked(&native_handle_); }
68
Brian Silvermanb073f242014-09-08 16:29:57 -040069 private:
70 aos_mutex native_handle_;
71
72 bool owner_died_ = false;
73
74 DISALLOW_COPY_AND_ASSIGN(stl_mutex);
75};
76
77// A mutex with the same API and semantics as ::std::recursive_mutex, with the
78// addition of methods for checking if the previous owner died and a constexpr
79// default constructor.
80// Definitely safe to put in SHM.
81// This uses the pthread_mutex semantics for owner-died: once somebody dies with
82// the lock held, anybody else who takes it will see true for owner_died() until
83// one of them calls consistent(). It is an error to call unlock() or lock()
84// again when owner_died() returns true.
85class stl_recursive_mutex {
86 public:
87 constexpr stl_recursive_mutex() {}
88
89 void lock() {
Austin Schuh3054f5f2021-07-21 15:38:01 -070090 if (mutex_.is_locked()) {
Austin Schuha0c41ba2020-09-10 22:59:14 -070091 CHECK(!owner_died());
Brian Silvermanb073f242014-09-08 16:29:57 -040092 ++recursive_locks_;
93 } else {
94 mutex_.lock();
95 if (mutex_.owner_died()) {
96 recursive_locks_ = 0;
97 } else {
Austin Schuha0c41ba2020-09-10 22:59:14 -070098 CHECK_EQ(0, recursive_locks_);
Brian Silvermanb073f242014-09-08 16:29:57 -040099 }
100 }
101 }
102 bool try_lock() {
Austin Schuh3054f5f2021-07-21 15:38:01 -0700103 if (mutex_.is_locked()) {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700104 CHECK(!owner_died());
Brian Silvermanb073f242014-09-08 16:29:57 -0400105 ++recursive_locks_;
106 return true;
107 } else {
108 if (mutex_.try_lock()) {
109 if (mutex_.owner_died()) {
110 recursive_locks_ = 0;
111 } else {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700112 CHECK_EQ(0, recursive_locks_);
Brian Silvermanb073f242014-09-08 16:29:57 -0400113 }
114 return true;
115 } else {
116 return false;
117 }
118 }
119 }
120 void unlock() {
121 if (recursive_locks_ == 0) {
122 mutex_.unlock();
123 } else {
124 --recursive_locks_;
125 }
126 }
127
128 typedef stl_mutex::native_handle_type native_handle_type;
129 native_handle_type native_handle() { return mutex_.native_handle(); }
130
131 bool owner_died() const { return mutex_.owner_died(); }
132 void consistent() { mutex_.consistent(); }
133
134 private:
135 stl_mutex mutex_;
136 int recursive_locks_ = 0;
137
138 DISALLOW_COPY_AND_ASSIGN(stl_recursive_mutex);
139};
140
141// Convenient typedefs for various types of locking objects.
142typedef ::std::lock_guard<stl_mutex> mutex_lock_guard;
143typedef ::std::lock_guard<stl_recursive_mutex> recursive_lock_guard;
144typedef ::std::unique_lock<stl_mutex> mutex_unique_lock;
145typedef ::std::unique_lock<stl_recursive_mutex> recursive_unique_lock;
146
147} // namespace aos
148
John Park33858a32018-09-28 23:05:48 -0700149#endif // AOS_STL_MUTEX_H_