SuperTinyKernel™ RTOS 1.06.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 ISyncObject, 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 // recursive path: already owned by the calling thread
125 if ((m_recursion_count != 0U) && (owner_tid == current_tid))
126 {
127 STK_ASSERT(m_recursion_count < RECURSION_MAX); // API contract: caller must not exceed max recursion depth
128
129 m_recursion_count = static_cast<uint16_t>(m_recursion_count + 1U);
130 success = true;
131 }
132 // fast path: mutex is free
133 else if (m_recursion_count == 0U)
134 {
135 // kernel invariant: counter is zero so owner must be TID_NONE
136 if (owner_tid != TID_NONE)
137 {
139 }
140
142 m_owner_tid = current_tid;
143 __stk_full_memfence();
144
145 success = true;
146 }
147 // slow path: block until available or timeout expires
148 else if (timeout_ticks != NO_WAIT)
149 {
150 STK_ASSERT(!hw::IsInsideISR()); // API contract: caller must not be in ISR for a blocking call
151
152 // boost priority of the owner to avoid priority inversion (in case of SwitchStrategyFixedPriority,
153 // otherwise ignored by the kernel), noop if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
154 svc->InheritWeight(owner_tid, GetUserTaskFromTid(current_tid)->GetWeight());
155
156 // mutex owned by another thread (slow path/blocking)
157 if (svc->Wait(this, &cs_, timeout_ticks) == WAIT_RESULT_TIMEOUT)
158 {
159 // if owner did not change, undo priority boost to avoid stuck elevated priority: lookup for a
160 // higher weight within existing wait objects, noop if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
161 if (owner_tid == m_owner_tid)
162 {
163 svc->RestoreWeight(owner_tid, this);
164 }
165
166 success = false;
167 }
168 else
169 {
170 // kernel invariant: if either condition is false, the low-level lock and the
171 // recursion counter are out of sync, this is an internal defect, not a caller error
172 if ((m_owner_tid != current_tid) || (m_recursion_count != 1U))
173 {
175 }
176
177 success = true;
178 }
179 }
180 // try-lock variant: owned by someone else, but no-wait requested
181 else
182 {
183 // success is false already, noop
184 }
185
186 return success;
187}
188
189// ---------------------------------------------------------------------------
190// Unlock
191// ---------------------------------------------------------------------------
192
193inline void Mutex::Unlock()
194{
195 const ScopedCriticalSection cs_;
196
197 STK_ASSERT(m_owner_tid == GetTid()); // API contract: caller must own the lock
198 STK_ASSERT(m_recursion_count != 0U); // API contract: must have matching Lock()
199
200 m_recursion_count = static_cast<uint16_t>(m_recursion_count - 1U);
201
202 if (m_recursion_count == 0U)
203 {
205
206 // restore priority of the owner, noop if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
208
209 if (!m_wait_list.IsEmpty())
210 {
211 // pass ownership directly to the first waiter (FIFO order)
213
214 // transfer ownership to the waiter
216 m_owner_tid = waiter->GetTid();
217 __stk_full_memfence();
218
219 // wake up
220 waiter->Wake(false);
221
222 // boost priority from the highest-priority task currently in wait list,
223 // noop if the list is empty or if ISwitchStrategy::PRIORITY_INHERITANCE_API = 0
226 }
227 else
228 {
229 // free completely if there are no waiters
231 __stk_full_memfence();
232 }
233 }
234}
235
236} // namespace sync
237} // namespace stk
238
239#endif /* STK_SYNC_MUTEX_H_ */
#define STK_UNUSED(X)
Explicitly marks a variable as unused to suppress compiler warnings.
Definition stk_defs.h:608
#define STK_NONCOPYABLE_CLASS(TYPE)
Disables copy construction and assignment for a class.
Definition stk_defs.h:601
#define STK_ASSERT(e)
Runtime assertion. Halts execution if the expression e evaluates to false.
Definition stk_defs.h:409
#define STK_VIRT_DTOR
Makes destructors virtual and compliant to strict rules if STK_STRICT_COMPLIANCY=0.
Definition stk_defs.h:159
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:532
constexpr Timeout NO_WAIT
Timeout value: return immediately if the synchronization object is not yet signaled (non-blocking pol...
Definition stk_common.h:210
int32_t Timeout
Timeout time (ticks).
Definition stk_common.h:146
static __stk_forceinline void STK_KERNEL_PANIC(stk::EKernelPanicId id)
Called when the kernel detects an unrecoverable internal fault.
Definition stk_arch.h:75
@ WAIT_RESULT_TIMEOUT
The wake was caused by a timeout expiry.
Definition stk_common.h:126
constexpr Timeout WAIT_INFINITE
Timeout value: block indefinitely until the synchronization object is signaled.
Definition stk_common.h:204
static TId GetTid()
Get task/thread Id of the calling task.
Definition stk_helper.h:237
constexpr TId TID_NONE
Reserved task/thread id representing zero/none thread id.
Definition stk_common.h:198
Word TId
Task (thread) id.
Definition stk_common.h:141
@ KERNEL_PANIC_ASSERT
Internal assertion failed (maps from STK_ASSERT).
Definition stk_common.h:68
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:362
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:410
IWaitObject::ListHeadType m_wait_list
tasks blocked on this object
Definition stk_common.h:605
ISyncObject()
Constructor.
Definition stk_common.h:562
Weight FindWeightHigherThan(Weight comp) const
Find higher weight within linked wait objects.
Definition stk_helper.h:208
Interface for mutex synchronization primitive.
Definition stk_common.h:613
Interface for the kernel services exposed to the user processes during run-time when Kernel started s...
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.
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