IPC:signal basics (2)

Signal actions

three types of actions:

  • SIG_DFL,
    • for most signals, kill the process.
    • SIGSTOP: stop the process
    • SIGCONT: continue the program.
    • SIGCHLD, SIGIO, SIGURG, SIGWINCH: ignore the signal.
  • SIG_IGN,
    • discard all pending signals, whether it is blocked or not. the new signals are discarded, too.
  • or a pointer to a function (signal handler)
    • the function is called in a manner equivalent to the code sequence of : signal (sig_no, SIG_DFL); (*func)(sig_no);

Note:

  • Initially, all signals are set to SIG_DFL or SIG_IGN, prior to entry of main() routine.
  • The default action for most signals is to terminate the process.

Related functions

  • int sigaction (int sig, const struct sigaction *act, struct sigaction *oact) examine or specify the action associated with a signal.
  • void *signal (int sig, void (*func)(int)) specify an action to take place when the process is hit by the signal.
    • signal() will call sigaction().

More about signal handler

  1. What you can do:
    • Return
    • Call exit() or abort() to terminate the program
    • Call longjmp(), or siglongjmp().
  2. After return from the signal handler, the receiving process resumes execution at the point where it was interrupted.
  3. signal handlers are invoked asynchronously with process execution, so you should be taken into account the same sort of things that you would in a multithread environment, when inspecting or manipulating shared resources.
  4. When a signal handler is invoked,  the responsible signal is masked before its handler is called. If the handler returns normally, OS restores the signal mask. Any signal mask change using pthread_sigmask() in the handler are undone..

Signal Mask

pthread_sigmask(int how, const sigset_t* set, sigset_t oset)  exmain or/and change the calling thread’s signal mask.

how:

SIG_BLOCK:  block the “set”, together with the current signal mask.

SIG_UNBLOCK: unblock the “set”.

SIG_SETMASK: block only the “set”.

Or sigprocmask()

Generate a signal
1) int raise (int sig) == pthread_kill(pthread-self(), sig)

2) pthread_kill(thread, int sig)

3)kill(pid, sig)

Manipulate a signal set

sigfillset(*set): initialize set to contain all signals.

Sigempty(*set)

Sigaddset(*set, signo)

Sigdelset(*set, signo)

sigismember(*set, signo)

Wait for a signal

1)  sigwait(*set, *signo)

returns 0 if success, EINTR, EINVAL,, etc, otherwise.

Note: the signals defined by “set” must be blocked before you call sigwait(). otherwise, the behavior is undefined.

2) sigwaitinfo(*set, *info). blocks until the specified signal (defined in *set) is pending. If already pending, returns immediately.

    returns: a signal number, or -1 (with errno set).

3) sigtimedwait(*set, *info, const sruct timespec *timeout)

Advertisements

IPC: Signal Basics

Processes can ignore, block, or catch all signals except SIGSTOP and SIGKILL.

  • Catch: If a process catches a signal, it means that it contains code that will take appropriate action when the signal is received.
  • signal mask: Attribute of a thread.  All the signals in signal mask are being blocked by the thread. To change it, use pthread_sigmask().
    • If a masked signal occurs, it becomes pending (can be checked by sigpending (*set)), but doesn’t affect the execution of the process.
    • When a pending signal is unmasked, it’s act upon immediately, before pthread_sigmask() returns.
    • Ignore:

Some principles/rules

  • The signal actions (ignore, catch) are maintained at the process level.
    • If a thread ignores or catches a signal, it affects all threads within that process.
  • The signal mask(block, unblock) is maintained at the thread level.
    • If a thread blocks a signal, it affects only that thread.
  • An unignored signal targeted at a thread will be delivered to that thread alone.
  • An unignored signal targeted at a process is delivered to the first thread that doesn’t have the signal blocked.
    • If all threads have the signal blocked, the signal will be queued on the process until one thread ignores or unblocks it.
    • A practical way is to mask the signals in all threads but one, which is dedicated to handling them.

Some signals

  • CTRL-C: SIGINT (signo 2)
  • CTRL-Z: SIGTSTP (signo 24)
  • Slay: SIGTERM (signo 15)
  • Bad pointer/invalid memory address: SIGSEGV (signo 11)
    • Hardware generates a fault – the kerneal set SIGSEGV signal on the process
  • note: in QNX, SIGSEGV, is generated by the program itself, will target only the thread which causes the issue, not the process. the signal is not caught by the separate signal thread!
  • SIGBUS (signo 10)

Send a signal to a process: slay -s <process name>

QNX extends the signal-delivery mechanisms of POSIX by allowing signals to be targeted at specific threads, rather than simply at the process containing the threads. QNX kernel uses common code to manage signal and pulse (8 bit code, 32-bit value). Signal number is mapped to a pulse priority using _SIGMAX-signo. As a result, signals are delivered in priority order with lower signal numbers having higher priority.

Use setjmp/longjmp for error handling