apache / nuttx

Apache NuttX is a mature, real-time embedded operating system (RTOS)
https://nuttx.apache.org/
Apache License 2.0
2.77k stars 1.15k forks source link

Use of Semaphores in KERNEL mode #2787

Open patacongo opened 3 years ago

patacongo commented 3 years ago

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
patacongo commented 3 years ago

Other OSs do not use semaphores to signal between the OS and applications. That is a behavior unique to NuttX. But how would this handled in other OSs? Most likely via the second parameter to the sem_init() call:

If the pshared argument has a non-zero value, then the semaphore is shared between processes; in this case, any
process that can access the semaphore sem can use sem for performing sem_wait(), sem_trywait(), sem_post(),
and sem_destroy() operations.

The pshared argument is currently ignored in NuttX.