Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 16 additions & 9 deletions core/include/thread_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,26 @@ thread_flags_t thread_flags_wait_all(thread_flags_t mask);
thread_flags_t thread_flags_wait_one(thread_flags_t mask);

/**
* @brief Possibly Wake up thread waiting for flags
*
* Wakes up a thread if it is thread flag blocked and its condition is met.
* Has to be called with interrupts disabled.
* Does not trigger yield.
* @brief Set the flags of the given thread and update its state, but do not
* yield
*
* @internal
*
* @param[in] thread thread to possibly wake up
* @return 1 if @p thread has been woken up
* 0 otherwise
* @warning This is not a stable API intended for external use.
*
* @param[in,out] thread Thread to modify
* @param[in] mask Bitmask containing the flags to set
*
* @retval true The thread in @p thread has changed its state to pending,
* the caller needs to yield
* @retval false The thread in @p has not changed its state. It may already
* be pending or is not waiting on the flags in @p mask
*
* @pre The caller has IRQ disabled.
* @pre @p thread is not `NULL`
* @pre The caller is prepared to yield if this function returns `true`
*/
int thread_flags_wake(thread_t *thread);
bool thread_flags_set_internal(thread_t *thread, thread_flags_t mask);

#ifdef __cplusplus
}
Expand Down
6 changes: 2 additions & 4 deletions core/msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ static int queue_msg(thread_t *target, const msg_t *m)

*dest = *m;
#if MODULE_CORE_THREAD_FLAGS
target->flags |= THREAD_FLAG_MSG_WAITING;
thread_flags_wake(target);
thread_flags_set_internal(target, THREAD_FLAG_MSG_WAITING);
#endif
return 1;
}
Expand Down Expand Up @@ -157,8 +156,7 @@ static int _msg_send(msg_t *m, kernel_pid_t target_pid, bool block,
thread_add_to_list(&(target->msg_waiters), me);

#if MODULE_CORE_THREAD_FLAGS
target->flags |= THREAD_FLAG_MSG_WAITING;
thread_flags_wake(target);
thread_flags_set_internal(target, THREAD_FLAG_MSG_WAITING);
#endif

irq_restore(state);
Expand Down
11 changes: 6 additions & 5 deletions core/thread_flags.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ static inline int __attribute__((always_inline)) _thread_flags_wake(
return wakeup;
}

int thread_flags_wake(thread_t *thread)
{
return _thread_flags_wake(thread);
}

static thread_flags_t _thread_flags_clear_atomic(thread_t *thread,
thread_flags_t mask)
{
Expand Down Expand Up @@ -142,6 +137,12 @@ thread_flags_t thread_flags_wait_all(thread_flags_t mask)
return _thread_flags_clear_atomic(me, mask);
}

bool thread_flags_set_internal(thread_t *thread, thread_flags_t mask)
{
thread->flags |= mask;
return _thread_flags_wake(thread);
}

void thread_flags_set(thread_t *thread, thread_flags_t mask)
{
DEBUG("thread_flags_set(): setting 0x%08x for pid %" PRIkernel_pid "\n",
Expand Down
33 changes: 32 additions & 1 deletion core/thread_flags_group.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,58 @@
* @}
*/

#include <stdbool.h>

#include "bitarithm.h"
#include "irq.h"
#include "thread.h"
#include "thread_flags_group.h"

#define ENABLE_DEBUG 0
#include "debug.h"

void thread_flags_group_set(thread_flags_group_t *group, thread_flags_t mask)
{
/* Interrupts must be disabled because the threads are not ordered by
* priority. */
unsigned irq_state = irq_disable();

DEBUG("thread_flags_group_set(%p, %x):\n", (void *)group, (unsigned)mask);
DEBUG("| TID | Flags | Status (old) | Status (new) |\n");

bool yield = false;
for (kernel_pid_t i = 0; i < (kernel_pid_t)ARRAY_SIZE(group->members); i++) {
unsigned pid_block = group->members[i];
kernel_pid_t const pid_base = i * UINT_WIDTH;
uint8_t pid_offs = 0;

while (pid_block) {
pid_block = bitarithm_test_and_clear(pid_block, &pid_offs);
thread_flags_set(thread_get(pid_base + pid_offs), mask);
kernel_pid_t target_pid = pid_base + pid_offs;
thread_t *target = thread_get(target_pid);
if (!target) {
DEBUG("| %02u | n/a | n/a (dead) | n/a (dead) |\n",
target_pid);
continue;
}
thread_status_t old_status = target->status;
bool awoken = thread_flags_set_internal(target, mask);
thread_status_t new_status = target->status;
/* NOTE: wait_data is shared by thread_flags with other
* mechanisms and may e.g. be a pointer to an `msg_t`.
* Some interpretation of the output is needed by the
* user of the debug output. */
thread_flags_t wait_data = (uint16_t)(uintptr_t)target->wait_data;
DEBUG("| %02u | %04x | %12s | %12s |\n",
(unsigned)target_pid, (unsigned)wait_data,
thread_state_to_string(old_status),
thread_state_to_string(new_status));
yield = yield || awoken;
}
}

irq_restore(irq_state);
if (yield) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't this be called unconditionally?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it will be faster in case all threads of the group either where already pending or not currently actively waiting for one of the flags in mask.

thread_yield_higher();
}
}
Loading