Search code examples
cprocesssignalsforkexec

Is there a way to execute code in the parent process after the child, which is created using fork and execl?


I am having a parent process play that creates a fork and runs foo using execl

Code for play.c

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
    if (fork() == 0) {
      execl("./foo", "", NULL);
    } else {
      wait(0);
      write(STDOUT_FILENO, "in parent after waiting", 5);
    }
  printf("outside everything");
  return 0;
}

Code for foo.c

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void signal_handler() {
  write(STDOUT_FILENO, "\nBye!\n", 6);
  exit(1);
}

int main() {
  struct sigaction sa;
  sa.sa_handler = signal_handler;
  sigaction(SIGINT, &sa, NULL);

  while (1) {
    printf("Wasting time...%d \n", getpid());
    sleep(1);
  }

  return 0;
}

My questions are,

  • Why aren't the print statements after the wait(0) statement executed?
  • Why isn't the signal handler in the child process triggered when Ctrl + C?

Solution

  • You should ensure that the sa_flags and sa_mask fields of struct sigaction are set. You can initialize them — struct sigaction sa = { 0 }; will probably do the job. Or you can use sigemptyset(&sa.sa_mask); and sa.sa_flags = 0; to assign values. Or you can set them to some non-zero value. Not setting sa_flags means you've no idea what operation you requested. You also need a signal handler in play.c. You need to ignore SIGINT before the fork(), then in the child re-enable the signal before executing foo. The write() in the parent does not print much; it may once have printed "\nBar!\n" or something.

    Here's some working code.

    play.c

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <unistd.h>
    
    int main(void)
    {
        struct sigaction sa = { 0 };
        sa.sa_handler = SIG_IGN;
        sigaction(SIGINT, &sa, NULL);
        if (fork() == 0)
        {
            sa.sa_handler = SIG_DFL;
            sigaction(SIGINT, &sa, NULL);
            execl("./foo", "", NULL);
            exit(1);
        }
        else
        {
            wait(0);
            printf("in parent after waiting\n");
        }
        printf("outside everything\n");
        return 0;
    }
    

    foo.c

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    static void signal_handler(int signum)
    {
        char message[] = "\nBye (XX)\n";
        message[6] = signum / 10 + '0';
        message[7] = signum % 10 + '0';
        write(STDOUT_FILENO, message, sizeof(message) - 1);
        exit(1);
    }
    
    int main(void)
    {
        struct sigaction sa = { 0 };
        sa.sa_handler = signal_handler;
        sigaction(SIGINT, &sa, NULL);
    
        while (1)
        {
            printf("Wasting time...%d \n", getpid());
            sleep(1);
        }
    
        return 0;
    }
    

    Example output

    $ play
    Wasting time...11383 
    Wasting time...11383 
    Wasting time...11383 
    Wasting time...11383 
    ^C
    Bye (02)
    in parent after waiting
    outside everything
    $