Removed Common
Change-Id: I01ea8f07220375c2ad9bc0092281d4f27c642303
diff --git a/aos/mutex/mutex.h b/aos/mutex/mutex.h
new file mode 100644
index 0000000..8bd986c
--- /dev/null
+++ b/aos/mutex/mutex.h
@@ -0,0 +1,150 @@
+#ifndef AOS_MUTEX_H_
+#define AOS_MUTEX_H_
+
+#include "aos/macros.h"
+#include "aos/type_traits/type_traits.h"
+#include "aos/die.h"
+#include "aos/linux_code/ipc_lib/aos_sync.h"
+
+namespace aos {
+
+class Condition;
+
+// An abstraction of a mutex that is easy to implement for environments other
+// than Linux too.
+// If there are multiple threads or processes contending for the mutex,
+// higher priority ones will succeed in locking first,
+// and tasks of equal priorities have the same chance of getting the lock.
+// To deal with priority inversion, the linux implementation does priority
+// inheritance.
+// Before destroying a mutex, it is important to make sure it isn't locked.
+// Otherwise, the destructor will LOG(FATAL).
+class Mutex {
+ public:
+ // States that signify the result of TryLock.
+ enum class State {
+ // The mutex was acquired successfully.
+ kLocked,
+ // TryLock tried to grab the mutex and failed.
+ kLockFailed,
+ // The previous owner of the mutex died.
+ kOwnerDied,
+ };
+
+ // Creates an unlocked mutex.
+ Mutex() : impl_() {
+ static_assert(shm_ok<Mutex>::value,
+ "Mutex is not safe for use in shared memory.");
+ }
+ // Verifies that it isn't locked.
+ //
+ // This is important because freeing a locked mutex means there is freed
+ // memory in the middle of the robust list, which breaks things horribly.
+ ~Mutex() = default;
+
+ // Locks the mutex. If it fails, it calls LOG(FATAL).
+ // Returns true if the previous owner died instead of unlocking nicely.
+ bool Lock() __attribute__((warn_unused_result));
+ // Unlocks the mutex. Fails like Lock.
+ // Multiple unlocking is undefined.
+ void Unlock();
+ // Locks the mutex unless it is already locked.
+ // Returns the new state of the mutex.
+ // Doesn't wait for the mutex to be unlocked if it is locked.
+ State TryLock() __attribute__((warn_unused_result));
+
+ // Returns true iff the current task has this mutex locked.
+ // This is mainly for IPCRecursiveMutexLocker to use.
+ bool OwnedBySelf() const;
+
+ private:
+ aos_mutex impl_;
+
+ friend class Condition; // for access to impl_
+};
+
+// A class that locks a Mutex when constructed and unlocks it when destructed.
+// Designed to be used as a local variable so that
+// the mutex will be unlocked when the scope is exited.
+// This one immediately Dies if the previous owner died. This makes it a good
+// choice for mutexes that are only used within a single process, but NOT for
+// mutexes shared by multiple processes. For those, use IPCMutexLocker.
+class MutexLocker {
+ public:
+ explicit MutexLocker(Mutex *mutex) : mutex_(mutex) {
+ if (__builtin_expect(mutex_->Lock(), false)) {
+ ::aos::Die("previous owner of mutex %p died but it shouldn't be able to",
+ this);
+ }
+ }
+ ~MutexLocker() {
+ mutex_->Unlock();
+ }
+
+ private:
+ Mutex *const mutex_;
+
+ DISALLOW_COPY_AND_ASSIGN(MutexLocker);
+};
+
+// A version of MutexLocker which reports the previous owner dying instead of
+// immediately LOG(FATAL)ing.
+class IPCMutexLocker {
+ public:
+ explicit IPCMutexLocker(Mutex *mutex)
+ : mutex_(mutex), owner_died_(mutex_->Lock()) {}
+ ~IPCMutexLocker() {
+ if (__builtin_expect(!owner_died_checked_, false)) {
+ ::aos::Die("nobody checked if the previous owner of mutex %p died", this);
+ }
+ mutex_->Unlock();
+ }
+
+ // Whether or not the previous owner died. If this is not called at least
+ // once, the destructor will ::aos::Die.
+ __attribute__((warn_unused_result)) bool owner_died() {
+ owner_died_checked_ = true;
+ return __builtin_expect(owner_died_, false);
+ }
+
+ private:
+ Mutex *const mutex_;
+ const bool owner_died_;
+ bool owner_died_checked_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCMutexLocker);
+};
+
+// A version of IPCMutexLocker which only locks (and unlocks) the mutex if the
+// current task does not already hold it.
+class IPCRecursiveMutexLocker {
+ public:
+ explicit IPCRecursiveMutexLocker(Mutex *mutex)
+ : mutex_(mutex),
+ locked_(!mutex_->OwnedBySelf()),
+ owner_died_(locked_ ? mutex_->Lock() : false) {}
+ ~IPCRecursiveMutexLocker() {
+ if (__builtin_expect(!owner_died_checked_, false)) {
+ ::aos::Die("nobody checked if the previous owner of mutex %p died", this);
+ }
+ if (locked_) mutex_->Unlock();
+ }
+
+ // Whether or not the previous owner died. If this is not called at least
+ // once, the destructor will ::aos::Die.
+ __attribute__((warn_unused_result)) bool owner_died() {
+ owner_died_checked_ = true;
+ return __builtin_expect(owner_died_, false);
+ }
+
+ private:
+ Mutex *const mutex_;
+ const bool locked_, owner_died_;
+ bool owner_died_checked_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCRecursiveMutexLocker);
+};
+
+} // namespace aos
+
+#endif // AOS_MUTEX_H_