Skip to content

Commit 12cba7a

Browse files
utsavm9kartben
authored andcommitted
portability: cmsis: Bugfix osThreadFlagsWait behavior
The osFlagsWaitAny option is not handled correctly. It returns once any flag at all is set, whereas it is supposed to only return once one of the flags specified in flags is set. Signed-off-by: Utsav Munendra <[email protected]>
1 parent 6127264 commit 12cba7a

File tree

2 files changed

+97
-26
lines changed

2 files changed

+97
-26
lines changed

subsys/portability/cmsis_rtos_v2/thread_flags.c

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
109109

110110
time_stamp_start = (uint64_t)k_cycle_get_32();
111111

112+
sig = tid->signal_results & flags;
113+
114+
if (options & osFlagsWaitAll) {
115+
/* Check if all events we are waiting on have
116+
* been signalled
117+
*/
118+
if (sig == flags) {
119+
break;
120+
}
121+
} else {
122+
/* Check if any events we are waiting on have
123+
* been signalled
124+
*/
125+
if (sig != 0) {
126+
break;
127+
}
128+
}
129+
112130
switch (timeout) {
113131
case 0:
114132
retval = k_poll(&tid->poll_event, 1, K_NO_WAIT);
@@ -138,40 +156,27 @@ uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
138156
tid->poll_event.signal->signaled = 0U;
139157
tid->poll_event.state = K_POLL_STATE_NOT_READY;
140158

141-
if (options & osFlagsWaitAll) {
142-
/* Check if all events we are waiting on have
143-
* been signalled
144-
*/
145-
if ((tid->signal_results & flags) == flags) {
146-
break;
147-
}
159+
/* If we need to wait on more signals, we need to
160+
* adjust the timeout value accordingly based on
161+
* the time that has already elapsed.
162+
*/
163+
hwclk_cycles_delta = (uint64_t)k_cycle_get_32() - time_stamp_start;
148164

149-
/* If we need to wait on more signals, we need to
150-
* adjust the timeout value accordingly based on
151-
* the time that has already elapsed.
152-
*/
153-
hwclk_cycles_delta = (uint64_t)k_cycle_get_32() - time_stamp_start;
154-
155-
time_delta_ns = (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta);
165+
time_delta_ns = (uint32_t)k_cyc_to_ns_floor64(hwclk_cycles_delta);
156166

157-
time_delta_ms = (uint32_t)time_delta_ns / NSEC_PER_MSEC;
167+
time_delta_ms = (uint32_t)time_delta_ns / NSEC_PER_MSEC;
158168

159-
if (timeout_ms > time_delta_ms) {
160-
timeout_ms -= time_delta_ms;
161-
} else {
162-
timeout_ms = 0U;
163-
}
169+
if (timeout_ms > time_delta_ms) {
170+
timeout_ms -= time_delta_ms;
164171
} else {
165-
break;
172+
timeout_ms = 0U;
166173
}
167174
}
168175

169-
sig = tid->signal_results;
170176
if (!(options & osFlagsNoClear)) {
171-
172177
/* Clear signal flags as the thread is ready now */
173178
key = irq_lock();
174-
tid->signal_results &= ~(flags);
179+
tid->signal_results &= ~(sig);
175180
irq_unlock(key);
176181
}
177182

tests/subsys/portability/cmsis_rtos_v2/src/thread_flags.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66

77
#include <zephyr/ztest.h>
88
#include <zephyr/kernel.h>
9-
#include <cmsis_os2.h>
9+
#include <zephyr/portability/cmsis_os2.h>
10+
#include <zephyr/portability/cmsis_types.h>
1011

1112
#include <zephyr/irq_offload.h>
1213
#include <zephyr/kernel_structs.h>
1314

14-
#define TIMEOUT_TICKS (10)
15+
#define TIMEOUT_TICKS (1000)
1516
#define FLAG1 (0x00000020)
1617
#define FLAG2 (0x00000004)
18+
#define FLAG3 (0x00000100)
1719
#define FLAG (FLAG1 | FLAG2)
1820
#define ISR_FLAG (0x50)
1921
#define STACKSZ CONFIG_CMSIS_V2_THREAD_MAX_STACK_SIZE
@@ -34,6 +36,10 @@ static void thread1(void *arg)
3436
flags = osThreadFlagsGet();
3537
zassert_equal(flags & FLAG1, FLAG1, "");
3638

39+
/* We should be able to get the exact same flags again as they were not cleared */
40+
flags = osThreadFlagsWait(FLAG1, osFlagsWaitAny | osFlagsNoClear, 0);
41+
zassert_equal(flags & FLAG1, FLAG1, "");
42+
3743
/* Clear the Flag explicitly */
3844
flags = osThreadFlagsClear(FLAG1);
3945
zassert_not_equal(flags, osFlagsErrorParameter, "ThreadFlagsClear failed");
@@ -161,4 +167,64 @@ ZTEST(cmsis_thread_flags, test_thread_flags_isr)
161167

162168
osDelay(TIMEOUT_TICKS);
163169
}
170+
171+
static K_THREAD_STACK_DEFINE(test_stack4, STACKSZ);
172+
static struct cmsis_rtos_thread_cb test_cb4;
173+
static osThreadAttr_t thread4_attr = {
174+
.name = "Thread4",
175+
.cb_mem = &test_cb4,
176+
.cb_size = sizeof(test_cb4),
177+
.stack_mem = &test_stack4,
178+
.stack_size = STACKSZ,
179+
.priority = osPriorityHigh,
180+
};
181+
static bool m_thread_4_is_blocked;
182+
183+
static void thread4(void *arg)
184+
{
185+
uint32_t flags;
186+
187+
/* Nothing will trigger FLAG1 to this thread, so the following should timeout */
188+
flags = osThreadFlagsWait(FLAG1, osFlagsWaitAny, 0);
189+
zassert_equal(flags, osFlagsErrorTimeout,
190+
"ThreadFlagsWait unexpected found 0x%x flags were set");
191+
192+
flags = osThreadFlagsWait(FLAG1, osFlagsWaitAll, TIMEOUT_TICKS / 10);
193+
zassert_equal(flags, osFlagsErrorTimeout,
194+
"ThreadFlagsWait unexpected found 0x%x flags were set");
195+
196+
flags = osThreadFlagsWait(FLAG1, osFlagsWaitAny | osFlagsNoClear, 0);
197+
zassert_equal(flags, osFlagsErrorTimeout,
198+
"ThreadFlagsWait unexpected found 0x%x flags were set");
199+
200+
/* Nothing will trigger FLAG1 to this thread, so it should remain blocked here */
201+
m_thread_4_is_blocked = true;
202+
flags = osThreadFlagsWait(FLAG1, osFlagsWaitAny, osWaitForever);
203+
zassert_unreachable();
204+
}
205+
206+
ZTEST(cmsis_thread_flags, test_thread_flags_set_flags_not_waited_upon)
207+
{
208+
osThreadId_t id;
209+
uint32_t flags;
210+
211+
m_thread_4_is_blocked = false;
212+
213+
id = osThreadNew(thread4, NULL, &thread4_attr);
214+
zassert_true(id != NULL, "Failed creating thread3");
215+
216+
/* The thread will wait on any of FLAG1. Signal something it is not waiting for. */
217+
flags = osThreadFlagsSet(id, FLAG3);
218+
zassert_equal(flags & FLAG3, FLAG3, "");
219+
osThreadYield();
220+
221+
/* Wait a bit, but thread4 should remain blocked */
222+
osDelay(TIMEOUT_TICKS);
223+
224+
zassert_true(m_thread_4_is_blocked, "Thread 4 did run till expected point");
225+
226+
/* Kill the thread */
227+
osThreadTerminate(id);
228+
}
229+
164230
ZTEST_SUITE(cmsis_thread_flags, NULL, NULL, NULL, NULL, NULL);

0 commit comments

Comments
 (0)