BeRTOS
signal.c File Reference

IPC signals implementation. More...

#include "signal.h"
#include "cfg/cfg_timer.h"
#include <cfg/debug.h>
#include <cfg/depend.h>
#include <cpu/irq.h>
#include <kern/proc.h>
#include <kern/proc_p.h>
#include <drv/timer.h>

Go to the source code of this file.


Detailed Description

IPC signals implementation.

Signals are a low-level IPC primitive. A process receives a signal when some external event has happened. Like interrupt requests, signals do not carry any additional information. If processing a specific event requires additional data, the process must obtain it through some other mechanism.

Despite the name, one shouldn't confuse these signals with POSIX signals. POSIX signals are usually executed synchronously, like software interrupts.

Signals are very low overhead. Using them exclusively to wait for multiple asynchronous events results in very simple dispatch logic with low processor and resource usage.

The "event" module is a higher-level interface that can optionally deliver signals to processes. Messages provide even higher-level IPC services built on signals. Semaphore arbitration is also implemented using signals.

In this implementation, each process has a limited set of signal bits (usually 32) and can wait for multiple signals at the same time using sig_wait(). Signals can also be polled using sig_check(), but a process spinning on its signals usually defeats their purpose of providing a multitasking-friendly infrastructure for event-driven applications.

Signals are like flags: they are either active or inactive. After an external event has delivered a particular signal, it remains raised until the process acknowledges it using either sig_wait() or sig_check(). Counting signals is not a reliable way to count how many times a particular event has occurred, because the same signal may be delivered twice before the process can notice.

Signals can be delivered synchronously via sig_send() or asynchronously via sig_post().

In the synchronous case the process is awakened if it was waiting for any signal and immediately dispatched for execution via a direct context switch, if its priority is greater than the running process.

  • Synchronous-signal delivery:
     [P1]____sig_send()____proc_wakeup()____[P2]
 

In the asynchronous case, the process is scheduled for execution as a consequence of the delivery, but it will be dispatched by the scheduler as usual, according to the scheduling policy.

  • Asynchronous-signal delivery:
     [P1]____sig_post()____[P1]____proc_schedule()____[P2]
 

In this way, any execution context, including an interrupt handler, can deliver a signal to a process. However, synchronous signal delivery from a non-sleepable context (like an interrupt handler) is forbidden in order to avoid potential deadlock conditions. Instead, sig_post() can be used from any context, expecially from interrupt context or when the preemption is disabled.

Multiple independent signals may be delivered at once with a single invocation of sig_send() or sig_post(), although this is rarely useful.

Signal Allocation

There's no hardcoded mapping of specific events to signal bits. The meaning of a particular signal bit is defined by an agreement between the delivering entity and the receiving process. For instance, a terminal driver may be designed to deliver a signal bit called SIG_INT when it reads the CTRL-C sequence from the keyboard, and a process may react to it by quitting.

SIG_SINGLE

The SIG_SINGLE bit is reserved as a convenient shortcut in those simple scenarios where a process needs to wait on just one event synchronously. By using SIG_SINGLE, there's no need to allocate a specific signal from the free pool. The constraints for safely accessing SIG_SINGLE are:

Author:
Bernie Innocenti <bernie@codewiz.org>

Definition in file signal.c.