1

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>
#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?

BЈовић
  • 62,405
  • 41
  • 173
  • 273
fido
  • 5,566
  • 5
  • 24
  • 20
  • It works if I add a sleep call right before the call to kill. It looks like this is a timing issue. – fido Jul 15 '11 at 19:28
  • Question: What's the procedure, now that I've figured out the problem and there isn't necessarily an answer that gives the answer? Should I edit my question and close it somehow or create my own answer and give it the "accepted answer"? – fido Jul 15 '11 at 19:56

3 Answers3

2

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).

ninjalj
  • 42,493
  • 9
  • 106
  • 148
  • I like that. After having read the clone(2) manpage over and over again for hours it makes so much sense, too bad I didn't figure it out earlier :) – fido Jul 15 '11 at 20:25
1

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.

luser droog
  • 18,988
  • 3
  • 53
  • 105
amit
  • 11
  • 1
0

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.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • If I add a sleep call right before the kill (sleep for 10 sec), I get: My pid: 14164, child_tid: 14165 Hello from cloned thread Signal Received exited, status=10 So, it looks like, in the previous scenario, the child thread's signal handler wasn't yet installed. To make this more robust in a real application, the child would signal the parent when it's initialization is done then the parent could conintue. – fido Jul 15 '11 at 19:50