2

I have a code segment that looks like this:

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

int main(int argc, char *argv[]) {
  pid_t first, last;

  last = fork();
  if (last == 0) {
    char *args[] = { "./last", NULL };
    char *env[] = { NULL };
    execve("./last", args, env);
    _exit(1);
  } else if (last == -1) {
    fprintf(stderr, "Error: failed to fork last.\n");
    exit(1);
  }

  first = fork();
  if (first == -1) {
    fprintf(stderr, "Error: failed to fork first.\n");
    exit(1);
  } else if (first > 0) {
    int status;
    waitpid(first, &status, 0);
  } else {
    char *args[] = { "./first", NULL };
    char *env[] = { NULL };
    execve("./first", args, env);
    _exit(1);
  }

  return 0;
}

This works fine in a sense that I can see processes being invoked and running. However, my issue is that process last has an infinity loop, and when process first terminates, it still stays running. Is there a way in C to force process last here to terminate also when process first finishes?

m0hithreddy
  • 1,752
  • 1
  • 10
  • 17
terett
  • 355
  • 1
  • 8

2 Answers2

4

kill() should be of interest. From the man page of kill():

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

Since fork() returns the child PID in the parent, you can use that to call kill(). Here is the modified code and test run.

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>  // Modification 1

int main(int argc, char *argv[]) {
  pid_t first, last;

  last = fork();
  if (last == 0) {
    char *args[] = { "./last", NULL };
    char *env[] = { NULL };
    execve("./last", args, env);
    _exit(1);
  } else if (last == -1) {
    fprintf(stderr, "Error: failed to fork last.\n");
    exit(1);
  }

  first = fork();
  if (first == -1) {
    fprintf(stderr, "Error: failed to fork first.\n");
    exit(1);
  } else if (first > 0) {
    int status;
    waitpid(first, &status, 0);
    kill(last, SIGINT);   // Modification 2
  } else {
    char *args[] = { "./first", NULL };
    char *env[] = { NULL };
    execve("./first", args, env);
    _exit(1);
  }

  return 0;
}

Terminal Session (before):

$ ls test first last 
first  last  test
$ ./test
$ ps aux | grep last
root      165130  0.0  0.0   2136   752 pts/3    S    16:58   0:00 ./last
root      165135  0.0  0.0   6136   892 pts/3    S+   16:58   0:00 grep last

Terminal Session (after):

$ ls test first last 
first  last  test
$ ./test
$ ps aux | grep last
root      165240  0.0  0.0   6136   836 pts/3    S+   17:01   0:00 grep last

Regarding which signal to be passed: anyone whose default action is termination. You can find more from the signal man page. Since I don't know what is exactly in the last executable, I assume that there is no signal handler registered for SIGINT and hence when last gets SIGINT, the program is terminated by default.

m0hithreddy
  • 1,752
  • 1
  • 10
  • 17
2

One way to do that is by sending a SIGTERM or SIGKILL signal to the first process, using the function kill()

An example:

kill(first, SIGTERM);

When you send that signal, if you want, you can make some "clean up" on that process. To do that you need to capture and hadle the signal. In that case i would recommend the use of SIGTERM.

For signal handling, take a look at this.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
slipz
  • 64
  • 4
  • 1
    *For signal handling, take a look at this.* Please don't. The examples there are horrible. The code posted at that link [uses `signal()` instead of `sigaction()`](https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal) (bad) and [calls `printf()` from within the signal handler](https://stackoverflow.com/questions/9547949/printf-is-not-working-in-c-signal-handler/9547988) (also bad). – Andrew Henle Jun 23 '20 at 17:12