File syn_event_flags.c¶
File List > sched > syn_event_flags.c
Go to the documentation of this file
#include "syn_event_flags.h"
#include "../port/syn_port_system.h"
SYN_Status syn_event_flags_init(SYN_EventFlags *ef)
{
if (!ef)
return SYN_INVALID_PARAM;
ef->flags = 0;
return SYN_OK;
}
/*
* set/clear/wait are callable from both ISR and task context. `volatile`
* alone does not make |= / &= atomic (LDR+ORR/BIC+STR on Cortex-M), so a
* preempting ISR's flag update can be lost to a stale read-modify-write.
* Critical sections make the RMW atomic; syn_port_enter_critical() nests.
*/
SYN_Status syn_event_flags_set(SYN_EventFlags *ef, uint32_t flags_mask)
{
if (!ef)
return SYN_INVALID_PARAM;
syn_port_enter_critical();
ef->flags |= flags_mask;
syn_port_exit_critical();
return SYN_OK;
}
SYN_Status syn_event_flags_clear(SYN_EventFlags *ef, uint32_t flags_mask)
{
if (!ef)
return SYN_INVALID_PARAM;
syn_port_enter_critical();
ef->flags &= ~flags_mask;
syn_port_exit_critical();
return SYN_OK;
}
uint32_t syn_event_flags_get(const SYN_EventFlags *ef)
{
if (!ef)
return 0;
return ef->flags;
}
SYN_Status syn_event_flags_wait(SYN_EventFlags *ef, uint32_t wait_mask, uint32_t mode,
uint32_t *out_flags)
{
if (!ef || wait_mask == 0)
return SYN_INVALID_PARAM;
/* Read and auto-clear must be one atomic unit: an ISR setting an
* unrelated bit between them would be clobbered by the stale RMW. */
syn_port_enter_critical();
uint32_t current = ef->flags;
uint32_t matched = current & wait_mask;
bool satisfied = false;
if (mode & SYN_EVENT_FLAGS_WAIT_ALL) {
satisfied = (matched == wait_mask);
} else {
/* Default to WAIT_ANY */
satisfied = (matched != 0);
}
if (!satisfied) {
syn_port_exit_critical();
return SYN_BUSY; /* Condition not yet satisfied */
}
if (mode & SYN_EVENT_FLAGS_AUTO_CLEAR) {
ef->flags &= ~matched;
}
syn_port_exit_critical();
if (out_flags) {
*out_flags = matched;
}
return SYN_OK;
}