blob: 8450e73f3ef0cb346e4a21fff87e0116218e49fd [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>
Stephan Pleines45ea55a2024-05-30 20:26:24 -07005#include <ostream>
Brian Silvermanb073f242014-09-08 16:29:57 -04006
Austin Schuh99f7c6a2024-06-25 22:07:44 -07007#include "absl/log/check.h"
8#include "absl/log/log.h"
Philipp Schrader790cb542023-07-05 21:06:52 -07009
John Park398c74a2018-10-20 21:17:39 -070010#include "aos/ipc_lib/aos_sync.h"
John Park33858a32018-09-28 23:05:48 -070011#include "aos/macros.h"
Brian Silvermanb073f242014-09-08 16:29:57 -040012
13namespace aos {
14
15// A mutex with the same API and semantics as ::std::mutex, with the addition of
16// methods for checking if the previous owner died and a constexpr default
17// constructor.
18// Definitely safe to put in SHM.
19// This uses the pthread_mutex semantics for owner-died: once somebody dies with
20// the lock held, anybody else who takes it will see true for owner_died() until
21// one of them calls consistent(). It is an error to call unlock() when
22// owner_died() returns true.
23class stl_mutex {
24 public:
25 constexpr stl_mutex() : native_handle_() {}
26
27 void lock() {
28 const int ret = mutex_grab(&native_handle_);
29 switch (ret) {
30 case 0:
31 break;
32 case 1:
33 owner_died_ = true;
34 break;
35 default:
Austin Schuha0c41ba2020-09-10 22:59:14 -070036 LOG(FATAL) << "mutex_grab(" << &native_handle_ << ") failed: " << ret;
Brian Silvermanb073f242014-09-08 16:29:57 -040037 }
38 }
39
40 bool try_lock() {
41 const int ret = mutex_trylock(&native_handle_);
42 switch (ret) {
43 case 0:
44 return true;
45 case 1:
46 owner_died_ = true;
47 return true;
48 case 4:
49 return false;
50 default:
Austin Schuha0c41ba2020-09-10 22:59:14 -070051 LOG(FATAL) << "mutex_trylock(" << &native_handle_
52 << ") failed: " << ret;
Brian Silvermanb073f242014-09-08 16:29:57 -040053 }
54 }
55
56 void unlock() {
Austin Schuha0c41ba2020-09-10 22:59:14 -070057 CHECK(!owner_died_);
Brian Silvermanb073f242014-09-08 16:29:57 -040058 mutex_unlock(&native_handle_);
59 }
60
61 typedef aos_mutex *native_handle_type;
62 native_handle_type native_handle() { return &native_handle_; }
63
64 bool owner_died() const { return owner_died_; }
65 void consistent() { owner_died_ = false; }
66
Austin Schuh3054f5f2021-07-21 15:38:01 -070067 // Returns whether this mutex is locked by the current thread. This is very
68 // hard to use reliably, please think very carefully before using it for
69 // anything beyond probabilistic assertion checks.
70 bool is_locked() const { return mutex_islocked(&native_handle_); }
71
Brian Silvermanb073f242014-09-08 16:29:57 -040072 private:
73 aos_mutex native_handle_;
74
75 bool owner_died_ = false;
76
77 DISALLOW_COPY_AND_ASSIGN(stl_mutex);
78};
79
80// A mutex with the same API and semantics as ::std::recursive_mutex, with the
81// addition of methods for checking if the previous owner died and a constexpr
82// default constructor.
83// Definitely safe to put in SHM.
84// This uses the pthread_mutex semantics for owner-died: once somebody dies with
85// the lock held, anybody else who takes it will see true for owner_died() until
86// one of them calls consistent(). It is an error to call unlock() or lock()
87// again when owner_died() returns true.
88class stl_recursive_mutex {
89 public:
90 constexpr stl_recursive_mutex() {}
91
92 void lock() {
Austin Schuh3054f5f2021-07-21 15:38:01 -070093 if (mutex_.is_locked()) {
Austin Schuha0c41ba2020-09-10 22:59:14 -070094 CHECK(!owner_died());
Brian Silvermanb073f242014-09-08 16:29:57 -040095 ++recursive_locks_;
96 } else {
97 mutex_.lock();
98 if (mutex_.owner_died()) {
99 recursive_locks_ = 0;
100 } else {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700101 CHECK_EQ(0, recursive_locks_);
Brian Silvermanb073f242014-09-08 16:29:57 -0400102 }
103 }
104 }
105 bool try_lock() {
Austin Schuh3054f5f2021-07-21 15:38:01 -0700106 if (mutex_.is_locked()) {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700107 CHECK(!owner_died());
Brian Silvermanb073f242014-09-08 16:29:57 -0400108 ++recursive_locks_;
109 return true;
110 } else {
111 if (mutex_.try_lock()) {
112 if (mutex_.owner_died()) {
113 recursive_locks_ = 0;
114 } else {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700115 CHECK_EQ(0, recursive_locks_);
Brian Silvermanb073f242014-09-08 16:29:57 -0400116 }
117 return true;
118 } else {
119 return false;
120 }
121 }
122 }
123 void unlock() {
124 if (recursive_locks_ == 0) {
125 mutex_.unlock();
126 } else {
127 --recursive_locks_;
128 }
129 }
130
131 typedef stl_mutex::native_handle_type native_handle_type;
132 native_handle_type native_handle() { return mutex_.native_handle(); }
133
134 bool owner_died() const { return mutex_.owner_died(); }
135 void consistent() { mutex_.consistent(); }
136
137 private:
138 stl_mutex mutex_;
139 int recursive_locks_ = 0;
140
141 DISALLOW_COPY_AND_ASSIGN(stl_recursive_mutex);
142};
143
144// Convenient typedefs for various types of locking objects.
145typedef ::std::lock_guard<stl_mutex> mutex_lock_guard;
146typedef ::std::lock_guard<stl_recursive_mutex> recursive_lock_guard;
147typedef ::std::unique_lock<stl_mutex> mutex_unique_lock;
148typedef ::std::unique_lock<stl_recursive_mutex> recursive_unique_lock;
149
150} // namespace aos
151
John Park33858a32018-09-28 23:05:48 -0700152#endif // AOS_STL_MUTEX_H_