Thread: How can you make a parent process wait for a child? I'm gettin a seg fault.

  1. #1
    Registered User
    Join Date
    Sep 2008
    Posts
    47

    Unhappy How can you make a parent process wait for a child? I'm gettin a seg fault.

    Hi guys,

    For some reason my application is doing a seg fault when I tell the parent to wait for the child to be done with the process.
    Here is the output:
    andorian 73% pr5 -a 3 -s 10 -c 1

    child_alarm_time = 3
    child_processes = 1
    child_sleep_time = 10
    Installed SIGALRM, SIGINIT,SIGCHLD signals
    18740: Tue Oct 14 02:57:45 2008 alarm signal received
    18740: Tue Oct 14 02:57:48 2008 alarm signal received
    18740: Tue Oct 14 02:57:51 2008 alarm signal received
    18740: Tue Oct 14 02:57:52 2008 here is child 0
    18740: Tue Oct 14 02:57:52 2008 Killing this child process. 0
    18739: Tue Oct 14 02:57:52 2008 child signal received - ignored
    Segmentation fault

    I also get the seg fault if I do the following:
    pr5 -c 1
    pr5 -c 2


    Here is my code
    Code:
    static void Sleep(int alarm_time_interval, int total_sleep_time)
    {
    	int remaining_sleep_time = total_sleep_time;
    
    	while (remaining_sleep_time > 0)
    	{
    		if (alarm_time_interval > 0)
    		{ alarm(alarm_time_interval); }
    		remaining_sleep_time = sleep(remaining_sleep_time);
    	}
    }
    
    /*----------------------------------------------------------------------------*/
    
    /* The functions in this section are intended to demonstrate various usages and
    * properties of signals and signal handlers.  They should be removed or modified
    * in the final version of the program.
    */
    
    static void generic_signal_handler(int sig)
    {
    	print_message_1("generic_signal_handler, signal", sig);
    }
    
    static void SIGALRM_handler(int sig)
    {
    	if (sig == SIGALRM)
    	{ print_message("alarm signal received"); }
    	else
    	{ print_message_1("serious error: SIGALRM_handler, received signal", sig); }
    }
    
    static void SIGINT_handler(int sig)
    {
    	if (sig == SIGINT)
    	{ print_message("interrupt signal received - ignored"); }
    	else
    	{ print_message_1("serious error: SIGINT_handler, received signal", sig); }
    }
    
    static void SIGCHLD_hanlder(int sig)
    {
    	if(sig == SIGCHLD)
    	{ print_message("child signal received - ignored"); }
    	else
    	{ print_message_1("serious error: SIGCHLD_handler, received signal", sig); }
    }
    
    
    
    #ifndef NSIG
    #define NSIG 64
    #endif
    
    static int generic_signal_handler_installed[NSIG];
    /* signal 0 is reserved
    * the default handlers for SIGKILL and SIGSTOP cannot be replaced
    */
    
    /* try to replace every default signal handler */
    static void signal_setup(void)
    {
    	/* int i, ret;
    
    	for (i = 0; i < NSIG; i++)
    	{
    	ret = install_signal_handler(i, generic_signal_handler);
    	generic_signal_handler_installed[i] = (ret == 0);
    	}*/
    
    
    	printf("Installed SIGALRM, SIGINIT,SIGCHLD signals\n");
    	//just set up these 3 signal handlers
    	install_signal_handler(SIGALRM, SIGALRM_handler);
    	install_signal_handler(SIGINT, SIGINT_handler);
    	install_signal_handler(SIGCHLD,SIGCHLD_hanlder);
    }
    
    
    /*----------------------------------------------------------------------------*/
    
    int main(int argc, char *argv[])
    {
    	
    	//set up the signal handlers
    	signal_setup();
    
    	//check to see if no arguments were passed, if there weren't then don't
    	//create any children
    
    	//fork children based on what is passed through the command line
    	pid_t child_pid;
    
    	//holds an array of the child processes so the parent can wait for them.
    	pid_t child_array[MAX_CHILDREN];
    
    	int CHILD_STAT;
    
    	//print_process_table("Table before forking.");
    
    	//creating processes
    	for(int i =0; i < child_processes; i++)
    	{
    		child_pid = fork();
    		child_array[i] = child_pid;
    
    
    		if(child_pid == (pid_t)(-1))
    		{
    			//this is the parent process.  The fork failed, and there is no child
    			print_message_error("fork()", strerror(errno));
    			exit(EXIT_FAILURE);
    		}
    		else if(child_pid == 0)
    		{
    			//this is a child process.  The fork worked
    			//checking to see if alarm/sleep flags were set
    			if(a_flag || s_flag)
    			{
    				Sleep(child_alarm_time,child_sleep_time);
    			}
    			
    			print_message_1("here is child ",i);
    			print_message_1("Killing this child process.",i);
    			exit(child_exit_status);
    		}
    		else
    		{
    			//print_message("here is the parent, all children created.");
    			//if this flag is set, then set the parent alarm/sleep 
    			if(b_flag || t_flag)
    			{
    				//set alarm
    				//printf("set the alarm: %d set sleep: %d for the process: %d\n",parent_alarm_time,parent_sleep_time,getpid());
    				Sleep(parent_alarm_time,parent_sleep_time);
    			}
    
    			//this is a parent process.  The fork worked
    			//add more code but do not exit yet
    			//Wait for the child process to be done
    			wait_child(child_pid,CHILD_STAT);
    
    
    			
    
    			//update the process table
    			//printf("added child process %d\n", child_pid);
    			insert_process_table(child_pid);
    			//print_process_table("Table after inserting the process in parent.");
    
    			//print_process_table("Parent calling this again");
    		}
    	}
    
    	//tried this didn't work 
    	/*for(int i = 0; i < child_processes; i++)
    	{
    		wait_child(child_array[i],CHILD_STAT);
    
    	}*/
    
    	print_message("here is the parent, all children created");
    
    
    	if(b_flag || t_flag)
    	{
    		//set alarm
    		//printf("set the alarm: %d set sleep: %d for the process: %d",parent_alarm_time,parent_sleep_time,getpid());
    		Sleep(parent_alarm_time,parent_sleep_time);
    	}
    
    	return EXIT_SUCCESS;


    So basically I'm getting this when I try to create a 1 or more child processes and I tell the parent to wait for the child to be done, so the wait_child is where the error has to be at and I"m not sure why.

    My guess is that I'm killing the process and then asking it to wait for a dead process?

    Here is what the child_wait process looks like:
    Code:
    #include <errno.h>
    
    /* for waitpid(2) and wait(2) */
    #include <sys/types.h>
    #include <sys/wait.h>
    
    #include "pr5_wait.h"
    
    /*----------------------------------------------------------------------------*/
    
    /* wait for a child process whose pid you know
     *
     * return 1 if a child was found
     *    *child_status has been updated, and the child has terminated
     *
     * return 0 if no child was found
     *    *child_status has not been updated
     */
    
    int wait_child(pid_t wait_pid, int *child_status)
    {
      int s;
    
      /* loop because waitpid() can be interrupted by a signal and return early */
    
      while (waitpid(wait_pid, &s, 0) == (pid_t)(-1))
        {
          if (errno == ECHILD)		/* no more children */
            { return 0; }
        }
    
      *child_status = s;
    
      return 1;
    }
    
    /*----------------------------------------------------------------------------*/
    
    /* wait for a child process whose pid you do not know
     *    if more than one child has terminated, report only one
     *
     * return 1 if a child was found
     *    *wait_pid and *child_status have been updated, and the child has terminated
     *
     * return 0 if no child was found
     *    *wait_pid and *child_status have not been updated
     */
    
    int wait_any_child(pid_t *wait_pid, int *child_status)
    {
      pid_t w;
      int s;
    
      /* loop because wait() can be interrupted by a signal and return early */
    
      while ((w = wait(&s)) == (pid_t)(-1))
        {
          if (errno == ECHILD)		/* no more children */
            { return 0; }
        }
    
      *wait_pid = w;
      *child_status = s;
    
      return 1;
    }
    
    /*----------------------------------------------------------------------------*/

    That code is correct, I"m just using it wrong I think.

    Any help would be great.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    This compiles without errors?

    int CHILD_STAT;
    ...
    wait_child(child_pid,CHILD_STAT);
    ...
    int wait_child(pid_t wait_pid, int *child_status)

    As in, the function expects a POINTER, and you don't pass one.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I've been learning about fork() lately and here's too really short examples (one that works and one that doesn't, but may seem to).

    Example #1: Using signal handler
    Code:
    #include <stdio.h>
    #include <signal.h>
    
    void handler () {
    	puts("child done!");
    }
    
    int main() {
    	short int i;
    	pid_t parent=getpid(), child;
    	signal(SIGUSR1,handler);
    	if (fork()==0) {
    		sleep(3);
    		kill(parent,SIGUSR1);
    		return;
    	}
    	for (i=0;i<5;i++) {sleep(1);puts("...");
                    fflush(stdout);}
    	puts("parent done");
    }
    Output:
    ...
    ...
    child done!
    ...
    ...
    ...
    parent done


    Example #2: Using return value


    Code:
    #include <stdio.h>
    
    short int forkchild () {
    	if (fork()==0) {
    		sleep(3);
    		return 1;}
    	else return 0;
    }	
    
    int main () {
    	short int retv=forkchild(),i;
    	if (retv==1) {puts("child done");return;}
    	for (i=0;i<5;i++) {sleep(1);puts("...");}
    	puts("parent done");
    }
    Output:
    ...
    ...
    child done
    ...
    ...
    ...
    parent done


    A useful element of example #2 is how the child is prevented from running main again when it returns (this had me looped for a while; try removing the red return).

    fflush() in the first example is not totally necessary but it may prevent the "put" lines from appearing after a delay or all at once.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    Registered User
    Join Date
    Sep 2008
    Posts
    47
    thanks the solution was to add wait_any_child rather than use wait_child

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  2. Request for comments
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 15
    Last Post: 01-02-2004, 10:33 AM
  3. Resource ICONs
    By gbaker in forum Windows Programming
    Replies: 4
    Last Post: 12-15-2003, 07:18 AM
  4. How to execute a child process in dos, without closing the parent.
    By Unregistered in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 08-22-2002, 11:48 PM
  5. Tab Controls - API
    By -KEN- in forum Windows Programming
    Replies: 7
    Last Post: 06-02-2002, 09:44 AM