1 // Copyright 2016 The Fuchsia Authors
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 <assert.h>
12 #include <debug.h>
13 #include <kernel/atomic.h>
14 #include <kernel/thread.h>
15 #include <stdint.h>
16 #include <zircon/compiler.h>
17 #include <zircon/thread_annotations.h>
18 
19 __BEGIN_CDECLS
20 
21 #define MUTEX_MAGIC (0x6D757478) // 'mutx'
22 
23 // Body of the mutex.
24 // The val field holds either 0 or a pointer to the thread_t holding the mutex.
25 // If one or more threads are blocking and queued up, MUTEX_FLAG_QUEUED is ORed in as well.
26 // NOTE: MUTEX_FLAG_QUEUED is only manipulated under the THREAD_LOCK.
27 typedef struct TA_CAP("mutex") mutex {
28     uint32_t magic;
29     uintptr_t val;
30     wait_queue_t wait;
31 } mutex_t;
32 
33 #define MUTEX_FLAG_QUEUED ((uintptr_t)1)
34 
35 // accessors to extract the holder pointer from the val member
mutex_val(const mutex_t * m)36 static inline uintptr_t mutex_val(const mutex_t* m) {
37     static_assert(sizeof(uintptr_t) == sizeof(uint64_t), "");
38     return atomic_load_u64_relaxed((uint64_t*)&m->val);
39 }
40 
mutex_holder(const mutex_t * m)41 static inline thread_t* mutex_holder(const mutex_t* m) {
42     static_assert(sizeof(uintptr_t) == sizeof(uint64_t), "");
43     return (thread_t*)(mutex_val(m) & ~MUTEX_FLAG_QUEUED);
44 }
45 
46 #define MUTEX_INITIAL_VALUE(m)                      \
47     {                                               \
48         .magic = MUTEX_MAGIC,                       \
49         .val = 0,                                   \
50         .wait = WAIT_QUEUE_INITIAL_VALUE((m).wait), \
51     }
52 
53 // Rules for Mutexes:
54 // - Mutexes are only safe to use from thread context.
55 // - Mutexes are non-recursive.
56 void mutex_init(mutex_t* m);
57 void mutex_destroy(mutex_t* m);
58 void mutex_acquire(mutex_t* m) TA_ACQ(m);
59 void mutex_release(mutex_t* m) TA_REL(m);
60 
61 // special version of the above with the thread lock held
62 void mutex_release_thread_locked(mutex_t* m, bool reschedule) TA_REL(m);
63 
64 // does the current thread hold the mutex?
is_mutex_held(const mutex_t * m)65 static inline bool is_mutex_held(const mutex_t* m) {
66     return (mutex_holder(m) == get_current_thread());
67 }
68 
69 __END_CDECLS
70 
71 #ifdef __cplusplus
72 
73 #include <lockdep/lock_policy.h>
74 #include <lockdep/lock_traits.h>
75 
76 // Declares a fbl::Mutex member of the struct or class |containing_type|.
77 //
78 // Example usage:
79 //
80 // struct MyType {
81 //     DECLARE_MUTEX(MyType) lock;
82 // };
83 //
84 #define DECLARE_MUTEX(containing_type) \
85     LOCK_DEP_INSTRUMENT(containing_type, fbl::Mutex)
86 
87 // Declares a |lock_type| member of the struct or class |containing_type|.
88 //
89 // Example usage:
90 //
91 // struct MyType {
92 //     DECLARE_LOCK(MyType, LockType) lock;
93 // };
94 //
95 #define DECLARE_LOCK(containing_type, lock_type) \
96     LOCK_DEP_INSTRUMENT(containing_type, lock_type)
97 
98 // Declares a singleton fbl::Mutex with the name |name|.
99 //
100 // Example usage:
101 //
102 //  DECLARE_SINGLETON_MUTEX(MyGlobalLock [, LockFlags]);
103 //
104 #define DECLARE_SINGLETON_MUTEX(name, ...) \
105     LOCK_DEP_SINGLETON_LOCK(name, fbl::Mutex, ##__VA_ARGS__)
106 
107 // Declares a singleton |lock_type| with the name |name|.
108 //
109 // Example usage:
110 //
111 //  DECLARE_SINGLETON_LOCK(MyGlobalLock, LockType, [, LockFlags]);
112 //
113 #define DECLARE_SINGLETON_LOCK(name, lock_type, ...) \
114     LOCK_DEP_SINGLETON_LOCK(name, lock_type, ##__VA_ARGS__)
115 
116 // Forward declaration.
117 struct MutexPolicy;
118 
119 namespace fbl {
120 
121 // Forward declaration. In the kernel this header is included by fbl/mutext.h.
122 class Mutex;
123 
124 // Configure Guard<fbl::Mutex> to use the following policy. This must be done
125 // in the same namespace as the mutex type.
126 LOCK_DEP_POLICY(Mutex, MutexPolicy);
127 
128 } // namespace fbl
129 
130 // Lock policy for acquiring an fbl::Mutex.
131 struct MutexPolicy {
132     // No extra state required for mutexes.
133     struct State {};
134 
135     // Basic acquire and release operations.
136     template <typename LockType>
AcquireMutexPolicy137     static bool Acquire(LockType* lock, State*) TA_ACQ(lock) {
138         lock->Acquire();
139         return true;
140     }
141     template <typename LockType>
ReleaseMutexPolicy142     static void Release(LockType* lock, State*) TA_REL(lock) {
143         lock->Release();
144     }
145 
146     // A enum tag that can be passed to Guard<fbl::Mutex>::Release(...) to
147     // select the special-case release method below.
148     enum SelectThreadLockHeld { ThreadLockHeld };
149 
150     // Specifies whether the special-case release method below should
151     // reschedule.
152     enum RescheduleOption : bool {
153         NoReschedule = false,
154         Reschedule = true,
155     };
156 
157     // Releases the lock using the special mutex release operation. This
158     // is selected by calling:
159     //
160     //  Guard<fbl::Mutex>::Release(ThreadLockHeld [, Reschedule | NoReschedule])
161     //
162     template <typename LockType>
163     static void Release(LockType* lock, State*, SelectThreadLockHeld,
164                         RescheduleOption reschedule = Reschedule)
165         TA_NO_THREAD_SAFETY_ANALYSIS {
166         mutex_release_thread_locked(lock->GetInternal(), reschedule);
167     }
168 };
169 
170 #endif // __cplusplus
171