blob: b952644e19ace582701517d2dea50205f14a4859 [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001#ifndef AOS_COMMON_MUTEX_H_
2#define AOS_COMMON_MUTEX_H_
3
brians343bc112013-02-10 01:53:46 +00004#include "aos/common/macros.h"
Brian Silverman14fd0fb2014-01-14 21:42:01 -08005#include "aos/linux_code/ipc_lib/aos_sync.h"
Brian Silvermandc1eb272014-08-19 14:25:59 -04006#include "aos/common/die.h"
brians343bc112013-02-10 01:53:46 +00007
8namespace aos {
9
Brian Silverman08661c72013-09-01 17:24:38 -070010class Condition;
11
Brian Silvermandc1eb272014-08-19 14:25:59 -040012// An abstraction of a mutex that is easy to implement for environments other
13// than Linux too.
14// If there are multiple threads or processes contending for the mutex,
brians343bc112013-02-10 01:53:46 +000015// higher priority ones will succeed in locking first,
16// and tasks of equal priorities have the same chance of getting the lock.
Brian Silvermandc1eb272014-08-19 14:25:59 -040017// To deal with priority inversion, the linux implementation does priority
18// inheritance.
19// Before destroying a mutex, it is important to make sure it isn't locked.
20// Otherwise, the destructor will LOG(FATAL).
brians343bc112013-02-10 01:53:46 +000021class Mutex {
22 public:
Brian Silvermandc1eb272014-08-19 14:25:59 -040023 enum class State {
24 kLocked, kUnlocked
25 };
26
brians343bc112013-02-10 01:53:46 +000027 // Creates an unlocked mutex.
28 Mutex();
Brian Silvermandc1eb272014-08-19 14:25:59 -040029 // Verifies that it isn't locked.
30 //
31 // This is important because freeing a locked mutex means there is freed
32 // memory in the middle of the robust list, which breaks things horribly.
brians343bc112013-02-10 01:53:46 +000033 ~Mutex();
Brian Silvermandc1eb272014-08-19 14:25:59 -040034
brians343bc112013-02-10 01:53:46 +000035 // Locks the mutex. If it fails, it calls LOG(FATAL).
Austin Schuhf4b194e2014-09-21 10:26:41 -070036 // Returns false.
Brian Silvermandc1eb272014-08-19 14:25:59 -040037 bool Lock() __attribute__((warn_unused_result));
brians343bc112013-02-10 01:53:46 +000038 // Unlocks the mutex. Fails like Lock.
Brian Silverman6da04272014-05-18 18:47:48 -070039 // Multiple unlocking is undefined.
brians343bc112013-02-10 01:53:46 +000040 void Unlock();
41 // Locks the mutex unless it is already locked.
Brian Silvermandc1eb272014-08-19 14:25:59 -040042 // Returns the new state of the mutex.
brians343bc112013-02-10 01:53:46 +000043 // Doesn't wait for the mutex to be unlocked if it is locked.
Brian Silvermandc1eb272014-08-19 14:25:59 -040044 State TryLock() __attribute__((warn_unused_result));
brians343bc112013-02-10 01:53:46 +000045
Brian Silverman1dfe48b2014-09-06 16:13:02 -040046 // Returns true iff the current task has this mutex locked.
47 // This is mainly for IPCRecursiveMutexLocker to use.
48 bool OwnedBySelf() const;
49
brians343bc112013-02-10 01:53:46 +000050 private:
Brian Silvermandc1eb272014-08-19 14:25:59 -040051 aos_mutex impl_;
Brian Silverman08661c72013-09-01 17:24:38 -070052
53 friend class Condition; // for access to impl_
brians343bc112013-02-10 01:53:46 +000054};
55
56// A class that locks a Mutex when constructed and unlocks it when destructed.
57// Designed to be used as a local variable so that
58// the mutex will be unlocked when the scope is exited.
Brian Silvermandc1eb272014-08-19 14:25:59 -040059// This one immediately Dies if the previous owner died. This makes it a good
60// choice for mutexes that are only used within a single process, but NOT for
61// mutexes shared by multiple processes. For those, use IPCMutexLocker.
brians343bc112013-02-10 01:53:46 +000062class MutexLocker {
63 public:
64 explicit MutexLocker(Mutex *mutex) : mutex_(mutex) {
Brian Silvermandc1eb272014-08-19 14:25:59 -040065 if (__builtin_expect(mutex_->Lock(), false)) {
66 ::aos::Die("previous owner of mutex %p died but it shouldn't be able to",
67 this);
68 }
brians343bc112013-02-10 01:53:46 +000069 }
70 ~MutexLocker() {
71 mutex_->Unlock();
72 }
73
74 private:
Brian Silvermandc1eb272014-08-19 14:25:59 -040075 Mutex *const mutex_;
76
brians343bc112013-02-10 01:53:46 +000077 DISALLOW_COPY_AND_ASSIGN(MutexLocker);
78};
Brian Silvermandc1eb272014-08-19 14:25:59 -040079
80// A version of MutexLocker which reports the previous owner dying instead of
81// immediately LOG(FATAL)ing.
82class IPCMutexLocker {
Brian Silvermand41b4422013-09-01 14:02:33 -070083 public:
Brian Silvermandc1eb272014-08-19 14:25:59 -040084 explicit IPCMutexLocker(Mutex *mutex)
85 : mutex_(mutex), owner_died_(mutex_->Lock()) {}
86 ~IPCMutexLocker() {
87 if (__builtin_expect(!owner_died_checked_, false)) {
88 ::aos::Die("nobody checked if the previous owner of mutex %p died", this);
89 }
Brian Silvermand41b4422013-09-01 14:02:33 -070090 mutex_->Unlock();
91 }
Brian Silvermandc1eb272014-08-19 14:25:59 -040092
93 // Whether or not the previous owner died. If this is not called at least
94 // once, the destructor will ::aos::Die.
95 __attribute__((warn_unused_result)) bool owner_died() {
96 owner_died_checked_ = true;
97 return __builtin_expect(owner_died_, false);
Brian Silvermand41b4422013-09-01 14:02:33 -070098 }
99
100 private:
Brian Silvermandc1eb272014-08-19 14:25:59 -0400101 Mutex *const mutex_;
102 const bool owner_died_;
103 bool owner_died_checked_ = false;
104
105 DISALLOW_COPY_AND_ASSIGN(IPCMutexLocker);
Brian Silvermand41b4422013-09-01 14:02:33 -0700106};
brians343bc112013-02-10 01:53:46 +0000107
Brian Silverman1dfe48b2014-09-06 16:13:02 -0400108// A version of IPCMutexLocker which only locks (and unlocks) the mutex if the
109// current task does not already hold it.
110class IPCRecursiveMutexLocker {
111 public:
112 explicit IPCRecursiveMutexLocker(Mutex *mutex)
113 : mutex_(mutex),
114 locked_(!mutex_->OwnedBySelf()),
115 owner_died_(locked_ ? mutex_->Lock() : false) {}
116 ~IPCRecursiveMutexLocker() {
117 if (__builtin_expect(!owner_died_checked_, false)) {
118 ::aos::Die("nobody checked if the previous owner of mutex %p died", this);
119 }
120 if (locked_) mutex_->Unlock();
121 }
122
123 // Whether or not the previous owner died. If this is not called at least
124 // once, the destructor will ::aos::Die.
125 __attribute__((warn_unused_result)) bool owner_died() {
126 owner_died_checked_ = true;
127 return __builtin_expect(owner_died_, false);
128 }
129
130 private:
131 Mutex *const mutex_;
132 const bool locked_, owner_died_;
133 bool owner_died_checked_ = false;
134
135 DISALLOW_COPY_AND_ASSIGN(IPCRecursiveMutexLocker);
136};
137
brians343bc112013-02-10 01:53:46 +0000138} // namespace aos
139
140#endif // AOS_COMMON_MUTEX_H_