Subject: test program for waitpid/sigchld problems
To: None <gimp-developer@xcf.berkeley.edu>
From: Raphael Quinet <quinet@gamers.org>
List: tech-kern
Date: 11/08/2000 09:52:07
Included below is a small test program that checks how the OS behaves
when a child process exits while the parent is blocking on waitpid()
and has a SIGCHLD handler installed (which also calls waitpid, and
thus could steal the status if the signal handler is called before
the first waitpid returns).

Currently, I only tested this under Linux (2.2.13, 2.2.14), Solaris
2.6 and IRIX 6.5.  Linux and IRIX give priority to waitpid(), Solaris
gives priority to the signal handler.  That's why several plug-ins did
not work under Solaris.

If you are running another UNIX-like system (*BSD, HP-UX, AIX, etc.),
it would be nice if you could compile and run the following code and
report what it says.  The code does not depend on glib, gtk or any
other libraries, so it should be easy to compile it on any system.

-Raphael


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

int pid;
int sig_pid = 9999;
int sig_status = 9999;
int main_pid = 9999;
int main_status = 9999;

static void
sigchld_handler (int signum)
{
  sig_pid = waitpid (pid, &sig_status, WNOHANG);
}

int
main (int argc, char *argv[])
{
  int ret;
  struct sigaction sa;
  struct sigaction osa;

  printf ("installing signal handler...\n");
  sa.sa_handler = sigchld_handler;
  sigfillset (&sa.sa_mask);
  sa.sa_flags = SA_RESTART;
  ret = sigaction (SIGCHLD, &sa, &osa);
  if (ret < 0)
    {
      printf ("cannot set signal handler, bye!\n");
      exit (-1);
    }

  printf ("forking...\n");
  pid = fork ();
  if (pid == 0)
    {
      sleep (1);
      _exit (100);
    }

  printf ("waiting for child %d to exit...\n", pid);
  main_pid = waitpid (pid, &main_status, 0);

  printf ("child %d has exited\n", pid);
  printf ("  sig_pid = %d\n", sig_pid);
  printf ("  sig_status = %d\n", sig_status);
  printf ("  main_pid = %d\n", main_pid);
  printf ("  main_status = %d\n", main_status);
  if (sig_pid < 0)
    {
      if (main_pid < 0)
	printf ("no child status (fork failed?)\n");
      else
	printf ("waitpid got the status before sigchld handler was called\n");
    }
  else
    {
      if (main_pid < 0)
	printf ("sigchld handler was called before waitpid (no status)\n");
      else
	printf ("you seem to have a very interesting OS...\n");
    }
}