Linux signal Practice (2)--Signal classification

Source: Internet
Author: User
Tags error handling sigint signal signal handler sleep function

Signal Classification

Unreliable signal

The Linux signaling mechanism is basically inherited from Unix systems. The signaling mechanism in the early Unix system was relatively simple and primitive, and later exposed some problems in practice, and its main problems were:

1. Each time the process processes the signal, the response to the signal is set to the default action. In some cases, it will cause error handling of the signal, so if the user does not want to do so, it is necessary to re-install the signal by calling signal () at the end of the signal processing function.

2. As a result, unreliable signals in the early stages of Unix mainly mean that the process may react incorrectly to the signal and the signal may be lost.

Linux supports unreliable signaling, but improves the unreliable signaling mechanism: after the signal processing function is called, it is not necessary to recall the installation function of the signal (the signal installation function is implemented on a reliable mechanism). Therefore, the unreliable signal problem under Linux mainly means that the signal may be lost .


Reliable signal

With the development of time, it is proved necessary to improve and expand the original mechanism of signal. As a result, later versions of Unix have been studied in this area, trying to achieve "reliable signals". Since there are many applications for the previously defined signals, it is not good to make any changes, and eventually we have to add some new signals (sigrtmin ~ sigrtmax) and define them as reliable signals at the outset, which support queuing and will not be lost. At the same time, the signal transmission and installation also appeared a new version: signal transmission function sigqueue () and Signal installation function sigaction ().

The sigaction and signal functions are called kernel service do_signal functions; [Kernel service function, application cannot call this function]

Early UNIX systems defined only 31 signals, while Linux 3.x supported 64 signals, number 1-64 (sigrtmin=34,sigrtmax=64), which could be further increased in the future, which needed to be supported by the kernel. The first 31 types of signals already have predefined values, each with a definite purpose and meaning, and each signal has its own default action. If you press CTRL + C on the keyboard, the SIGINT signal is generated, and the default response to that signal is the process termination. The latter 32 signals represent real-time signals , which are equivalent to reliable signals. This ensures that multiple real-time signals sent are received. Real-time signals are part of the POSIX standard and can be used for application processes.

Non-real-time signals do not support queueing, are unreliable signals, real-time signal support queuing, are reliable signals.


Signal api-Signal Transmission (1)

1.kill

kill can either send a signal to itself or send a signal to another process  

Signo parameter combination case explanation :

Pid>0 sends signal SIG to PID process

Pid=0 signal sig to the same group process

Pid=-1 sends the signal sig to all processes, and the caller process has permission to send each process (in addition to the 1th process and itself)

Pid<-1 sends the signal SIG to each process that the process Group is pid(absolute value)

example void onsignalaction (int signalnumber) {switch (signalnumber) {case Sigusr1:cout << "SIGUSR1 ="        << Signalnumber << Endl;    Break        Default:cout << "Other Signal ..." << Endl;    Break        }}int Main () {if (signal (sigusr1,onsignalaction) = = Sig_err) {perror ("signal error");    return-1;    } pid_t pid = fork ();        if (PID = =-1) {perror ("fork Error");    return-1;        } else if (PID = = 0) {/** sends a signal to the parent process pid_t Ppid = Getppid ();        Kill (PPID,SIGUSR1);        *//** sends a signal to all processes in the same group, and the child process receives the signal kill (0,SIGUSR1);        *//Send signal to all processes in this group, function as above//getpgrp () function get process group pid pid_t pgid = Getpgrp ();        KILLPG (PGID,SIGUSR1);    Exit (0);    } int sleeptime = 3; while (Sleeptime > 0) {write (Stdout_fileno, "Parent start sleep...\n", sizeof ("Parent Start Slee        P...\n "));        Sleeptime = Sleep (sleeptime); Write (StdouT_fileno, "Parent return from sleep...\n", sizeof ("Parent return from sleep...\n")); } return 0;}

Note: If the signal is installed before fork, the child process can inherit the signal .

Sleep encounters a signal, a child process sends a signal to the parent process, several explanations of the sleep function

1) Sleep function, let the process of sleeping.

2) can be interrupted by the signal, and then after processing the signal function, no longer sleep. Execute code directly down

3) The return value of the sleep function, which is the remaining number of seconds

The Man Handbook shows:

RETURN VALUE

Zero If the requested time has a elapsed, or the number of seconds left to sleep,

If the call is interrupted by a signal handler.

//Example: Sleep meets signalvoid onsignalaction (int signalnumber) {switch (signalnumber) {case Sigint:cout << SIG        INT = "<< signalnumber << Endl;    Break        Default:cout << "Other Signal ..." << Endl;    Break        }}int Main () {if (signal (sigint,onsignalaction) = = Sig_err) {perror ("signal error");    return-1;    } cout << "Main Start sleeping ..." << Endl; int returnvalue = sleep (100);    Interruptible sleep cout << "Main End sleeping ... returnvalue =" << returnvalue << Endl; return 0;} 
Example: Sleep enhancement int main () {//... Ibid. cout << "Main Start sleeping ..." << endl;//sleep enhanced ^ ^    int sleeptime =;    Do    {        sleeptime = sleep (sleeptime), cout << "continue ..." << Endl;    }    while (Sleeptime > 0);    cout << "Main End sleeping ... sleeptime =" << sleeptime << Endl;    return 0;}

2.raise

int raise (int sig);

Send a signal to yourself. Raise (SIG) is equivalent to Kill (Getpid (), SIG);


3.killpg

int killpg (int pgrp, int sig);

Sends a signal to the process group . KILLPG (Pgrp, SIG) is equivalent to kill (-pgrp, SIG);


4.sigqueue

int Sigqueue (pid_t pid, int sig, Const Union Sigval value);

Sends a signal to the process, supports queuing, and can be accompanied by information.


Signal Api-pause

int pause (void);

set the process to an interruptible sleep state . It then calls the kernel function schedule (), which causes the Linux process scheduler to find another process to run .

Pause causes the caller process to hang until a signal is captured

Example int main () {    if (signal (sigint,handler) = = Sig_err)        err_exit ("Signal error");    while (true)    {        pause ();        cout << "Pause return ..." << Endl;}    }
Signal api-Signal Transmission (2)
unsigned int alarm (unsigned int seconds);

Alarm function, set an alarm delay send SIGALRM signal (tell Linux kernel n seconds later, send SIGALRM signal);

Manual Description- DESCRIPTION

Alarm () arranges for a SIGALRM signal to being delivered to the process in seconds seconds.

If seconds is zero and no new alarm () is scheduled.

In any event previously set alarm () is cancelled.

Alarm recursive call to void onsignalaction (int signalnumber) {    switch (signalnumber)    {case    sigalrm:        cout < < "SIGALRM =" << signalnumber << Endl;        Alarm (1);//Continue calling onsignalaction break        ;    Default:        cout << "Other Signal ..." << Endl;        break;    }} int main () {    if (signal (sigalrm,onsignalaction) = = Sig_err)    {        perror ("Signal error");        return-1;    }    Alarm (1);    while (true)    {        pause ();        cout << "Pause returned ..." << Endl;    return 0;}
reentrant/Non -reentrant functions

A reentrant function is a process that can be called by multiple tasks, and the task does not have to worry about whether the data will go wrong when it is called. Since the process receives the signal, it jumps to the signal handler to proceed. If a non-reentrant function is used in a signal-processing function, the signal-processing function may modify data that should not be modified in the original process, so that the process may have unpredictable consequences when it returns to execution from the signal handler function. non-reentrant functions are considered unsafe functions in signal processing functions.

To enhance the stability of the program, the reentrant function should be used in the signal processing function.

Non-reentrant Function example struct teacher{    int A;    int b;    int C;    int D;}; Teacher g_teacher;void onsigalarm (int signo) {    printf ("%d%d", G_TEACHER.A, g_teacher.b);    printf ("%d%d\n", g_teacher.c, G_TEACHER.D);    Alarm (1);} int main () {    if (signal (sigalrm,onsigalarm) = = Sig_err)        err_exit ("Signal error");    Teacher zero = {0, 0, 0, 0};    Teacher ones = {1, 1, 1, 1};    Alarm (1);    G_teacher = zero;    while (true)    {        g_teacher = zero;        G_teacher = ones;    }}

Output Results Demo:

Cause Analysis:

You can decompose the statement g_teacher = zero to:

G_TEACHER.A = ZERO.A;

G_teacher.b = ZERO.B;

G_TEACHER.C = ZERO.C;

G_TEACHER.D = ZERO.D;

So, in the middle of the four statement execution, if the SIGALRM signal arrives at this point (the interrupt arrives), then some of the data in G_teacher is the new value, while some are the previously left dirty values, the original is G_teacher = zero is not an atomic operation, The signal processing function onsigalarm, however, accesses the global variable G_teacher.  

If you encapsulate two printf as a function

void Unsafe_function () {    printf ("%d%d", G_TEACHER.A, g_teacher.b);    printf ("%d%d\n", g_teacher.c, G_TEACHER.D);}

Then called in Onsigalarm, the Unsafe_function function becomes a non-reentrant function (in fact, printf is not reentrant function), so in the signal response function, try not to call the non-reentrant function;

Non-reentrant function

Most of the functions that meet the following conditions are non -reentrant:

(1) Using static data structures such as GetLogin (), Gmtime (), Getgrgid (), Getgrnam (), Getpwuid () and Getpwnam (), etc.;

(2) When the function is implemented, the malloc () or free () function is called;

(3) Use of standard I/O functions when implemented

With-man 7 signal you can see which functions are reentrant and non-reentrant.

Linux signal Practice (2)--Signal classification

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.