-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPreemptiveMutex.cpp
More file actions
135 lines (110 loc) · 3.27 KB
/
Copy pathPreemptiveMutex.cpp
File metadata and controls
135 lines (110 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**************************** PreemptiveMutex *******************************
Adapted from the PDI framework (Portable Device Interface stack).
Reference / inspiration : https://github.com/Suraj151/pdi-framework
This is free software. You can redistribute it and/or modify it but without any
warranty.
Author : Suraj I.
Created Date : 1st June 2025
******************************************************************************/
#include "PreemptiveMutex.h"
PreemptiveMutex::PreemptiveMutex() : m_locked(false), m_owner(nullptr) {
m_waiter_count = 0;
for (uint8_t i = 0; i < PREEMPT_MAX_TASKS; ++i) m_waiters[i] = nullptr;
}
PreemptiveMutex::~PreemptiveMutex() {
// Release any parked waiters so they don't dangle.
while (m_waiter_count > 0) {
PreemptiveTask* t = m_waiters[0];
for (uint8_t i = 1; i < m_waiter_count; ++i) m_waiters[i - 1] = m_waiters[i];
m_waiter_count--;
preemptive_scheduler.add_to_ready(t);
}
m_locked = false;
m_owner = nullptr;
}
/**
* Acquire the mutex, or park the caller on the FIFO waiter list if it is held.
*/
void PreemptiveMutex::lock() {
PREEMPT_CRITICAL_ENTER
// Only meaningful from a task context.
if (!preemptive_scheduler.current) {
PREEMPT_CRITICAL_EXIT
return;
}
if (!m_locked) {
m_locked = true;
m_owner = preemptive_scheduler.current;
PREEMPT_CRITICAL_EXIT
return;
}
// Re-entrant: same task already owns it.
if (preemptive_scheduler.current == m_owner) {
PREEMPT_CRITICAL_EXIT
return;
}
// Queue and park this task until unlock() wakes it.
if (m_waiter_count < PREEMPT_MAX_TASKS) {
m_waiters[m_waiter_count++] = preemptive_scheduler.current;
}
preemptive_scheduler.mute();
PREEMPT_CRITICAL_EXIT
}
/**
* Release the mutex. Ownership passes directly to the next FIFO waiter.
*/
void PreemptiveMutex::unlock() {
PREEMPT_CRITICAL_ENTER
// Only the owner may unlock.
if (preemptive_scheduler.current != m_owner) {
PREEMPT_CRITICAL_EXIT
return;
}
if (m_waiter_count > 0) {
PreemptiveTask* t = m_waiters[0];
for (uint8_t i = 1; i < m_waiter_count; ++i) m_waiters[i - 1] = m_waiters[i];
m_waiter_count--;
m_owner = t; // hand ownership over
preemptive_scheduler.add_to_ready(t); // wake it
} else {
m_locked = false;
m_owner = nullptr;
}
PREEMPT_CRITICAL_EXIT
}
/**
* lock() then disable interrupts.
*/
void PreemptiveMutex::critical_lock() {
lock();
noInterrupts();
}
/**
* Re-enable interrupts then unlock().
*/
void PreemptiveMutex::critical_unlock() {
interrupts();
unlock();
}
/**
* Best-effort acquire. Returns true iff acquired; never parks the caller.
*/
bool PreemptiveMutex::try_lock() {
PREEMPT_CRITICAL_ENTER
if (!preemptive_scheduler.current) {
PREEMPT_CRITICAL_EXIT
return false;
}
if (!m_locked) {
m_locked = true;
m_owner = preemptive_scheduler.current;
PREEMPT_CRITICAL_EXIT
return true;
}
if (preemptive_scheduler.current == m_owner) {
PREEMPT_CRITICAL_EXIT
return true;
}
PREEMPT_CRITICAL_EXIT
return false;
}