1 /* 2 * Copyright (c) 2008-2014 Travis Geiselbrecht 3 * Copyright (c) 2012 Shantanu Gupta 4 * 5 * Use of this source code is governed by a MIT-style 6 * license that can be found in the LICENSE file or at 7 * https://opensource.org/licenses/MIT 8 */ 9 #pragma once 10 11 #include <kernel/thread.h> 12 #include <lk/compiler.h> 13 #include <lk/debug.h> 14 #include <stdint.h> 15 16 __BEGIN_CDECLS 17 18 #define MUTEX_MAGIC (0x6D757478) // 'mutx' 19 20 typedef struct mutex { 21 uint32_t magic; 22 thread_t *holder; 23 int count; 24 wait_queue_t wait; 25 } mutex_t; 26 27 #define MUTEX_INITIAL_VALUE(m) \ 28 { \ 29 .magic = MUTEX_MAGIC, \ 30 .holder = NULL, \ 31 .count = 0, \ 32 .wait = WAIT_QUEUE_INITIAL_VALUE((m).wait), \ 33 } 34 35 /* Rules for Mutexes: 36 * - Mutexes are only safe to use from thread context. 37 * - Mutexes are non-recursive. 38 */ 39 40 void mutex_init(mutex_t *); 41 void mutex_destroy(mutex_t *); 42 status_t mutex_acquire_timeout(mutex_t *, lk_time_t); /* try to acquire the mutex with a timeout value */ 43 status_t mutex_release(mutex_t *); 44 mutex_acquire(mutex_t * m)45static inline status_t mutex_acquire(mutex_t *m) { 46 return mutex_acquire_timeout(m, INFINITE_TIME); 47 } 48 49 /* does the current thread hold the mutex? */ is_mutex_held(const mutex_t * m)50static bool is_mutex_held(const mutex_t *m) { 51 return m->holder == get_current_thread(); 52 } 53 54 __END_CDECLS 55 56 #ifdef __cplusplus 57 58 #include <lk/cpp.h> 59 60 // C++ wrapper object 61 class Mutex { 62 public: 63 constexpr Mutex() = default; ~Mutex()64 ~Mutex() { mutex_destroy(&lock_); } 65 acquire(lk_time_t timeout)66 status_t acquire(lk_time_t timeout) { return mutex_acquire_timeout(&lock_, timeout); } release()67 status_t release() { return mutex_release(&lock_); } is_held()68 bool is_held() { return is_mutex_held(&lock_); } 69 70 // suppress default constructors 71 DISALLOW_COPY_ASSIGN_AND_MOVE(Mutex); 72 73 private: 74 mutex_t lock_ = MUTEX_INITIAL_VALUE(lock_); 75 76 // AutoLock has access to the inner lock 77 friend class AutoLock; 78 }; 79 80 // RAII wrapper around the mutex 81 class AutoLock { 82 public: AutoLock(mutex_t * mutex)83 explicit AutoLock(mutex_t *mutex) : mutex_(mutex) { mutex_acquire(mutex_); } AutoLock(mutex_t & mutex)84 AutoLock(mutex_t &mutex) : AutoLock(&mutex) {} 85 AutoLock(Mutex * mutex)86 explicit AutoLock(Mutex *mutex) : AutoLock(&mutex->lock_) {} AutoLock(Mutex & mutex)87 AutoLock(Mutex &mutex) : AutoLock(&mutex) {} 88 ~AutoLock()89 ~AutoLock() { release(); } 90 91 // early release the mutex before the object goes out of scope release()92 void release() { 93 if (likely(mutex_)) { 94 mutex_release(mutex_); 95 mutex_ = nullptr; 96 } 97 } 98 99 // suppress default constructors 100 DISALLOW_COPY_ASSIGN_AND_MOVE(AutoLock); 101 102 private: 103 mutex_t *mutex_ = nullptr; 104 }; 105 106 #endif // __cplusplus 107 108