简体   繁体   中英

Sending signal to parent process with kill logs me out

I'm learning signals and processes on Linux(Ubuntu) and writing simple programs in C.

Here's the code.

#define _XOPEN_SOURCE 500
#include <ftw.h>
#define MAXFD 20
#include <unistd.h>
#include <stdio.h> // standard input/output
#include <stdlib.h> 
#include <string.h> // string operations
#include <dirent.h> // dirent
#include <sys/stat.h> // filestat
#include <errno.h> // errno
#include <time.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>

#define ERR(source) (perror(source),\
                    fprintf(stderr,"%s:%d\n",__FILE__,__LINE__),\
                    kill(0,SIGKILL),\
                    exit(EXIT_FAILURE))

volatile sig_atomic_t last_signal = 0;
int sig_count=0;

void usage(char *name){
    fprintf(stderr,"USAGE: %s t \n",name);
    fprintf(stderr,"t - how often send SIGUSR1 signals\n");
    exit(EXIT_FAILURE);
}

void sethandler(void(*f)(int),int sigNo){
    struct sigaction act;
    memset(&act,0,sizeof(struct sigaction));
    act.sa_handler = f;
    if (-1==sigaction(sigNo,&act,NULL)) ERR ("sigaction");
}

void countSigHandler(int sig){
    sig_count++;
    printf("Parent received a total of %d SIGUSR2\n",sig_count);
}

void sigchld_handler(int sig) {
        pid_t pid;
        for(;;){
                pid=waitpid(0, NULL, WNOHANG);
                if(pid==0) return;
                if(pid<=0) {
                        if(errno==ECHILD) return;
                        ERR("waitpid");
                }
        }
}

void child_work(int t){
    struct timespec ts = {0,t};
    int i=0;
    sethandler(SIG_DFL,SIGUSR1);
    for (i=0;i<10;i++){
        //nanosleep(&ts,NULL);
        sleep(t);
        if (kill(getppid(),SIGUSR1)) ERR("kill");
        //if (kill(getppid(),SIGUSR1)) ERR("kill");
        printf("[%d] sending SIGUSR1 to %d\n",getpid(),getppid());
    }
}

void parent_work(){
    return;
}

int main(int argc, char** argv) {
        int t;
        t = atoi(argv[1]);

        sethandler(sigchld_handler,SIGCHLD);
        sethandler(countSigHandler,SIGUSR1);    

        pid_t pid;
        if ((pid=fork())==-1)ERR("fork");

        if (pid==0) child_work(t);
        else {
            if (kill(0,SIGUSR1)) ERR("kill");
            //parent_work();
            //while(wait(NULL)>0);
        }
        return EXIT_SUCCESS;
}

When I run it from the terminal ( the compiled file ) with at of 1, it logs me out and I have to type my password again to log in (also all programs are closed when I log back in).

If I comment the line in child_work that uses kill to send a signal, it runs ok.

What's going on here? Can you help me?

I think I got it. I modified the code to remove all kills but added PID prints. Here is the sequence for t=0:

I am 12684
pgid=12684  // I printed the PGID to be sure
[12685] sending SIGUSR1 to 12684
[12685] sending SIGUSR1 to 11451
(…) // same line repeated, from the for loop

With t=1 it is directly 11451. You were right, because on my session process with PID 11451 is:

init --user

started as my user. So I'm allowed to send signals to it. And so yes, after father dies the child is attached to init, here "my" init, and so getppid() points to it and the code kills init!

If you re-activate the wait() loop the output is different as I only see the father PID (of course without real kill the father is still alive).

Not sure about why this "private" init is used (don't followed recent changes in Ubuntu). Knowing that, and to prevent such behavior, I would suggest to store the PID at process starting (before any forks) and to use this stored value after that in children. This way you are sure to "kill" the right target, or to kill nobody if the father dies for any reason.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM