Find the answer to your Linux question:
Results 1 to 5 of 5
Hi, I have a doubt about signals in C programming. I have done this little program to explain it. It creates a child process with fork and, when the child ...
  1. #1
    Just Joined!
    Join Date
    May 2010
    Location
    Madrid
    Posts
    21

    little signal question. SIGCHLD for wait(NULL)

    Hi, I have a doubt about signals in C programming. I have done this little program to explain it. It creates a child process with fork and, when the child ends, receives the SIGCHLD signal and wait for its termination.

    Ok, quite easy, BUT when I execute this code the SIGCHLD signal is received twice, first as an error (returns -1) and the second one to finish the child process.
    I don't understand the meaning of the first received signal. Why is it generated? Is the code wrong? any sugestion??

    Thanks

    (if you add the SIGINT and press Ctrl+C during the execution it also receives two signals instead of one)

    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    
    void sighandler(int sign){
    
    	pid_t chld_pid;
    
    	if(sign == SIGCHLD){
    		fprintf(stderr, "SIGCHLD received\n");
    		chld_pid = wait(NULL);
    		switch(chld_pid){
    		case -1:
    			fprintf(stderr, "Unknown error (%d)\n", chld_pid);
    			break;
    		case ECHILD:
    			fprintf(stderr,"ECHILD: The calling process does not have "
    						"any unwaited-for children.\n");
    			break;
    		case EINTR:
    			fprintf(stderr,"EINTR: WNOHANG was not set and an unblocked "
    					" signal or a SIGCHLD was caught.\n");
    			break;
    		case EINVAL:
    			fprintf(stderr,"EINVAL: The options argument was invalid.\n");
    			break;
    		default:
    			fprintf(stderr, "Child %d finished. Closing\n",chld_pid);
    			exit(0);
    			break;
    		}
    	}
    }
    
    int main(int argc, char *argv[]){
    	
    	pid_t pid;
    
    	signal(SIGCHLD, sighandler);
    
    	pid = fork();
    	if(pid < 0){
    		fprintf(stderr,"Error in fork\n");
    		exit(1);
    	}else if(pid == 0){
    		// son
    		system("uname -a");
    		sleep(2);
    		exit(0);
    	}else{
    		// father
    		sleep(100);
    	}
    }
    Last edited by occam25; 05-23-2011 at 10:40 AM.

  2. #2
    Just Joined!
    Join Date
    Jan 2011
    Location
    Fairfax, Virginia, USA
    Posts
    94
    Hi occam25,
    I really liked this example ... it turns out the reason for the first -1 return code is from the UNIX system(3) library call. The system() call fork()s a child of its own and runs /bin/sh on your input text. It pauses until the command is complete by doing a wait() embedded inside the system() library call. If you comment out the system() call, you won't get that error. According to "man 3 system":
    Code:
    [...]During execution  of the command, SIGCHLD will be blocked, 
    and SIGINT and SIGQUIT will be ignored. [...]  This latter return status is
    in the format specified in wait(2) [...]
    See what I mean? There are two children, the first from system() which fork()s /bin/sh and the second is your own fork(). The reason there isn't a wait() code for the first child is because its entry in the PID table was released as soon as it was wait()ed ...

    By the way, they "say" its a good idea to really limit what you do in a signal handler. For reasons I can't remember now, its bad to do things like printf() ... its best to try to limit the scope of your signal handlers to a flag if you can.
    Last edited by BrianMicek; 05-24-2011 at 02:36 AM. Reason: Edited for clarification

  3. #3
    Just Joined!
    Join Date
    Feb 2011
    Posts
    83
    The gcc compiler on my terminal gives the following error of your program:
    __________________________________________________ _________________
    $ gcc -Wall test-signal.c -o test-signal.bin

    test-signal.c: In function ‘main’:
    test-signal.c:60: warning: control reaches end of non-void function
    __________________________________________________ _________________

    It should be seen which is this non-void function.

  4. #4
    Linux Newbie
    Join Date
    Nov 2008
    Location
    Tokyo, Japan
    Posts
    243
    Quote Originally Posted by BrianMicek View Post
    By the way, they "say" its a good idea to really limit what you do in a signal handler. For reasons I can't remember now, its bad to do things like printf() ... its best to try to limit the scope of your signal handlers to a flag if you can.
    The reason is because <stdio.h> is a shared library which has its own global variables and state information, and none of these state variables were ever intended to be thread-safe, so using it can lead to race conditions.

    Running printf in a signal handler will cause it to execute code, setting various values in global variables in your program's memory. If your program receives a signal while it is executing printf, then the signal handler itself calls printf, the global variables set by the first call to printf will be overwritten by the second call to printf in the signal handler. This can, at best, garble output, and at worst, cause intermittent segment violations and other program failures that are nearly impossible to solve.

    When handling signals, it is best to set a flag in a global volatile variable. Once control has been returned to your program's execution loop, and before yielding to another process or reading any more input, your loop should call a routine that checks if the flag has been set, and handles the signal if it has been set.

  5. #5
    Just Joined!
    Join Date
    May 2010
    Location
    Madrid
    Posts
    21
    See what I mean? There are two children, the first from system() which fork()s /bin/sh and the second is your own fork(). The reason there isn't a wait() code for the first child is because its entry in the PID table was released as soon as it was wait()ed ...
    Thanks Brian, now it is perfectly clear, I have commented out the system() call and it works as you said. I will have to ckeck which functions are generating signals in my other program.
    And good advice about printf().. I did not know it. That kind of details can get you mad searching for an error that you do not see!

    The gcc compiler on my terminal gives the following error of your program:
    __________________________________________________ _________________
    $ gcc -Wall test-signal.c -o test-signal.bin

    test-signal.c: In function ‘main’:
    test-signal.c:60: warning: control reaches end of non-void function
    __________________________________________________ _________________

    It should be seen which is this non-void function.
    yes, I forgot to write the return value for main. Just put a 'return 0;' at the end of main. (main should not be void in order to return a value to the system)

    thanks for your help guys

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
...