roo_threads
API Documentation for roo_threads
Loading...
Searching...
No Matches
condition_variable_opt.cpp
Go to the documentation of this file.
2
3#ifdef ROO_THREADS_USE_FREERTOS
4
5#include <assert.h>
6
7namespace roo_threads {
8namespace freertos {
9
10#if (defined(ESP32) || defined(ESP8266) || defined(ESP_PLATFORM)) && defined(configNUM_CORES)
11#if configNUM_CORES > 1
12static portMUX_TYPE s_cond_lock = portMUX_INITIALIZER_UNLOCKED;
13#define condENTER_CRITICAL() portENTER_CRITICAL(&s_cond_lock)
14#define condEXIT_CRITICAL() portEXIT_CRITICAL(&s_cond_lock)
15#else
16#define condENTER_CRITICAL() vPortEnterCritical()
17#define condEXIT_CRITICAL() vPortExitCritical()
18#endif
19#else
20#define condENTER_CRITICAL() portENTER_CRITICAL()
21#define condEXIT_CRITICAL() portEXIT_CRITICAL()
22#endif
23
24condition_variable_opt::condition_variable_opt() noexcept {
25 for (int i = 0; i < kMaxWaitingThreads; ++i) {
26 tasks_waiting_[i] = nullptr;
27 }
28}
29
30void condition_variable_opt::notify_one() noexcept {
31 TaskHandle_t* task_to_notify = nullptr;
32 condENTER_CRITICAL();
33 for (int i = 0; i < kMaxWaitingThreads; ++i) {
34 if (tasks_waiting_[i] != nullptr) {
35 if (task_to_notify == nullptr ||
36 uxTaskPriorityGet(*task_to_notify) <
37 uxTaskPriorityGet(tasks_waiting_[i])) {
38 task_to_notify = &tasks_waiting_[i];
39 }
40 }
41 }
42 if (task_to_notify != nullptr) {
43 xTaskNotify(*task_to_notify, 0, eNoAction);
44 *task_to_notify = nullptr;
45 }
46 condEXIT_CRITICAL();
47}
48
49void condition_variable_opt::notify_all() noexcept {
50 condENTER_CRITICAL();
51 for (int i = 0; i < kMaxWaitingThreads; ++i) {
52 if (tasks_waiting_[i] != nullptr) {
53 xTaskNotify(tasks_waiting_[i], 0, eNoAction);
54 tasks_waiting_[i] = nullptr;
55 }
56 }
57 condEXIT_CRITICAL();
58}
59
60void condition_variable_opt::wait(unique_lock<mutex>& lock) noexcept {
61 TaskHandle_t me = xTaskGetCurrentTaskHandle();
62 bool queued = false;
63 condENTER_CRITICAL();
64 for (int i = 0; i < kMaxWaitingThreads; ++i) {
65 if (tasks_waiting_[i] == nullptr) {
66 tasks_waiting_[i] = me;
67 queued = true;
68 break;
69 }
70 }
71 lock.unlock();
72 condEXIT_CRITICAL();
73 assert(queued); // Checks for maximum number of queued threads reached.
74
75 // Wait on the condition variable.
76 // bool signaled =
77 xTaskNotifyWait(0, 0, nullptr, portMAX_DELAY); // == pdPASS;
78 lock.lock();
79 condENTER_CRITICAL();
80 for (int i = 0; i < kMaxWaitingThreads; ++i) {
81 if (tasks_waiting_[i] == me) {
82 tasks_waiting_[i] = nullptr;
83 break;
84 }
85 }
86 condEXIT_CRITICAL();
87}
88
89cv_status condition_variable_opt::wait_until_impl(unique_lock<mutex>& lock,
90 TickType_t when) noexcept {
91 TickType_t now = xTaskGetTickCount();
92 TickType_t delay = when - now;
93 if (delay == 0 || delay > internal::kMaxTicksDelay) {
94 return cv_status::timeout;
95 }
96 TaskHandle_t me = xTaskGetCurrentTaskHandle();
97 bool queued = false;
98 condENTER_CRITICAL();
99 for (int i = 0; i < kMaxWaitingThreads; ++i) {
100 if (tasks_waiting_[i] == nullptr) {
101 tasks_waiting_[i] = me;
102 queued = true;
103 break;
104 }
105 }
106 lock.unlock();
107 condEXIT_CRITICAL();
108 cv_status status = cv_status::timeout;
109 assert(queued); // Checks for maximum number of queued threads reached.
110 // Wait on the condition variable.
111 while (true) {
112 bool signaled = (xTaskNotifyWait(0, 0, nullptr, delay) == pdPASS);
113 if (signaled) {
114 status = cv_status::no_timeout;
115 break;
116 }
117 TickType_t now = xTaskGetTickCount();
118 delay = when - now;
119 if (delay == 0 || delay > internal::kMaxTicksDelay) break;
120 }
121 lock.lock();
122 condENTER_CRITICAL();
123 for (int i = 0; i < kMaxWaitingThreads; ++i) {
124 if (tasks_waiting_[i] == me) {
125 tasks_waiting_[i] = nullptr;
126 break;
127 }
128 }
129 condEXIT_CRITICAL();
130 return status;
131}
132
133} // namespace freertos
134} // namespace roo_threads
135
136#endif // ROO_THREADS_USE_FREERTOS
cv_status
Status returned from timed wait operations.