prctl(PR_SET_PDEATHSIG, SIGNAL) is called on paren

2019-06-21 04:57发布

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 page at http://www.kernel.org/doc/man-pages/online/pages/man2/prctl.2.html 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?

2条回答
兄弟一词,经得起流年.
2楼-- · 2019-06-21 05:16

You need to understand a couple things about threading (my knowledge is from C, but this implementation seems to match what I did in C for the most part)

A process is a big, heavy thing that can contain multiple threads, as I'm sure you know.

What I believe is happening here: the parent thread is killed, and the child thread never receives any signal that it should die, as well.

You need to make sure when your process ends, it is broadcasting that to all threads it contains, not just a parent thread.

This is demonstrated well by the following graph from the LLNL tutorial on POSIX threads:

enter image description here

I think the fix is just to make sure you call pthread_join when you initialize your threads.

Hope this helps!

查看更多
成全新的幸福
3楼-- · 2019-06-21 05:40

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.

查看更多
登录 后发表回答