RFC: GTK+ fork() example



Hi all,

I made a small example that shows how to use fork() within a GTK+ program.
I'd like to have it included in the GTK+ FAQ (instead of my current
example), but first I'd like you to have a look at it.

I know there are some quirks in the SIGCHLD handler, but that is
because I lend my copy of "Advanced programming in the Unix environment"
to a friend ;-). The signal handler works on Linux and IRIX, YMMV.


Erik

--- 8< --- 8< --- 8< --- gtk-fork.c --- 8< --- 8< --- 8< ---

/*-------------------------------------------------------------------------
 * Filename:      gtk-fork.c
 * Version:       0.99.1
 * Copyright:     Copyright (C) 1999, Erik Mouw
 * Author:        Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Description:   GTK+ fork example
 * Created at:    Thu Sep 23 21:37:55 1999
 * Modified by:   Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
 * Modified at:   Thu Sep 23 22:39:39 1999
 *-----------------------------------------------------------------------*/
/*
 * Compile with:
 *
 * cc -o gtk-fork gtk-fork.c `gtk-config --cflags --libs`
 *
 */

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




void sigchld_handler(int num)
{
  sigset_t set, oldset;
  pid_t pid;
  int status, exitstatus;

  /* block other incoming SIGCHLD signals */
  sigemptyset(&set);
  sigaddset(&set, SIGCHLD);
  sigprocmask(SIG_BLOCK, &set, &oldset);

  /* wait for child */
  while((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0)
    {
      if(WIFEXITED(status))
	{
	  exitstatus = WEXITSTATUS(status);

	  fprintf(stderr, 
		  "Parent: child exited, pid = %d, exit status = %d\n", 
		  (int)pid, exitstatus);
	}
      else if(WIFSIGNALED(status))
	{
	  exitstatus = WTERMSIG(status);

	  fprintf(stderr,
		  "Parent: child terminated by signal %d, pid = %d\n",
		  exitstatus, (int)pid);
	}
      else if(WIFSTOPPED(status))
	{
	  exitstatus = WSTOPSIG(status);

	  fprintf(stderr,
		  "Parent: child stopped by signal %d, pid = %d\n",
		  exitstatus, (int)pid);
	}
      else
	{
	  fprintf(stderr,
		  "Parent: child exited magically, pid = %d\n",
		  (int)pid);
	}
    }

  /* re-install the signal handler (some systems need this) */
  signal(SIGCHLD, sigchld_handler);
  
  /* and unblock it */
  sigemptyset(&set);
  sigaddset(&set, SIGCHLD);
  sigprocmask(SIG_UNBLOCK, &set, &oldset);
}




gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  return(FALSE);
}




void destroy(GtkWidget *widget, gpointer data)
{
  gtk_main_quit();
}




void fork_me(GtkWidget *widget, gpointer data)
{
  pid_t pid;

  pid = fork();

  if(pid == -1)
    {
      /* ouch, fork() failed */
      perror("fork");
      exit(-1);
    }
  else if(pid == 0)
    {
      /* child */
      fprintf(stderr, "Child: pid = %d\n", (int)getpid());

      execlp("ls", "ls", "-CF", "/", NULL);
      
      /* if exec() returns, there is something wrong */
      perror("execlp");

      /* exit child. note the use of _exit() instead of exit() */
      _exit(-1);
    }
  else
    {
      /* parent */
      fprintf(stderr, "Parent: forked a child with pid = %d\n", (int)pid);
    }
}




int main(int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *button;

  gtk_init(&argc, &argv);

  /* the basic stuff: make a window and set callbacks for destroy and
   * delete events 
   */
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

  gtk_signal_connect(GTK_OBJECT (window), "delete_event",
		     GTK_SIGNAL_FUNC(delete_event), NULL);
          
  gtk_signal_connect(GTK_OBJECT (window), "destroy",
		     GTK_SIGNAL_FUNC(destroy), NULL);

#if (GTK_MAJOR_VERSION == 1) && (GTK_MINOR_VERSION == 0)
  gtk_container_border_width(GTK_CONTAINER (window), 10);
#else  
  gtk_container_set_border_width(GTK_CONTAINER (window), 10);
#endif

  /* add a button to do something usefull */
  button = gtk_button_new_with_label("Fork me!");
          
  gtk_signal_connect(GTK_OBJECT (button), "clicked",
		     GTK_SIGNAL_FUNC(fork_me), NULL);

  gtk_container_add(GTK_CONTAINER(window), button);
          
  /* show everything */
  gtk_widget_show (button);
  gtk_widget_show (window);


  /* install a signal handler for SIGCHLD signals */
  signal(SIGCHLD, sigchld_handler);

  
  /* main loop */
  gtk_main ();

  exit(0);         
}

--- 8< --- 8< --- 8< --- gtk-fork.c --- 8< --- 8< --- 8< ---

-- 
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Department
of Electrical Engineering, Faculty of Information Technology and Systems,
Delft University of Technology, PO BOX 5031,  2600 GA Delft, The Netherlands
Phone: +31-15-2785859  Fax: +31-15-2781843  Email J.A.K.Mouw@its.tudelft.nl
WWW: http://www-ict.its.tudelft.nl/~erik/



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]