Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

prctl(PR_SET_PDEATHSIG, SIGNAL) is called on parent thread exit, not parent process exit

I have a process that is forking to a child process. The child process should not exist if the parent process exists.

So, I call ::prctl(PR_SET_PDEATHSIG, SIGKILL) in the child process to kill it if the parent dies.

What ends up happening is the parent thread calls pthread_exit, and that thread ends up being the catalyst that kills the child process.

Here is my code:

parent.cpp:

#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <iostream>

void* run(void* ptr) {

    std::cout << "thread:" << getpid() << ":" << std::hex << pthread_self() << ":" << std::dec << getppid() << std::endl;
    auto pid = fork();
    if ( pid != 0 ) {
        sleep(1);
    }
    else {
        char* arg = NULL;
        execv("./child", &arg);
    }
    return NULL;
}

int main() {

    std::cout << "main:" << getpid() << ":" << std::hex << pthread_self() << ":" << std::dec << getppid() << std::endl;

    pthread_t threadid;
    pthread_attr_t attr;

    ::pthread_attr_init( &attr );
    ::pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );
    ::pthread_create(&threadid,&attr,run,NULL);

    sleep(6);

    return 0;
}

child.cpp:

#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <iostream>

int main() {
    std::cout << "child:" << getpid() << ":" << std::hex << pthread_self() << ":" << std::dec << getppid() << std::endl;
    ::prctl( PR_SET_PDEATHSIG, SIGKILL );
    sleep(6);


    return 0;
}

Run the following on the command line:

$ ./parent

At the same time, run the following to find the status of child:

$ for i in {1..10000}; do ps aux | grep child ; sleep .5; done

Child goes defunct. If you take out the prctl call in child, it does not go defunct.

The prctl man page seems to describe that this call should call SIGKILL when the parent process dies, not the parent thread.

Is there any way to make prctl kill the child when the parent process dies instead of the parent thread?

like image 485
user1418199 Avatar asked May 25 '12 20:05

user1418199


1 Answers

The child process dies because it receives PR_SET_PDEATHSIG signal when the parent thread dies. What it means is that it gets a signal when the thread that created it dies. So if you want the child to depend on the parent process (I assume you mean when the "main" function dies) fork from the main thread of execution of your parent process. If you look up the man pages at Linux prctl(2) man page they specifically state that it is the thread which created this process, delivers the signal to the calling (In your case the child) process:

Warning: the "parent" in this case is considered to be the thread that created this process. In other words, the signal will be sent when that thread terminates (via, for example, pthread_exit(3)), rather than after all of the threads in the parent process terminate.

Bottom line: Fork from the main thread of execution if you want it to depend on the parent process's execution. In simpler words, don't create a thread to fork the child process, just fork it from the main thread.

like image 141
Abhishek Patel Avatar answered Oct 23 '22 05:10

Abhishek Patel