0

I am trying to call a function when a background process finishes running. I am essentially creating a little shell and trying to background a process so that its contents is returned when the program finishes executing and does not block the process. The code I have below runs correctly and does what I want, except that it is not calling the signalInterrupt() function when it completes. There are some steps I want to happen when the background process finishes running, but since it is not hitting my function I can't accomplish these. How can I fix this?

pid = fork();
if(pid == 0) {
    signal(SIGINT, signalInterrupt);
    if(execvp(args[0], args) == -1)
        fprintf(stderr, "Error executing command\n");
    exit(EXIT_FAILURE);
}

void signalInterrupt(int signal) {
    fprintf(stderr, "Got a sigint\n");
}
ComputerLocus
  • 3,448
  • 10
  • 47
  • 96
  • 2
    Right idea, wrong signal, wrong process. In the parent, *before* forking, set a handler for `SIGCHLD`. You will then receive a signal when the child process terminates. In the handler, you need to call `waitpid` to reap the zombie. – zwol Feb 14 '16 at 18:00
  • @zwol why is `waitpid` needed for backgrounded process? I am using that when I don't want to background, but I thought waitpid would cause a block? – ComputerLocus Feb 14 '16 at 18:06
  • Your child sets the signal handler, but then is replaced with `execvp`. You want to notify the parent anyway, not the child. Also, [don't use `fprintf` in a signal handler function](http://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-a-signal-handler). – e0k Feb 14 '16 at 18:07
  • @Fogest it will only block if it has to wait. If the child has already terminated (i.e. it's a zombie) it will just pull the record from the system and won't have to block. – e0k Feb 14 '16 at 18:08
  • @e0k okay so then my handler `signalInterrupt()` should be calling `waitpid()` then? – ComputerLocus Feb 14 '16 at 18:09
  • Yes, if you set the signal to `SIGCHLD`, it will notify the parent when its child has terminated. Then the `waitpid` "reaps the zombie" as @zwol put it. See [this tutorial](http://www.microhowto.info/howto/reap_zombie_processes_using_a_sigchld_handler.html) for more explanation. – e0k Feb 14 '16 at 18:12
  • @e0k also funny that you mention issues with `fprintf` in a signal handler. That is a problem I am seeing now :) – ComputerLocus Feb 14 '16 at 18:24
  • @e0k the problem is with the method suggested of setting a variable in the handler and then checking that in the code is that this process is backgrounded so it could finish anytime while my "shell" is running so I it is unclear when/how I would be checking if this variable is changed. – ComputerLocus Feb 14 '16 at 18:27
  • @Fogest You don't have to react _immediately_, just wait for a convenient moment to look at the variable. Unix does make this harder than it should be -- the Right Thing would be if you could include child processes in a `select()` call, but alas, you can't. – zwol Feb 14 '16 at 18:55
  • @zwol the issue is that since this is a little test of making a small simple shell when a background process returns its stdout and hits my signal handler I need it to output another shell prompt. Basically a line with `> ` on it. I can't really wait to do this as it needs to have that prompt back up right away. – ComputerLocus Feb 14 '16 at 19:24
  • @zwol I just switched to using a `write()` instead so I have something like `write(STDOUT_FILENO, "> ", 2);` – ComputerLocus Feb 14 '16 at 20:01

0 Answers0