The "signal" concept, originating from the U*NIX world, is also available in the operating systems MultiTOS (actually the underlying MiNT) and MagiC (as of Version 4.50). Signals can be thought of as natural number messages that represent a given exception condition. They are comparable to an interrupt or a CPU exception, but with the difference that they deal with a pure software implementation.
Each process possesses:
A bit-vector of the pending signal. This describes those
signals that are still waiting to be processed, perhaps because they
are currently blocked by the signal mask, or because the process is in
a state where it cannot process signals.
A signal mask. This 32-bit value defines those signals that are
currently blocked as a bit-vector; if, say, bit 30 is set in this
vector, then the signal SIGUSR2 is blocked. The signal mask is not
just impacted explicitly (i.e. by system calls) but also
implicitly by other processes. During the processing of a
signal, for instance, it is blocked, yet others may occur. After the
signal has been processed it is released again and any signals waiting
can then be processed. One should note that some signals (e.g.
SIGKILL, SIGSTOP, SIGCONT) can not be masked.
A table in the form struct sigaction.
At a Pexec the signal mask and the pending value (see above) of the child process will be zeroed. The element sa_handler of the sigaction structure is inherited, during which a non-0 or 1 value is always set to 0. The elements sa_mask and sa_flags of the structure are zeroed.
Most signals can be caught by a program (perhaps to call up a given routine on receipt), ignored, or also blocked. Blocked signals will be ignored until the blockade is lifted again. Re terminology: One says that a signal is sent to a process when the exception that is represented by the signal occurs, or the signal is sent by another process via Pkill. On the other hand a signal is caught by a process when the corresponding process awakes and starts the actions matching the signal. One should note that the signal handling takes up time: Between sending a signal and the execution of the matching action a considerable period of time may pass.
In total there are 31 possible signals (0 to 30) available, not all of which however have been assigned a fixed meaning. The following list describes (as far as known) all possible signals in the form: Signal number, Name of the signal, Meaning of the signal for the receiving process. Unless explicitly noted otherwise, the default action on the receipt of a signal is the killing (termination) of the receiving process.
Number Name | Meaning |
0 SIGNULL | Null: This signal has no default action, because strictly speaking it is not really a signal at all. Together with Pkill it can be used, however, to test for the existence of a child process. The signal can not be masked or caught. |
1 SIGHUP | Hang up: Is normally sent when the terminal with which a process is connected is no longer valid. After receiving this signal the process should make no further output to the terminal. In MagiC the VT52 will send the signal when a terminal window has been closed. |
2 SIGINT | Interrupt: Is usually sent when the user presses the key combination ^C to interrupt a process. This signal is used by later versions of MagiC in place of previous ways of handling ^C. |
3 SIGQUIT | Quit: Generally this is sent when the user presses the key combination ^\. This signal should be 'harder' than SIGINT, and at present is not sent by MagiC or VT52. |
4 SIGILL | Illegal instruction: Corresponds to the exception vector of the same name of the 68k processor. The signal should not be caught. In MiNT the signal can be caught, i.e. the vector will be diverted for almost every process. In MagiC however this does not work at present, so that here 8 bombs will always appear. |
5 SIGTRAP | Trap: Corresponds to the 'Trace' exception vector of the 68k processor, and is sent after each instruction is executed with the system in single-step 'trace' mode. This signal should be caught only by debuggers. In MiNT the signal can be caught, i.e. the vector will be diverted for almost every process. In MagiC however this does not work at present, so that here 9 bombs will always appear. |
6 SIGABRT | Abort: Is normally used by the library function abort in ANSI C, and should not be caught. This signal is not sent by the operating system itself. |
7 SIGPRIV | Privilege violation: Corresponds to the exception vector of the same name of the 68k processor, when a process tries to execute an instruction in user-mode that may be executed only in supervisor-mode. The signal should not be caught. In MiNT, however, this is possible, so that the exception vector will be diverted for almost every process. But in MagiC this does not work at present, so that here 8 bombs will always appear. |
8 SIGFPE | Floating point exception: The default action consists of ignoring the signal. It corresponds to the 68k exception vector 'Division by zero' or a floating point exception. The signal may be ignored or caught. In MiNT the signal may be caught, so the vector will be diverted for almost every process. In MagiC however this does not work at present. |
9 SIGKILL | Kill: Forcibly terminates the receiving process. The signal cannot be masked or caught; therefore this signal should only be sent if SIGTERM failed. The signal is not presently sent by MagiC itself. |
10 SIGBUS | Bus error: Corresponds to the exception vector of the same name of the 68k processor. The signal should not be ignored or caught. In MiNT the signal may be caught, i.e. the exception vector will be diverted for almost every process. In MagiC however this does not work at present, so that 2 bombs will always appear. In MiNT, SIGBUS, SIGSEGV and SIGPRIV are reset to the default routine of the system on first receipt of the signals, so that a double bus/address/privilege error always kills the process. |
11 SIGSEGV | Segmentation violation: Corresponds to an 'address error' exception vector of the 68k processor. The signal should not be caught or ignored. In MiNT the signal may be caught, i.e. the exception vector will be diverted for almost every process. In MagiC however this does not work at present, so 3 bombs always appear. |
12 SIGSYS | Bad system call: Sent when an argument to a system call is bad or out of range and the call does not have means to report the error. Is not sent by MagiC at present. |
13 SIGPIPE | Pipe error: Is sent when an attempt is made to write to a pipe that no longer exists or has no readers, and can be masked in Drag&Drop protocol, for instance. This signal is not sent by MagiC at present. |
14 SIGALRM | Alarm: Is used by MiNT for Talarm, and serves for handling timeouts, for instance. In MagiC this signal is not sent at present. |
15 SIGTERM | Terminate: Standard request for the process to clean up and exit; sent by MiNT, for instance, when deleting a program file in the U:\PROC directory. At present ignored by MagiC. |
16 SIGURG | This signal is currently not defined. |
17 SIGSTOP | Stop: The default action serves to suspend the receiving process. The signal can not be blocked, caught or ignored. In MagiC it causes all threads of a process to be paused. When paused, no mouse or keyboard clicks are lost in MagiC; on a restart of the process with SIGCONT all the corresponding messages will be evaluated. |
18 SIGTSTP | Terminal stop: The default action is suspension of the receiving process until a SIGCONT is caught. The signal corresponds to SIGSTOP, and is usually initiated by the user pressing the key combination ^Z. It can not be masked or caught. The signal is not sent by MagiC and VT52 at present. |
19 SIGCONT | Continue: The default action is to resume the process that was previously suspended with SIGSTOP or Pause. Though the signal cannot be masked or ignored, one can install a handling routine for this signal. In MagiC all threads will be awakened that were paused with a Pause call or a SIGSTOP signal. |
20 SIGCHLD | Child terminated: The default action is to ignore the signal. It is sent to the parent process both on termination as well as pausing of a child process. In MiNT one can arrange that this signal is sent only on termination, and in addition one can determine which child process was affected. As MagiC until now only knows the waiting Pexec (i.e. the parent waits until the child terminates), this signal does not exist there. Processes that are created with shel_write are not real child processes, but fully independent ones; in such cases one therefore has to wait for the arrival of a CH_EXIT message. |
21 SIGTTIN | Terminal input error: The default action consists of pausing the receiving process. As a rule, a process is attempting to read from a terminal in a process group that does not belong to it. This signal is not sent by MagiC or VT52 at present. |
22 SIGTTOU | Terminal output error: The default action consists of pausing the receiving process. As a rule, a process is attempting to output to a terminal in a process group that does not belong to it. This signal is not sent by MagiC or VT52 at present. |
23 SIGIO | I/O possible: Sent to show that input/output is possible on a file descriptor. |
24 SIGXCPU | Exhaustion of CPU limit: The calculation time contingent set by Psetlimit or by the extended shel_write modes has elapsed. As the limitation of CPU time is not yet implemented in MagiC, this signal is not sent at present under this OS. |
25 SIGXFSZ | File size limit exceeded: Sent to a process if it tries to modify a file in a way that makes it exceed the maximum file size limit of the process. |
26 SIGVTALRM | Time limit expired: Sent to a process that has exceeded its maximum time limit. |
27 SIGPROF | Profiling time expired: Sent to a process to tell it that its profiling time has expired. |
28 SIGWINCH | Window changed: The default action is to ignore the signal. Normally it is sent if the size of the terminal (i.e. number of lines or columns) has altered. A program that is running in a terminal window can then reconfigure itself to match the new size of the window. For obtaining the current window size one can use in MiNT Fcntl Opcodes, which however are not yet implemented in MagiC. Hence the signal is currently not sent by MagiC or VT52. |
29 SIGUSR1 | User-defined: |
30 SIGUSR2 | User-defined: These two signals may be sent by user programs. As a process is killed by default on receipt of this signal, it should only be sent if the receiver is known. |
31 SIGPWR | The system is restart due to a power failure. |
See also:
Signal-handler in MagiC Process functions Sample code Psigaction
Psignal Pkill Test for pipes
As MagiC's signal-handlers differ somewhat from those in MiNT or in MultiTOS, we will deal here with the most important differences and features. First of all it must be realised that in MagiC, AES and VDI calls from within a signal-handler are permitted (quite in contrast to MiNT).
A signal-handler runs in user-mode and employs the user stack of the main thread, while this sleeps. In MiNT the supervisor stack of the process is used. Hence, according to the MiNT documentation, the nesting of signals more than 4 deep makes a process crash due to stack overflow. In MagiC each signal-handler is its own thread with its own supervisor stack, so that the worst that can happen is the extremely rare case of user stack overflow. However, if too little memory is available for a new thread when handling a signal, then an "Out of internal memory" alert will appear, and one should terminate a program as soon as possible. MagiC requires about 7 kb of memory for handling each signal.
In MagiC, the same applies for signals as for threads (a signal-handler is a thread), i.e. the corresponding system libraries have to be reentrant. However, there is a complication because the main thread is halted while processing the signal. So if the main thread has set a signal (wind_update for example), a deadlock occurs if the signal-handler also wants to set these signals. Furthermore, in MagiC a process may be interrupted at almost any point (MagiC is reentrant, even DOS is interruptible), so that the main thread may in some cases block important areas of the system (files, directories, semaphores). Due to this it is possible that certain files cannot be deleted or opened, for instance.
With normal termination of a signal-handler all semaphores blocked by the handler are released automatically. Furthermore, windows, screen background and menu bar of the signal-handler will be released if appropriate. Note that a signal-handler has its own AES message-queue, i.e. evnt_message and appl_write should be used with care.
On Psigreturn the semaphores of all signal-handlers as well as those of the main thread will be released. However the windows, screen background and menu bar of the signal-handler will not be released. Though this would not have been much of a problem, it may not be necessary in practice. Psigreturn restores the supervisor stack of the main thread, i.e. a setjmp/longjmp mechanism only needs to set the USP. This is not sufficiently documented in the MiNT documentation, and also works only if the main thread is waiting via a GEMDOS call. If AES comes into play, MultiTOS crashes! Hence Psigreturn should be avoided if possible. Psigreturn in MagiC is not of the type VOID as in MiNT, but of the type LONG. If the function is called from a non-signal-handler, Psigreturn returns the value EACCDN, otherwise E_OK. If Psigreturn has returned E_OK, then (as in MiNT) under no circumstances should the handling procedure be terminated in the normal way via rts, because the jump-back address on the user stack is invalid after execution of Psigreturn.
A problem exists in MagiC with the existing versions of VT52. A signal-handler cannot yet perform keyboard scans in VT52; the keys will not be received. This may alter in a later version, however.
See also: Process functions Signals Threads
The first program installs a signal-handler for the two signals SIGUSR1 and SIGUSR2. With that one can test the nesting of both signals, if both are sent consecutively. The program should run in VT52 or in MINIWIN. If one presses Ctrl-Alt-Esc during the "for()" delay loop, one can see that MagiC creates its own thread for each signal-handler. This has the advantage that under MagiC no events (mouse, timer, ...) will be lost while a signal is being processed.
------------------------------ snip -------------------------- #include <tos.h> #include <stdio.h> void cdecl handler(long signr) { long i; printf("Handler: Signal %ld received.\n", signr); Cconws("Wait..."); for (i = 0; i < 7000000L; i++) ; Cconws("...OK\r\n"); } int main( void ) { long ret; printf("My ProcID is %d.\n", Pgetpid()); ret = (long) Psignal(SIGUSR1, handler); printf("Psignal => %ld\n", ret); ret = (long) Psignal(SIGUSR2, handler); printf("Psignal => %ld\n", ret); Cconin(); return(0); } ------------------------------ snap --------------------------
The second program shows the treatment of the Psigreturn call. Under MiNT this program only works if one doesn't use any AES calls (evnt_keybd or evnt_multi), but uses, say, Cconin. This means that the following program works under MagiC but crashes under MultiTOS (MiNT 1.08+AES 4.1). The problem lies probably in the restoration of the supervisor stack (system stack pointer), where MultiTOS fails due to the non-homogenous concept AES<->MiNT.
------------------------------ snip --------------------------- #include <tos.h> #include <aes.h> #include <setjmp.h> #include <tosdefs.h> #include <stdio.h> jmp_buf env; void cdecl handler(long signr) { printf("Handler: Signal %ld received.\n", signr); Cconws("Perform Psigreturn()\r\n"); Psigreturn(); longjmp(env, 1); } int main( void ) { long ssp; appl_init(); printf("My ProcID is %d.\n", Pgetpid()); Psignal(SIGUSR1, handler); if (setjmp(env)) Cconws("Coming from longjmp.\r\n"); else Cconws("Coming from setjmp.\r\n"); ssp = Super(0L); Super((void *) ssp); printf("ssp = 0%08lx\n", ssp); evnt_keybd(); return(0); }
See also: Signals Process functions GEMDOS