开发者

Sending and handling a signal on a cloned thread

开发者 https://www.devze.com 2023-03-20 11:13 出处:网络
UPDATE: This appears to be a timing issue.Adding a call to sleep before the call to kill makes everything work as expected.

UPDATE: This appears to be a timing issue. Adding a call to sleep before the call to kill makes everything work as expected.

I have been playing with clone(2) and trying to get a handle on how it works. I am currently having trouble sending signals to a cloned process. I have the following code:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
#include <sys/types.h&开发者_运维知识库gt;
#include <sys/wait.h>
#include <pthread.h>

volatile int keep_going = 1;

typedef void (*sighandler_t)(int);

void handler(int sig) {
   printf("Signal Received\n");
   keep_going = 0;
}

int thread_main(void* arg) {
   struct sigaction usr_action;
   sigset_t block_mask;
   sigfillset(&block_mask);
   usr_action.sa_handler = &handler;
   usr_action.sa_mask = block_mask;
   usr_action.sa_flags = 0;
   sigaction(SIGUSR1, &usr_action, NULL);
   printf("Hello from cloned thread\n");
   while(keep_going);
}

int main(int argc, char **argv) {
   void* stack = malloc(4096);
   int flags = SIGCHLD;
   int child_tid = clone(&thread_main, stack + 4096, flags, NULL);
   if (child_tid < 0) {
      perror("clone");
      exit(EXIT_FAILURE);
   }
   printf("My pid: %d, child_tid: %d\n", (int) getpid(), (int) child_tid);
   int kill_ret = kill(child_tid, SIGUSR1);
   if (kill_ret < 0) {
      perror("kill");
      exit(EXIT_FAILURE);
   }
   int status = 0;
   pid_t returned_pid = waitpid(child_tid, &status, 0);
   if (returned_pid < 0) {
      perror("waitpid");
      exit(EXIT_FAILURE);
   }
   if (WIFEXITED(status)) {
      printf("exited, status=%d\n", WEXITSTATUS(status));
   } else if (WIFSIGNALED(status)) {
      printf("killed by signal %d\n", WTERMSIG(status));
   } else if (WIFSTOPPED(status)) {
      printf("stopped by signal %d\n", WSTOPSIG(status));
   } else if (WIFCONTINUED(status)) {
      printf("continued\n");
   }
   exit(EXIT_SUCCESS);
}

Which yields the following output:

My pid: 14101, child_tid: 14102
killed by signal 10

The child was obviously killed as a result of the signal, why did the signal handler not get called?


To avoid the race condition, catch the signal on the parent, before the clone() call. The child inherits a copy of the parent's signal handlers. You can reset it later on the parent to SIG_DFL if you want. (Also, getpid() is async-signal-safe, if you want to emulate SIG_DFL behaviour on the parent).


The child is not receiving the signal because before the child has reached to the call to sigaction the parent is sending the signal and thats why it is getting killed. You should avoid setting the signal handler this way. Still if you want to do this way only then make sure is parent is waiting until the child sets up the signal handler. With this scenario you should see the expected result.


First what is strange is you didn't get this message :

"Hello from cloned thread\n"

therefore your child tread gets terminated before it manages to setup the signal handler.

EDIT: I just saw your comment about sleep. Try to add another variable, which is set when the sigaction gets executed. The main thread should be blocked until this variable is not set.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号