Description
Problem Description
In zephyr, we have drivers and subsystems which may be used pre kernel, post kernel, with and without multithreading. In all of these scenarios, we need thread safety, however, in some of them, thread safety is a given, since we either only have one thread, in cases of pre kernel and no multithreading
This currently leads to drivers and subsystems needing to implement conditional locking themselves, typically only after its discovered that they needed it, as a driver's init level is changed for example.
The logic looks like this:
#if !CONFIG_NO_MULTITHREADING
if (!k_is_pre_kernel()) {
(void)k_sem_take(&mysem, K_FOREVER);
}
#endif
...
#if !CONFIG_NO_MULTITHREADING
if (!k_is_pre_kernel()) {
k_sem_give(&mysem);
}
#endif
We also have the "ISR" thread in any case, which we typically also want to sync with, so an adaptive solution to what follows is proposed as well :)
#if !CONFIG_NO_MULTITHREADING
static K_SEM_DEFINE(mysem, 0, 1);
#else
static atomic_t myatom = ATOM_INIT(0);
#endif
void myisr()
{
#if !CONFIG_NO_MULTITHREADING
k_sem_give(&mysem);
#else
atomic_set_bit(&myatom, 0);
#endif
}
void myapi()
{
#if !CONFIG_NO_MULTITHREADING
k_sem_take(&mysem, K_FOREVER);
#else
!WAIT_FOR(atomic_test_bit(&myatom, 0), 100000, NULL)
#endif
}
Proposed Change (Summary)
This could preferable be packaged into a new feature: The struct k_threadlock
which would make the code look like:
(void)k_threadlock_lock(&mythreadlock, K_FOREVER);
...
k_treadlock_unlock(&mythreadlock)
which would automatically adapt to the build configurations and kernel stage.
As inspired by @mathieuchopstm we could also consider a primitive which automatically adapts to waiting on something from an ISR using threads or polling, namely a k_threadawait() which would look like this:
#if !CONFIG_NO_MULTITHREADING
static K_SEM_DEFINE(mysem, 0, 1);
#else
static atomic_t myatom = ATOM_INIT(0);
#endif
void myisr()
{
#if !CONFIG_NO_MULTITHREADING
k_sem_give(&mysem);
#else
atomic_set_bit(&myatom, 0);
#endif
}
void myapi()
{
#if !CONFIG_NO_MULTITHREADING
k_sem_take(&mysem, K_FOREVER);
#else
!WAIT_FOR(atomic_test_bit(&myatom, 0), 100000, NULL)
#endif
}
with
static struct k_threadawait mythreadawait;
void myisr()
{
k_threadawait_signal(&mythreadawait);
}
void myapi()
{
k_threadawait_await(&mythreadawait, K_FOREVER);
}
Proposed Change (Detailed)
Simply package a k_sem
and use it as a binary sem for locking, if required (!CONFIG_NO_MULTITHREADING). cheap and simple :)
Dependencies
No response
Concerns and Unresolved Questions
No response
Alternatives Considered
What we do now, technically a bit more efficient since we can avoid the check of k_is_pre_kernel() in some cases.
Metadata
Metadata
Assignees
Type
Projects
Status