RPV Event driven kernel
Loading...
Searching...
No Matches
Signals processing

There are 32 signals total (see kernel_signal.h). They defined as order numbers [1 - 32].
The signals kernel API as follows:

typical signals usage flow

signals set blocking behaviour

When signals set constructed using multiple signals and in case of _kernel_sigwait() blocking call usage. It will return to (unblock) the main execution loop when any signal from the signals set is flagged. Each next call to _kernel_sigwait() should either block or return immediatly notifying next flag from the signals set reception. So _kernel_sigwait() calls in a loop can be used to await a whole signals set if neccessary.

Note
in blocking calls loop a received signal flagged from awaiting set has to be acknowledged prior to next _kernel_sigwait() otherwise it will return immediatly duplicating just received signal notification.

signals set none-blocking behaviour

_kernel_sigpending() has exact same as blocking _kernel_sigwait() behaviour apart from that it doesnt block a main execution loop and it constructs the signals set that indicates subscribed signals flagged at the moment of calling none-blocking _kernel_sigpending(). Signals acknowledgement necessity and behaviour in a case of calls loop is exact same.

signals set usage code snippets

...
/* construct SIGINT & SIGBUS signals set */
sigset_t set;
_kernel_sigaddset(&set, SIGINT);
_kernel_sigaddset(&set, SIGBUS);
...
/* subscribe to signals set events */
/* poll signals set flags */
_kernel_sigpending(&set); // none-blocking call
if (!_kernel_sigismember(&set, SIGINT)) { // probe SIGINT flag
return;
}
...
/* wait any signals set flag */
int sgl;
_kernel_sigwait(&sgls, &sgl); // blocking call
switch(sgl) {
case SIGINT: { /* handle SIGINT flagged */ } break;
case SIGBUS: { /* handle SIGBUS flagged */ } break;
}
...
/* acknowledge signals set flags handled */
...
__sigset_t sigset_t
Signal set type.
Definition kernel_signal.h:97
int _kernel_sigaddset(sigset_t *set, const int sgl)
Adds a signal to a set.
#define SIG_UNBLOCK
Remove signals from current mask (unblock).
Definition kernel_signal.h:32
bool _kernel_sigismember(sigset_t *set, const int sgl)
Tests whether a signal is a member of a set.
int _kernel_sigpending(sigset_t *set)
Retrieves pending signals.
#define SIG_BLOCK
Add signals to current mask (block).
Definition kernel_signal.h:24
int _kernel_sigprocmask(int what, const sigset_t *set, sigset_t *oldset)
Examines or modifies signal mask.
int _kernel_sigemptyset(sigset_t *set)
Initializes a signal set to empty.
int _kernel_sigwait(const sigset_t *set, int *sgl)
Waits synchronously for a signal.
Note
signals logic usage doesnt affect/alter the behaviour of a kernel event loop it designed to help introduce a separation between target software design and system level events (e.g. interrupts) to avoid overloading the event loop with not required target software subscribers

SIGIO

see Kernel STDIO

SIGINT, SIGBUS (notify / bus error)

It reserved a special meaning and such signals flow scheme can be presented on a following diagram

dot_inline_dotgraph_3.png

The scheme presents a number of target peripherals and each its driver raises SIGINT, SIGBUS (see _kernel_raise() with (SIGINT | SIGBUS)). The service either use _kernel_sigwait() blocking or _kernel_sigpending() none-blocking call and when SIGINT raised it can check using driver state if a 'right' SIGINT, SIGBUS raised.

Note
In case of a _kernel_sigwait() blocking call from a service the kernel pipeline halts preventing calling the subscribers for the events published so that the only case in using such a call is where a target really needs a hardware signal to continue operation by design e.g. a power managment service that hibernates (forces into sleep) the target until awakend. When _kernel_sigwait() called not from a service the kernel pipeline behaviour is as usual i.e. as for Kernel STDIO the kernel shell is not a service

In case of multiple hardware drivers raise SIGINT, SIGBUS a kernel supplies a semaphore for each signal meaning as long as semaphore value > 0 the kernel persists SIGINT, SIGBUS flagged until a number of raise and a number of signals acknowledge calls are matched in a given hardware notification time period. Each call to _kernel_raise with (SIGINT | SIGBUS) increases and _kernel_sigprocmask() with SIG_UNBLOCK, (SIGINT | SIGBUS) decreases corresponsing semaphore value. When semaphore value reaches 0 the kernel flags down either SIGINT or SIGBUS or both.

Warning
at the moment only SIGINT, SIGBUS have semaphores attached other signals dont. For these a _kernel_raise() and _kernel_sigprocmask() call flags up/down only. Its not designed reserving a special meaning for signals different from SIGINT, SIGBUS and SIGIO yet and maybe shall not in a future.

blocking call usage example

/******************* blocking call ************************/
...
sigset_t sgls;
_kernel_sigemptyset(&sgls); // init signals set
_kernel_sigaddset(&sgls, SIGINT); // include SIGINT to the set
_kernel_sigaddset(&sgls, SIGBUS); // include SIGBUS to the set
int sgl;
_kernel_sigwait(&sgls, &sgl); // sigwait blocking call
if (sgl == SIGBUS) {
sb_reg = SB_CLOSE;
_kernel_jentry("sb_svc: DMA bus error occured"); // bus error
_kernel_sigprocmask(SIG_UNBLOCK, (sigset_t *) &sgl, NULL); // acknowledge SIGBUS
} else if (_xdma_mm2s_sgcmpltSignal()) { // is it 'right' SIGINT ?
sb_reg = SB_WRITE;
sb_playcount--;
sb_service();
_kernel_sigprocmask(SIG_UNBLOCK, &sgls, NULL); // yes, acknowledge SIGINT
...
void _kernel_jentry(char const *fmt,...)
Appends a formatted entry to the kernel journal.

none-blocking call usage example

/****************** none-blocking call *********************/
...
sigset_t set;
_kernel_sigaddset(&set, SIGINT);
if (!_kernel_sigismember(&set, SIGINT)) {
return;
}
int time = _rtmsure_time();
if (time == -1) {
return;
}
rt_msuretime = time;
...

driver isr example

/************************ driver isr **********************/
/* DMA1 ISR */
static void onxDMA1_irq(void) {
volatile xdmasr_t xdma_sr = { 0 };
xdma_sr.reg = (XDMA1 -> mm2s.sr).reg;
/* its either an error or i/o complete IRQ */
bool ioe = xdma_sr.err_irq;
bool ioc = xdma_sr.ioc_irq;
(XDMA1 -> mm2s.sr).reg = xdma_sr.reg;
int sgl = SIGINT;
if (ioe) {
sgl = SIGBUS;
}
if (ioc) {
sgmm2s_cmpltSig = true;
}
/* raised as separated calls if isr called twice for each case but can be combined as (SIGINT | SIGBUS) depending on current hardware state. Signals are order numbers.*/
}
int _kernel_raise(int sgl)
Sends a signal to the current execution context.