Process may in turn resume execution of the traced process by means of a sigcont signal

• The signal is not blocked by the destination process.

• The signal is being ignored by the destination process (either because the process explicitly ignored it or because the process did not change the default action of the signal and that action is "ignore").

• Handle the signal, which may require switching the process to a handler function at any point during its execution and restoring the original execution context after the function returns.

Moreover, Linux must take into account the different semantics for signals adopted by BSD and System V; furthermore, it must comply with the rather cumbersome POSIX requirements.

10.1.1 Actions Performed upon Delivering a Signal

There are three ways in which a process can respond to a signal:

1. Explicitly ignore the signal.

2. Execute the default action associated with the signal (see Table 10-1). This action, which is predefined by the kernel, depends on the signal type and may be any one of the following:

Terminate

The process is terminated (killed).

Dump

The process is terminated (killed) and a core file containing its execution context is created, if possible; this file may be used for debug purposes.

Ignore

The signal is ignored.

Stop

The process is stopped—i.e., put in the task_stopped state (see Section 3.2.1).

Continue

If the process is stopped (task_stopped), it is put into the task_running state.

3. Catch the signal by invoking a corresponding signal-handler function.

Notice that blocking a signal is different from ignoring it. A signal is not delivered as long as it is blocked; it is delivered only after it has been unblocked. An ignored signal is always delivered, and there is no further action.

The sigkill and sigstop signals cannot be ignored, caught, or blocked, and their default actions must always be executed. Therefore, sigkill and sigstop allow a user with appropriate privileges to terminate and to stop, respectively, any process,

regardless of the defenses taken by the program it is executing.

[2] There are two exceptions: it is not possible to send a signal to process 0 (swapper), and signals sent to process 1 (init) are always discarded unless they are caught. Therefore, process 0 never dies, while process 1 dies only when the init program terminates.

10.1.2 Data Structures Associated with Signals

For any process in the system, the kernel must keep track of what signals are currently pending or masked, as well as how to handle every signal. To do this, it uses several data structures accessible from the processor descriptor. The most significant ones are shown in Figure 10-1.

Figure 10-1. The most significant data structures related to signal handling

Figure 10-1. The most significant data structures related to signal handling

The fields of the process descriptor related to signal handling are listed in Table 10-3.
Table 10-3. Process descriptor fields related to signal handling

Type

Name

Description

spinlock t

sigmask lock

Spin lock protecting pending and blocked

struct signal struct *

sig

Pointer to the process's signal descriptor

sigset t

blocked

Mask of blocked signals

struct sigpending

pending

Data structure storing the pending signals

unsigned long

sas ss sp

Address of alternate signal handler stack

size t

sas ss size

Size of alternate signal handler stack

int (*) (void *)

notifier

Pointer to a function used by a device driver to block some signals of the process

void *

notifier data

Pointer to data that might be used by the notifier function (previous field of table)

sigset t *

notifier_mask

Bit mask of signals blocked by a device driver through a notifier function

The blocked field stores the signals currently masked out by the process. It is a sigset_t array of bits, one for each signal type:

typedef struct {

Since each unsigned long number consists of 32 bits, the maximum number of signals that may be declared in Linux is 64 (the _nsig macro specifies this value). No signal can have number 0, so the signal number corresponds to the index of the corresponding bit in a sigset_t variable plus one. Numbers between 1 and 31 correspond to the signals listed in Table 10-1, while numbers between 32 and 64 correspond to real-time signals.

The sig field of the process descriptor points to a signal descriptor, which describes how each signal must be handled by the process. The descriptor is stored in a signal_struct structure, which is defined as follows:

struct signal_struct {

atomic_t count;

struct k_sigaction action[64];

spinlock_t

siglock;

As mentioned in Section 3.4.1, this structure may be shared by several processes by invoking the clone( ) system call with the CLONE_SIGHAND flag set.[3] The count field specifies the number of processes that share the signal_struct structure, while the siglock field is used to ensure exclusive access to its fields. The action field is an array of 64 k_sigaction structures that specify how each signal must be handled.

Was this article helpful?

0 0

Post a comment