Basic of C Signal Processing

Source: Internet
Author: User

A signal is a mechanism provided by software interruption for processing asynchronous time. It has a very precise life cycle. First, a signal is triggered at a time, and then the kernel stores the signal until it is passed out. Finally, the kernel processes the signal as appropriate. The kernel can process signals in three ways:

  1. However, sigkill and sigstop cannot be ignored.
  2. Capture and process, the kernel pauses the execution of the current program, jumps to a previously registered function, the process executes the function, and then returns to the paused place.
  3. Perform the default operation. The specific operation depends on the signal type. The default operation is usually to terminate the process.
static void sigwinch_handler(int signo){
printf("window size has been changed\n");
}
int main(){
if(signal(SIGWINCH, sigwinch_handler) == SIG_ERR){
printf("signal error.\n");
exit(EXIT_FAILURE);
}
for(;;)
pause();

return 0;
}

The above code is an example of a simple signal: when the size of the terminal window changes, the output "window size has been changed ", that is to say, the sigwinch signal is handed over to sigwinch_handler for processing.

bool is_child;
bool has_fork;

static void sigwinch_handler(int signo){
if(is_child == true)
printf("child:\n");
else
printf("parent:\n");
printf("window size has been changed\n");
}

static void sigint_handler(int signo){
has_fork = true;
if(is_child == true)
printf("child:");
else
printf("parent:");
printf("int\n");
}


int main(){
has_fork = false;

if(signal(SIGWINCH, sigwinch_handler) == SIG_ERR){
printf("signal error.\n");
exit(EXIT_FAILURE);
}

if(signal(SIGINT, sigint_handler) == SIG_ERR){
printf("signal error.\n");
exit(EXIT_FAILURE);
}
while(has_fork == false){}
int pid = fork();

if(pid == 0)
is_child = true;
else
is_child = false;
for(;;)
pause();

return 0;
}

From the above code, we can see the effect of fork on signal processing. After fork, the child process will also receive the signal sent from the kernel to the parent process, but the child process will not process the signal received by the parent process again.

static void sigint_heandler(int signo){
printf("i get a signal: SIGINT\n");
}

int main(){
if(signal(SIGINT, sigint_heandler) == SIG_ERR){
printf("signal fail.\n");
exit(-1);
}
int pid = fork();

if(pid != 0){
if(kill(pid, SIGINT) == 0){
printf("send SIGINT success.\n");
}else{
printf("send fail.\n");
}
}

for(;;)
pause();

return 0;
}

There are many signal triggering methods, not only when the program is running, we press "Ctrl + C" on the console to trigger SIGINT, but also can send it through the program when the program is running, the above code is a small example. Generate a sub-process through fork and send a SIGINT signal to it. Of course, this is a permission issue. Only processes with the cap_kill capability can send various signals to other processes at will, if a process does not have this capability, it can send signals to processes of the same user.

If pid = 0 during the kill call, signo is sent to the process group to which it belongs. If pid =-1, the range is larger. Except for PID itself and init, all processes that can be sent are sent once. If PID <-1, signo is sent to the Process Group PID. Signo = 0 is an empty signal. Although nothing is done, error detection is still performed during sending. Therefore, you can use it to detect the permissions of processes.

Kill can certainly be used to send signals to itself, but there is another option: raise. The signal sent to the process group can also be replaced by killg.

If you use global variables as casually as the signal processing program just now (of course there are no major problems in this program, because when the kernel sends a signal, it does not know what code the process is executing. Therefore, the code running in the signal processing program must ensure that the operations or called functions do not cause problems when multiple parallel operations occur, that is, they must be reentrant.

static void sigint_handler(int signo){
printf("sigint_handler get a signal.\n");
}

void printset(sigset_t *sset){
for(int i = 0, *p = (int*)sset; i < sizeof(*sset)/sizeof(int); i++)
printf("%08x%c", *(p+i), (i%8!=7)?'':'\n');
printf("\n");
}

int main(){
if(signal(SIGINT, sigint_handler) == SIG_ERR){
printf("signal fail.\n");
exit(-1);
}

sigset_t *sset = (sigset_t*)malloc(sizeof(sigset_t));

sigfillset(sset);
printset(sset);

sigemptyset(sset);
printset(sset);

sigaddset(sset, SIGINT);
printset(sset);

int ret = sigismember(sset, SIGINT);
if(ret == 1){
printf("SIGINT is in set.\n\n");
}

ret = sigprocmask(SIG_SETMASK, sset, NULL);
if(ret == 0){
printf("set success.\n\n");
}

sleep(5);

ret = sigpending(sset);
printset(sset);

sigdelset(sset, SIGINT);
ret = sigprocmask(SIG_SETMASK, sset, NULL);
if(ret == 0)
printf("change success.\n");

return 0;
}

What should I do if I don't want to interrupt the code in the critical section? The above code shows the approximate method: first, use sigprocmask to block the acceptance of a group of signals, and remove the blocking of these signals when leaving the critical section, then these signals will be processed at this time.

void do_sth(int signo, siginfo_t *info, void *context){
printf("do_sth.\n");
}
int main(){
struct sigaction sig;

sig.sa_sigaction = do_sth;
sig.sa_flags = SA_SIGINFO;
sigemptyset(&(sig.sa_mask));

int ret = sigaction(SIGINT, &sig, NULL);

while(true){
pause();
}
return 0;
}

Sigaction is more flexible than signal, but the usage of this function has been introduced in an AIO blog, so I won't repeat it here. If you want to send signals to a specified process, you can use sigqueue to complete the process, which is also more powerful than kill.

----------------------------

For personal understanding, you are welcome to shoot bricks.

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.