0

I created parent process and child process. And then from the child process, I created 3 more grand child processes.

From child process, SIGTERM is sent to the grand child processes and wait the grand child process terminated using waitpid().

waitpid() returns unknown error for a grand child process out of 3 grand child processes. waitpid() does not return unknown errors for the other 2 grand child processes.

I compiled the code and run it. Then, I got the message like below.

$ ./a.out
shm_create : shmid = 0
main_process
child process pid = 1953
in grand_chile_process2 : pid = 1955
in grand_child_process2-1
g_child_id->pid[0] = 0
g_child_id->pid[1] = 1955
g_child_id->pid[2] = 0
in process2-2
in grand_child_process1 : pid = 1954
in process1-1
g_child_id->pid[0] = 1954
g_child_id->pid[1] = 1955
g_child_id->pid[2] = 0
in process1-2
in grand_child_process3 : pid = 1956
in process3-1
g_child_id->pid[0] = 1954
g_child_id->pid[1] = 1955
g_child_id->pid[2] = 1956
in process3-2

And if I check running processes, I saw 5 processes like below.

# ps -eLf | grep a.out
user1       1952    1684    1952  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1953    1952    1953  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1954    1953    1954  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1955    1953    1955  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1956    1954    1956  0    1 13:51 pts/2    00:00:00 ./a.out
root        1958    1885    1958  0    1 13:51 pts/4    00:00:00 grep --color=auto a.out

And if I enter 'a', then I see the error message like below.

a
Terminating...: pid = 1956
error : waitpid (No child processes)

And the process list became as shown below.

# ps -eLf | grep a.out
user1       1952    1684    1952  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1953    1952    1953  0    1 13:51 pts/2    00:00:00 [a.out] <defunct>
user1       1954       1    1954  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1955       1    1955  0    1 13:51 pts/2    00:00:00 ./a.out
user1       1956    1954    1956  0    1 13:51 pts/2    00:00:00 [a.out] <defunct>
root        1960    1885    1960  0    1 13:51 pts/4    00:00:00 grep --color=auto a.out

Here, as shown in the source code below, I sent SIGTERM to grand_child_process3() the first and grand_child_process2() and then grand_child_process1() between line 218~246.

And I made a change to send SIGTERM in the order of grand_child_process1(), grand_child_process2() and grand_child_process3().

Then, again I can see the output like below.

$ ./a.out
shm_create : shmid = 0
main_process
child process pid = 1985
in grand_chile_process2 : pid = 1987
in grand_child_process2-1
g_child_id->pid[0] = 0
g_child_id->pid[1] = 1987
g_child_id->pid[2] = 0
in process2-2
in grand_child_process1 : pid = 1986
in process1-1
g_child_id->pid[0] = 1986
g_child_id->pid[1] = 1987
g_child_id->pid[2] = 0
in process1-2
in grand_child_process3 : pid = 1988
in process3-1
g_child_id->pid[0] = 1986
g_child_id->pid[1] = 1987
g_child_id->pid[2] = 1988
in process3-2

And the process list shows like below.

# ps -eLf | grep a.out
user1       1984    1684    1984  0    1 14:03 pts/2    00:00:00 ./a.out
user1       1985    1984    1985  0    1 14:03 pts/2    00:00:00 ./a.out
user1       1986    1985    1986  0    1 14:03 pts/2    00:00:00 ./a.out
user1       1987    1985    1987  0    1 14:03 pts/2    00:00:00 ./a.out
user1       1988    1986    1988  0    1 14:03 pts/2    00:00:00 ./a.out
root        1990    1885    1990  0    1 14:03 pts/4    00:00:00 grep --color=auto a.out

Then, again pressed 'a' and the output becomes like below.

a
Terminating...: pid = 1986
pid = 1986
child process[1986] killed by signal 15 (Terminated)
Terminating...: pid = 1987
pid = 1987
child process[1987] killed by signal 15 (Terminated)
Terminating...: pid = 1988
error : waitpid (No child processes)

Then, process list became like this.

# ps -eLf | grep a.out
user1       1984    1684    1984  0    1 14:03 pts/2    00:00:00 ./a.out
user1       1985    1984    1985  0    1 14:03 pts/2    00:00:00 [a.out] <defunct>
root        1992    1885    1992  0    1 14:05 pts/4    00:00:00 grep --color=auto a.out

My question is why grand_child_process3() is not terminated properly.

If you see anything I'm doing wrong, please let me know. Here is the full source code I'm using.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <error.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>

#define KEY_NUM 1234

pid_t g_child1, g_child2, g_child3;
int shmid;

struct _process_id {
   pid_t pid[3];
};

typedef struct _process_id G_CHILD_ID_t;

int shared_memory_create()
{
   void *shared_memory;

   shmid = shmget((key_t)KEY_NUM, sizeof(G_CHILD_ID_t), IPC_CREAT|0666);
   if (shmid == -1)
   {
      printf("shmget failed\n");
      exit(0);
   }
   printf("shm_create : shmid = %d\n", shmid);

   shared_memory = shmat(shmid, NULL, 0);
   if (shared_memory == (void *)-1)
   {
      printf("shmat failed\n");
      exit(0);
   }
   memset(shared_memory, 0x0, sizeof(G_CHILD_ID_t));

   if(shmdt(shared_memory) == -1)
   {
      printf("shmdt failed\n");
      exit(0);
   }

   return 0;
}

int grand_child_process1(void)
{
   G_CHILD_ID_t *g_child_id;
   void *shared_memory;
   int i = 0;

   g_child1 = getpid();
   printf("in grand_child_process1 : pid = %d\n", g_child1);

   shared_memory = shmat(shmid, NULL, 0);
   if (shared_memory == (void *)-1)
   {
      printf("shmat failed\n");
      exit(0);
   }

   g_child_id = (G_CHILD_ID_t *)shared_memory;
   g_child_id->pid[0] = g_child1;
   printf("in process1-1\n");
   for (i = 0 ; i < 3 ; i++)
      printf("g_child_id->pid[%d] = %d\n", i, g_child_id->pid[i]);


   if(shmdt(shared_memory) == -1)
   {
      printf("shmdt failed\n");
      exit(0);
   }

   printf("in process1-2\n");
   while(1)
   {
      sleep(1);
   }
}

int grand_child_process2(void)
{
   G_CHILD_ID_t *g_child_id;
   void *shared_memory;
   int i = 0;

   g_child2 = getpid();
   printf("in grand_chile_process2 : pid = %d\n", g_child2);

   shared_memory = shmat(shmid, NULL, 0);
   if (shared_memory == (void *)-1)
   {
      printf("shmat failed\n");
      exit(0);
   }

   g_child_id = (G_CHILD_ID_t *)shared_memory;
   g_child_id->pid[1] = g_child2;
   printf("in grand_child_process2-1\n");
   for (i = 0 ; i < 3 ; i++)
      printf("g_child_id->pid[%d] = %d\n", i, g_child_id->pid[i]);

   if(shmdt(shared_memory) == -1)
   {
      printf("shmdt failed\n");
      exit(0);
   }

   printf("in process2-2\n");
   while(1)
   {
      sleep(1);
   }
}

int grand_child_process3(void)
{
   G_CHILD_ID_t *g_child_id;
   void *shared_memory;
   int i = 0;

   g_child3 = getpid();
   printf("in grand_child_process3 : pid = %d\n", g_child3);

   shared_memory = shmat(shmid, NULL, 0);
   if (shared_memory == (void *)-1)
   {
      printf("shmat failed\n");
      exit(0);
   }

   g_child_id = (G_CHILD_ID_t *)shared_memory;
   g_child_id->pid[2] = g_child3;
   printf("in process3-1\n");
   for (i = 0 ; i < 3 ; i++)
      printf("g_child_id->pid[%d] = %d\n", i, g_child_id->pid[i]);

   if(shmdt(shared_memory) == -1)
   {
      printf("shmdt failed\n");
      exit(0);
   }

   printf("in process3-2\n");
   while(1)
   {
      sleep(1);
   }
}

void printWaitStatus(pid_t pid, int status)
{
   printf("pid = %d\n", pid);
   if (WIFEXITED(status))
   {
      printf("child process[%d] exited, status = %d\n", pid, WEXITSTATUS(status));
   }
   else if (WIFSIGNALED(status))
   {
      printf("child process[%d] killed by signal %d (%s)\n", pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
   }
   else if (WIFSTOPPED(status))
   {
      printf("child process[%d] stopped by signal %d (%s)\n", pid, WSTOPSIG(status), strsignal(WSTOPSIG(status)));
   }
}

int child_process(void)
{
   G_CHILD_ID_t *g_child_id;
   void *shared_memory;
   int wstatus;
   int err;

   pid_t p1, p2;
   char ch;

   printf("child process pid = %d\n", getpid());

   p1 = fork();
   p2 = fork();

   if (p1 == 0 && p2 > 0)
   {
      grand_child_process1();
   }
   else if (p1 > 0 && p2 == 0)
   {
      grand_child_process2();
   }
   else if (p1 == 0 && p2 == 0)
   {
      grand_child_process3();
   }

   shared_memory = shmat(shmid, NULL, 0);
   if (shared_memory == (void *)-1)
   {
      printf("shmat failed\n");
      exit(0);
   }

   g_child_id = (G_CHILD_ID_t *)shared_memory;

   while (1)
   {
      ch = (char)getchar();
      if (ch == 'a')
      {
         printf("Terminating...: pid = %d\n", g_child_id->pid[2]);
         kill(g_child_id->pid[2], SIGTERM);
         err = waitpid(g_child_id->pid[2], &wstatus, WUNTRACED | WCONTINUED);
         if (err == -1)
         {
            printf("error : waitpid (%s)\n", strerror(errno));
            exit(EXIT_FAILURE);
         }
         printWaitStatus(g_child_id->pid[2], wstatus);

         printf("Terminating...: pid = %d\n", g_child_id->pid[1]);
         kill(g_child_id->pid[1], SIGTERM);
         err = waitpid(g_child_id->pid[1], &wstatus, WUNTRACED | WCONTINUED);
         if (err == -1)
         {
            printf("error : waitpid (%s)\n", strerror(errno));
            exit(EXIT_FAILURE);
         }
         printWaitStatus(g_child_id->pid[1], wstatus);

         printf("Terminating...: pid = %d\n", g_child_id->pid[0]);
         kill(g_child_id->pid[0], SIGTERM);
         err = waitpid(g_child_id->pid[0], &wstatus, WUNTRACED | WCONTINUED);
         if (err == -1)
         {
            printf("error : waitpid (%s)\n", strerror(errno));
            exit(EXIT_FAILURE);
         }
         printWaitStatus(g_child_id->pid[0], wstatus);

         if(shmdt(shared_memory) == -1)
         {
            printf("shmdt failed\n");
            exit(0);
         }
      }
      else
         sleep(1);
   }
   return 0;
}

int main_process(void)
{
   printf("main_process \n");
   while (1)
   {
      sleep(1);
   }
}

int main(void)
{
   pid_t pid;

   shared_memory_create();
   pid = fork();
   if (pid == 0)
   {
      child_process();
   }
   else
   {
      main_process();
   }
}
Cprogrammer
  • 153
  • 9
  • 4
    `strerror(err)` is `strerror(-1)`. You want to use `errno`. – ikegami Aug 10 '21 at 04:21
  • 2
    Also, error messages should be sent to stderr, not stdout. Use `fprintf stderr` instead of `printf`. In your case, you could use `perror` – ikegami Aug 10 '21 at 04:21
  • You can't wait for a grandchild process, only for a child process. – Barmar Aug 10 '21 at 04:52
  • I changed strerror(err) to strerror(errno). Now I can see the error message (No child processes). But I see this message for only child3(). child1() and child2() are terminated as expected by child(). Here, child1(), child2(), child3() are actually grand child from original parent process(). – Cprogrammer Aug 10 '21 at 05:23
  • If I cannot wait for grandchild process, how can I understand successfully terminated child1() and child2()? – Cprogrammer Aug 10 '21 at 08:58
  • the posted code does not cleanly compile. When compiling, always enable the warnings, then fix those warnings. for `gcc` at a minimum use: `-Wall -Wextra -Wconversion -pedantic -std-gnu11` to enable the warnings – user3629249 Aug 10 '21 at 15:40
  • regarding: `pid = fork(); if (pid == 0) { child_process(); } else { main_process(); }` the function: `fork()` has three kinds of returned values. The posted code is only handling 2 of those returned values – user3629249 Aug 10 '21 at 15:43
  • regarding: `printf("parent process pid = %ld\n", getpid());` This will return the pid of the process where this statement is located (I.E. the first child) for the parent process suggest using: `getppid()` – user3629249 Aug 10 '21 at 15:46
  • regarding: `p1 = fork(); p2 = fork();` The first call to `fork()` can return the current process, the new child process, or an error indication. The result is all three conditions will execute the second call to `fork()`. And after the second call to `fork()`, the code will not know which process it is running – user3629249 Aug 10 '21 at 15:52
  • OT: a `pid_t` is defined as an `int`, not a `long int` – user3629249 Aug 10 '21 at 16:08
  • The print message "parent process pid" means relative parent from the grand child. I think the message was confusing. But it was just my debug message. So I can change it but the main problem still exist. – Cprogrammer Aug 10 '21 at 17:05
  • 1
    I edited the original code. I included all the suggestions from the comments above. And used -Wall -Wextra -Wconversion -pedantic -std=gun11 and I see no warnings. Now the code is compiled cleanly. – Cprogrammer Aug 10 '21 at 17:31
  • `how can I understand successfully terminated child1() and child2()?` What do you mean by "understand"? – KamilCuk Aug 10 '21 at 17:35
  • KamilCuk,I updated the main question. In short, when I send SIGTERM to grand_child_process3(), grand_child_process3() process is not terminated properly but the other processes are terminated properly. And there was a comment by Barmar, I cannot wait grand child. But it seems I can wait from grand_child_process1() and grand_child_process2() but not grand_child_process3(). And how can I understand this? Is it because only by luck I saw grand_child_process1() and grand_child_process2() are terminated properly? Or there is something I made mistake for grand_child_process3()? That was my question. – Cprogrammer Aug 10 '21 at 18:10

0 Answers0