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
...
...
return;
}
...
int sgl;
switch(sgl) {
case SIGINT: { } break;
case SIGBUS: { } break;
}
...
...
__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
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
...
int sgl;
if (sgl == SIGBUS) {
sb_reg = SB_CLOSE;
} else if (_xdma_mm2s_sgcmpltSignal()) {
sb_reg = SB_WRITE;
sb_playcount--;
sb_service();
...
void _kernel_jentry(char const *fmt,...)
Appends a formatted entry to the kernel journal.
none-blocking call usage example
...
return;
}
int time = _rtmsure_time();
if (time == -1) {
return;
}
rt_msuretime = time;
...
driver isr example
static void onxDMA1_irq(void) {
volatile xdmasr_t xdma_sr = { 0 };
xdma_sr.reg = (XDMA1 -> mm2s.sr).reg;
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;
}
}
int _kernel_raise(int sgl)
Sends a signal to the current execution context.