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