SuperTinyKernel™ RTOS 1.08.x
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk_sync_mutex.h
Go to the documentation of this file.
1/*
2 * SuperTinyKernel(TM) RTOS: Lightweight High-Performance Deterministic C++ RTOS for Embedded Systems.
3 *
4 * Source: https://github.com/SuperTinyKernel-RTOS
5 *
6 * Copyright (c) 2022-2026 Neutron Code Limited <stk@neutroncode.com>. All Rights Reserved.
7 * License: MIT License, see LICENSE for a full text.
8 */
9
10#ifndef STK_SYNC_MUTEX_H_
11#define STK_SYNC_MUTEX_H_
12
13#include "stk_sync_cs.h"
14
18
19namespace stk {
20namespace sync {
21
54class Mutex final : private SyncObjectBase, public IMutex, public ITraceable
55{
56public:
60 {}
61
68 {
69 STK_ASSERT(m_wait_list.IsEmpty()); // API contract: must not be destroyed with waiting tasks
70 }
71
78 bool TimedLock(Timeout timeout_ticks);
79
83 void Lock() override { STK_UNUSED(TimedLock(WAIT_INFINITE)); }
84
89 bool TryLock() { return TimedLock(NO_WAIT); }
90
94 void Unlock() override;
95
99 TId GetOwner() const { return m_owner_tid; }
100
101private:
103
104 static const uint16_t RECURSION_MAX = 0xFFFEU;
105
108};
109
110// ---------------------------------------------------------------------------
111// TimedLock
112// ---------------------------------------------------------------------------
113
114inline bool Mutex::TimedLock(Timeout timeout_ticks)
115{
117 const TId current_tid = svc->GetTid();
118
120
121 const TId owner_tid = m_owner_tid;
122 bool success = false;
123
124 STK_ASSERT(current_tid != TID_NONE); // API contract: must be called inside STK task
125
126 // recursive path: already owned by the calling thread
127 if ((m_recursion_count != 0U) && (owner_tid == current_tid))
128 {
129 STK_ASSERT(m_recursion_count < RECURSION_MAX); // API contract: caller must not exceed max recursion depth
130
131 m_recursion_count = static_cast<uint16_t>(m_recursion_count + 1U);
132 success = true;
133 }
134 // fast path: mutex is free
135 else if (m_recursion_count == 0U)
136 {
137 // kernel invariant: counter is zero so owner must be TID_NONE
138 if (owner_tid != TID_NONE)
139 {
141 }
142
144 m_owner_tid = current_tid;
145 __stk_full_memfence();
146
147 success = true;
148 }
149 // slow path: block until available or timeout expires
150 else if (timeout_ticks != NO_WAIT)
151 {
152 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR for a blocking call
153
154 // boost priority of the owner to avoid priority inversion (in case of SwitchStrategyFixedPriority,
155 // otherwise ignored by the kernel), noop if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
156 svc->InheritWeight(owner_tid, GetUserTaskFromTid(current_tid)->GetWeight());
157
158 // mutex owned by another thread (slow path/blocking)
159 if (svc->Wait(this, &cs_, timeout_ticks) == WAIT_RESULT_TIMEOUT)
160 {
161 // if owner did not change, undo priority boost to avoid stuck elevated priority: lookup for a
162 // higher weight within existing wait objects, noop if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
163 if (owner_tid == m_owner_tid)
164 {
165 svc->RestoreWeight(owner_tid, this);
166 }
167
168 success = false;
169 }
170 else
171 {
172 // kernel invariant: if either condition is false, the low-level lock and the
173 // recursion counter are out of sync, this is an internal defect, not a caller error
174 if ((m_owner_tid != current_tid) || (m_recursion_count != 1U))
175 {
177 }
178
179 success = true;
180 }
181 }
182 // try-lock variant: owned by someone else, but no-wait requested
183 else
184 {
185 // success is false already, noop
186 }
187
188 return success;
189}
190
191// ---------------------------------------------------------------------------
192// Unlock
193// ---------------------------------------------------------------------------
194
195inline void Mutex::Unlock()
196{
197 const ScopedCriticalSection cs_;
198
200 (m_owner_tid != TID_NONE)); // API contract: caller must own the lock
201 STK_ASSERT(m_recursion_count != 0U); // API contract: must have matching Lock()
202
203 m_recursion_count = static_cast<uint16_t>(m_recursion_count - 1U);
204
205 if (m_recursion_count == 0U)
206 {
208
209 // restore priority of the owner, noop if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
210 if (m_owner_tid != TID_NONE)
211 {
213 }
214
215 if (!m_wait_list.IsEmpty())
216 {
217 // pass ownership directly to the first waiter (FIFO order)
219
220 // transfer ownership to the waiter
222 m_owner_tid = waiter->GetTid();
223 __stk_full_memfence();
224
225 // wake up
226 waiter->Wake(false);
227
228 // boost priority from the highest-priority task currently in wait list,
229 // noop if the list is empty or if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
232 }
233 else
234 {
235 // free completely if there are no waiters
237 __stk_full_memfence();
238 }
239 }
240}
241
242} // namespace sync
243} // namespace stk
244
245#endif /* STK_SYNC_MUTEX_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:715
#define STK_NONCOPYABLE_CLASS(TYPE)
Disables copy construction and assignment for a class.
Definition stk_defs.h:708
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:516
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:261
Implementation of synchronization primitive: stk::sync::ScopedCriticalSection.
Namespace of STK package.
static constexpr ITask * GetUserTaskFromTid(TId task_id) noexcept
Get task instance from its identifier.
Definition stk_arch.h:725
static constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:217
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:124
@ KERNEL_PANIC_ASSERT
Internal assertion failed (maps from STK_ASSERT).
Definition stk_common.h:62
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:153
static void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:183
static constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:211
static TId GetTid()
Get task/thread Id of the calling task.
Definition stk_helper.h:358
static constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:205
Word TId
Task (thread) id.
Definition stk_common.h:148
bool IsInsideISR()
Check whether the CPU is currently executing inside a hardware interrupt service routine (ISR).
Synchronization primitives for task coordination and resource protection.
Wait object.
Definition stk_common.h:462
virtual TId GetTid() const =0
Get thread Id of the task owning .
virtual void Wake(bool timeout)=0
Wake task.
Traceable object.
Definition stk_common.h:511
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:333
Interface for mutex synchronization primitive.
Definition stk_common.h:697
virtual TId GetTid() const =0
Get thread Id of the currently running task.
virtual void InheritWeight(TId tid, Weight weight)=0
Inherit weight for the task.
static IKernelService * GetInstance()
Get CPU-local instance of the kernel service.
virtual EWaitResult Wait(ISyncObject *sobj, IMutex *mutex, Timeout timeout)=0
Put calling process into a waiting state until synchronization object is signaled or timeout occurs.
virtual void RestoreWeight(TId tid, ISyncObject *sobj=nullptr)=0
Restore weight of the task to the original value.
SyncObjectBase()
Constructor.
Definition stk_helper.h:271
IWaitObject::ListHeadType m_wait_list
Tasks blocked on this object.
Definition stk_helper.h:294
friend class IKernelService
Definition stk_helper.h:249
static __stk_forceinline TTargetType * ListEntryToParent(TSourceType *const lentry)
Safely casts an intrusive list entry to its concrete parent container object type.
RAII-style low-level synchronization primitive for atomic code execution. Used as building brick for ...
Definition stk_sync_cs.h:54
bool TimedLock(Timeout timeout_ticks)
Acquire lock.
TId m_owner_tid
thread id of the current owner
~Mutex()
Destructor.
Mutex()
Constructor.
bool TryLock()
Acquire the lock.
TId GetOwner() const
Get owner of the mutex.
void Unlock() override
Release lock.
uint16_t m_recursion_count
recursion depth
void Lock() override
Acquire lock.
static const uint16_t RECURSION_MAX
maximum nesting depth