Use of Semaphores in KERNEL mode
- Dominant language
- C
- Stars
- 4k
- Forks
- 1.7k
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 237
Description
POSIX semaphores are often used to wait for events: The waiter calls `sem_wait()` then some time later the asynchronous event logic calls `sem_post()` to wake up the waiting thread. This is often interrupt handling logic within the OS kernel code.
An un-named semaphore of type sem_t is typically declared in user-space memory in this case. This works fine in FLAT and PROTECTED builds where the user-space memory is accessible by all applications and by the kernel logic as well. But it will not always work in the KERNEL build mode.
In the KERNEL build mode, each task (aka, "process") has its own protected _address environment_. Typically, only the application logic in that address environment where the semaphore is declared can access data declared in the process address environment. Asynchronous kernel logic can also access that data _if the correct address environment is in place_.
There are always two address environments in place: One for the kernel and one for the currently selected process. The kernel address environment is always in place. But the current process address environment switches from task to task so there is no guarantee that the correct address environment will be in place when an interrupt occurs and the system is running in kernel mode. If the interrupt handler logic then posts to a global semaphore declared in user-space it may correctly post to the semaphore or it may simply corrupt the aliased address in some other address space.
There are a set of functions available for use inside the OS to control the current address environment. These are prototyped in `include/nuttx/addrenv.h` (actually `arch.h`). These functions should be used within the OS to make certain that the correct address environment is in _place_ before posting the semaphore like:
#ifdef CONFIG_ARCH_ADDRENV
save_addrenv_t oldenv;
int ret = up_addrenv_select(newenv, & oldenv);
if (ret >= 0)
{
ret = sem_post(sem);
}
ret = up_addrenv_restore(&oldenv);
#else
ret = sem_post(sem);
#endif
Contributor guide
Assessment
This issue has not been assessed yet.