Multiprocess parent return value

Advertisements

Im wondering about the nature of the variable status and when its returned in a function.

Ive set my function to get an error, but if I dont do return status >> 8(127) and instead do return status, I get a return value of 0.

Ive used return WEXITSTATUS (status) in the past and itd return the correct status number.

My questions are if WEXITSTATUS actually does the operation status >> 8?
And when doing Multiprocessing and the parent process exists properly is it better to verify with WIFEXITED(status) then return WEXITSTATUS (status) rather than doing what I do?

int main {
    int status;
    int filedes[2];
    pid_t pid_enfant;
    pipe(filedes);

    if (pid_child == 0) {
        ...
        char *tab[] = {"/bin/bash", "-c", arg[1], NULL};
        execv("/bin/bash", arg[1]);
        return 1;
    } else {
        ...
        pid_t pid_child = wait(&status);
        return status >> 8;                   -- // return this vs this below
        //if (WIFEXITED(status) && pid_valide == pid_child)
              //return WEXITSTATUS (status);
    } 
}

>Solution :

To answer your your question regarding WEXITSTATUS, the answer is yes; it is meant to shift the status down by 8 bits.

   WEXITSTATUS(wstatus)
         returns the exit status of the child.  This consists of
         the least significant 8 bits of the status argument that
         the child specified in a call to exit(3) or _exit(2) or as
         the argument for a return statement in main().  This macro
         should be employed only if WIFEXITED returned true.

Further, it explicitly states that the value of WEXITSTATUS(wstatus) is only valid if WIFEXITED(wstatus) is non-zero. So for your code to be correct with this specification, you should have

pid_t pid_child = wait(&status);
if (WIFEXITED(status))
{
  return WEXITSTATUS(status);
}
else
{
  // child did not terminate normally
}

As to why you should check this, here’s a toy example:

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

int main()
{
  int signal = /* choose your favourite signal, or 0 */;
  
  switch (fork())
  {
    case -1:
      perror("fork");
      return -1;
    
    case 0:
      if (signal) { raise(signal); }
      return 0;

    default:
      {
        int status;
        pid_t child = wait(&status);        
        printf("child=%d, status=%04x\n", child, status);
        
        if (WIFEXITED(status))
        {
          puts("good exit");
          return WEXITSTATUS(status);
        }
        else
        {
          puts("bad exit");
          return -1;
        }
      }
      break;
  }
}

If we do not raise anything in the child and get a clean exit, we’ll see child=..., status=0000 in the parent, and would take the ‘good exit’ branch returning 0, as expected. However, if we raise something like SIGSEGV in the child, then the parent will get child=..., status=008b. Now, if you blindly did status >> 8, then your parent would return 0 just like the ‘good exit’ path, but clearly the child did not exit cleanly.

Leave a ReplyCancel reply