Skip to content

Commit 17e12fc

Browse files
maribubenpicco
authored andcommitted
core/thread_flags: add thread_flags_wait_any_or_mbox()
The new function blocks until either any of given set of flags is set or a message was fetch from the given mbox - whatever comes first.
1 parent d2fe58e commit 17e12fc

File tree

6 files changed

+114
-6
lines changed

6 files changed

+114
-6
lines changed

core/include/mbox.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
#ifndef MBOX_H
2323
#define MBOX_H
2424

25-
#include "list.h"
2625
#include "cib.h"
26+
#include "list.h"
2727
#include "msg.h"
2828

2929
#ifdef __cplusplus

core/include/sched.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ typedef enum {
170170
STATUS_REPLY_BLOCKED, /**< waiting for a message response */
171171
STATUS_FLAG_BLOCKED_ANY, /**< waiting for any flag from flag_mask */
172172
STATUS_FLAG_BLOCKED_ALL, /**< waiting for all flags in flag_mask */
173+
STATUS_FLAG_MBOX_BLOCKED, /**< waiting for any flag or an mbox msg */
173174
STATUS_MBOX_BLOCKED, /**< waiting for get/put on mbox */
174175
STATUS_COND_BLOCKED, /**< waiting for a condition variable */
175176
STATUS_RUNNING, /**< currently running */

core/include/thread_flags.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#define THREAD_FLAGS_H
5959

6060
#include "sched.h" /* for thread_t typedef */
61+
#include "mbox.h"
6162

6263
#ifdef __cplusplus
6364
extern "C" {
@@ -101,6 +102,10 @@ extern "C" {
101102
* @see xtimer_set_timeout_flag
102103
*/
103104
#define THREAD_FLAG_TIMEOUT (1u << 14)
105+
/**
106+
* @brief Flag used to wake @ref thread_flags_wait_any_or_mbox
107+
*/
108+
#define THREAD_FLAG_MBOX_READY (1u << 13)
104109

105110
/**
106111
* @brief Comprehensive set of all predefined flags
@@ -170,6 +175,30 @@ thread_flags_t thread_flags_wait_any(thread_flags_t mask);
170175
*/
171176
thread_flags_t thread_flags_wait_all(thread_flags_t mask);
172177

178+
/**
179+
* @brief Wait for any flag or a message via mbox, whatever comes first
180+
*
181+
* @param[in,out] mbox ptr to the mailbox to operate on
182+
* @param[out] msg destination where to store the retrieved message
183+
* @param[in] mask thread_flags mask to wait on
184+
*
185+
* @post Either a thread flag matching @p mask came in, was cleared and the
186+
* value of the cleared flag is returned, or a message was retrieved
187+
* from @p mbox, stored into @p msg and `0` was returned.
188+
*
189+
* @retval 0 A message came in first
190+
* @retval !=0 A flag came in first, the flag was cleared and is retuned
191+
* @return The flags that caused the wake up, or `0` if a message came in first
192+
*
193+
* @note This is only available when module @ref core_mbox is used
194+
*
195+
* @warning This API is not yet ***stable*** and was rushed into a release as
196+
* infrastructure for a bugfix. It is recommended that user do not
197+
* jump on this API as of now.
198+
*/
199+
thread_flags_t thread_flags_wait_any_or_mbox(mbox_t *mbox, msg_t *msg,
200+
thread_flags_t mask);
201+
173202
/**
174203
* @brief Wait for any flags in mask to become set (blocking), one at a time
175204
*

core/mbox.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020

2121
#include <string.h>
2222

23-
#include "mbox.h"
2423
#include "irq.h"
24+
#include "mbox.h"
2525
#include "sched.h"
2626
#include "thread.h"
27+
#include "thread_flags.h"
2728

2829
#define ENABLE_DEBUG 0
2930
#include "debug.h"
@@ -66,10 +67,31 @@ int _mbox_put(mbox_t *mbox, msg_t *msg, int blocking)
6667
if (next) {
6768
DEBUG("mbox: Thread %" PRIkernel_pid " mbox 0x%08x: _tryput(): "
6869
"there's a waiter.\n", thread_getpid(), (unsigned)mbox);
69-
thread_t *thread =
70-
container_of((clist_node_t *)next, thread_t, rq_entry);
71-
*(msg_t *)thread->wait_data = *msg;
72-
_wake_waiter(thread, irqstate);
70+
thread_t *thread = container_of((clist_node_t *)next, thread_t,
71+
rq_entry);
72+
if (!IS_USED(MODULE_CORE_THREAD_FLAGS) ||
73+
(thread->status == STATUS_MBOX_BLOCKED)) {
74+
*(msg_t *)thread->wait_data = *msg;
75+
_wake_waiter(thread, irqstate);
76+
}
77+
else {
78+
while (cib_full(&mbox->cib)) {
79+
if (!blocking) {
80+
/* put thread back into list and give up */
81+
thread_add_to_list(&mbox->readers, thread);
82+
irq_restore(irqstate);
83+
return 0;
84+
}
85+
86+
_wait(&mbox->writers, irqstate);
87+
irqstate = irq_disable();
88+
}
89+
90+
/* copy message to queue and set flags */
91+
mbox->msg_array[cib_put_unsafe(&mbox->cib)] = *msg;
92+
irq_restore(irqstate);
93+
thread_flags_set(thread, THREAD_FLAG_MBOX_READY);
94+
}
7395
return 1;
7496
}
7597
else {

core/thread.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ static const char *state_names[STATUS_NUMOF] = {
341341
[STATUS_REPLY_BLOCKED] = "bl reply",
342342
[STATUS_FLAG_BLOCKED_ANY] = "bl anyfl",
343343
[STATUS_FLAG_BLOCKED_ALL] = "bl allfl",
344+
[STATUS_FLAG_MBOX_BLOCKED] = "bl fl|mbox",
344345
[STATUS_MBOX_BLOCKED] = "bl mbox",
345346
[STATUS_COND_BLOCKED] = "bl cond",
346347
[STATUS_RUNNING] = "running",

core/thread_flags.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@
2020

2121
#include "thread_flags.h"
2222
#include "irq.h"
23+
#include "list.h"
24+
#include "sched.h"
2325
#include "thread.h"
2426

2527
#define ENABLE_DEBUG 0
2628
#include "debug.h"
2729

30+
struct flags_any_or_mbox_data {
31+
mbox_t *mbox;
32+
thread_flags_t flags;
33+
};
34+
2835
static inline int __attribute__((always_inline)) _thread_flags_wake(
2936
thread_t *thread)
3037
{
@@ -38,6 +45,18 @@ static inline int __attribute__((always_inline)) _thread_flags_wake(
3845
case STATUS_FLAG_BLOCKED_ALL:
3946
wakeup = ((thread->flags & mask) == mask);
4047
break;
48+
#ifdef MODULE_CORE_MBOX
49+
case STATUS_FLAG_MBOX_BLOCKED:
50+
{
51+
struct flags_any_or_mbox_data *data = thread->wait_data;
52+
wakeup = thread->flags & data->flags;
53+
if (wakeup) {
54+
list_remove(&data->mbox->readers,
55+
(list_node_t *)&thread->rq_entry);
56+
}
57+
}
58+
break;
59+
#endif
4160
default:
4261
wakeup = 0;
4362
break;
@@ -157,3 +176,39 @@ void thread_flags_set(thread_t *thread, thread_flags_t mask)
157176
irq_restore(state);
158177
}
159178
}
179+
180+
#ifdef MODULE_CORE_MBOX
181+
thread_flags_t thread_flags_wait_any_or_mbox(mbox_t *mbox, msg_t *msg,
182+
thread_flags_t mask)
183+
{
184+
thread_t *me = thread_get_active();
185+
thread_flags_t flags;
186+
187+
struct flags_any_or_mbox_data wait_data = {
188+
.mbox = mbox,
189+
.flags = mask | THREAD_FLAG_MBOX_READY,
190+
};
191+
192+
while (1) {
193+
if (mbox_try_get(mbox, msg)) {
194+
thread_flags_clear(THREAD_FLAG_MBOX_READY);
195+
return 0;
196+
}
197+
198+
flags = _thread_flags_clear_atomic(me, mask);
199+
if (flags) {
200+
return flags;
201+
}
202+
203+
unsigned irqstate = irq_disable();
204+
me->wait_data = &wait_data;
205+
sched_set_status(me, STATUS_FLAG_MBOX_BLOCKED);
206+
thread_add_to_list(&mbox->readers, me);
207+
irq_restore(irqstate);
208+
thread_yield_higher();
209+
irqstate = irq_disable();
210+
sched_set_status(me, STATUS_RUNNING);
211+
irq_restore(irqstate);
212+
}
213+
}
214+
#endif

0 commit comments

Comments
 (0)