2
void main ( )
{   int x;
    signal (SIGUSR1, f);
    x= fork ( );
    if (x == -1) exit (1);
    if (x != 0) 
    {   kill (x, SIGUSR1) ;
        sleep (2);
        exit (0);
    }
}
void f ( )
{
    printf ("signal received");
    exit (0);
}

I think that the program above asks the system to launch the f function ( which displays "signal received" ) when the SIGUSR1 signal is received by the parent process. but I'm not sure about that, please feel free to correct or to give more details. Thank for the help !

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
user3289789
  • 23
  • 1
  • 7
  • 1
    That's more or less it. The program sets up a handler so that `f()` is called when `SIGUSR1` is received. It then forks; the parent sends `SIGUSR` to the child and then sleeps for 2 seconds. The child exits immediately. So there's a bit of a race condition here in that the child program *may* have exited before the signal is received, in which case `f()` will not be called. – TypeIA Feb 11 '14 at 16:38
  • 9
    [don't use printf in signal handler](http://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-a-signal-handler) – Grijesh Chauhan Feb 11 '14 at 16:38
  • Did you try compiling and running it? Yes, your assumption of what it **should** do is correct. Copy the code into a file called unk.c. If you try compiling with ´gcc -o unk unk.c´ you'll find a few compile errors. Cleaning those up and running the unk program then gives what you would expect. Try exprimenting a bit... it's fun. – Achim Schmitz Feb 11 '14 at 16:55
  • Remember when you calls fork you let start another process *concurrently* and because you have not implemented any concurrency control mechanism so you should except every possible sequence of instruction execute. Sometime it can be happen that child process exits from signal handler, and Sometime it can be happen that child terminated before parent can send signal to child(although it would be very rare-case because fork() need some time to create a new process so most of times you will see printf in signal handler will be executed via child) – Grijesh Chauhan Feb 11 '14 at 18:45
  • **Note:** Please don't change your question once you got answer, If you have any other question [ask new question](http://stackoverflow.com/questions/ask) If it is realted to this question or its answer you can link it. – Grijesh Chauhan Apr 07 '14 at 08:32

3 Answers3

6

There are some mistakes in your code:

  1. Avoid calling printf( ) function in signal handler. SIGNAL(7) manual provides a list of authorized functions calling them is safe inside signal-handlers. Read:

    Async-signal-safe functions

    A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then the behavior of the program is undefined.

  2. Use return type of main() int; read "What should main() return in C?"

  3. x should be pid_t. (Process Identification).

Now lets suppose your program compile and run (not interrupted by any other signal while handler executing): I am just indenting your code and shifting f() function definition before main because function declaration is missing, also adding some comments that you should read:

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void f( )
{
    printf ("signal received\n");
    exit (0);//if child receives signal then child exits from here
}            // ******* mostly happens
int main ( )
{   int x;
    signal (SIGUSR1, f);// First: handler registered
    x = fork ( );       // Second: Child created, now child will execute in
    if (x == -1)        // parallel with parent 
      exit (1);
    if (x != 0) {// parent           
        kill(x, SIGUSR1) ; // Third: sends signal to child
        sleep(2);          // Forth: parent sleep
    }
    return 0; // parent always exits  
    // Child can exits from here **** 
    // if signal sent from parent delayed
}

In main() function, you registers f() function for SIGUSR1 signal and after that calls fork() to create a new process. In runtime as fork() function returns a child-process starts executing in parallel with parent process.
As I can see your code, I think that you understands that child-process is copy of parent-process except values of variables can be different from the point fork() returns and hence x is different in child and parent process. We can use the return value from fork to tell whether the program is running in the parent-process or in child. But note that it is not parent but actually the child-process that receives signal SIGUSR1. Value of self process id is always 0 for any process. You checks the return value x = fork() that is pid of newly created child-process, in child-process value of x is 0 and in parent x != 0. Hence signal is sent from parent process to child process.

Your comments:

I think that the program above asks the system to launch the f( ) function ( which displays "signal received") when the SIGUSR1 signal is received by the parent process.

I have impression that you don't consider that both processes execute concurrently and "it can be happen that soon after fork() create a child-process, child-process start executing and immediately terminate before parent-process can send a signal to child (or child-process can receive the signal)". In that case, function f() will never get a chance to execute and printf in signal handler never prints.

But the possibility of what I have described just above is very low because fork takes time to create a new process. And even if you execute the code again and again most of the times signal sent from the parent process will execute signal-handler.

What is correct way of writing this code?

Code is x.c: Correct way is set a flag that indicates that signal handler executed and then call printf function on the bases of flag value outside signal-handler as I have described in my answer: How to avoid using printf in a signal handler? And reason behind it explained by Jonathan Leffler in his answer.

#define _POSIX_SOURCE 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
volatile sig_atomic_t flag = 0; //initially flag == 0
void f(){
    flag = 1; // flag is one if handler executes
}
int main(void){   
  pid_t x;
  (void) signal (SIGUSR1, f);
  x = fork();
  if(x == -1) 
    exit(EXIT_FAILURE);
  if (x != 0){// parent 
    kill(x, SIGUSR1);
    sleep(1);
  }
  if(flag)//print only if signal caught and flag == 1
    printf("%s signal received \n", x == 0 ? "Child:" : "Parent:");
  return EXIT_SUCCESS;
}

Now compile it and execute:

@:~$ gcc -Wall  -pedantic -std=c99  x.c  -o x
@:~$ ./x
Child: signal received 
@:~$ 

Notice child-process prints because parent sends signal to child(but parent process doesn't prints as no signal catch in parent). So behavior of above code still similar as you was getting in your code. Below I have added one more example in which I am trying to demonstrate that 'concurrent execution of processes results different at different instance of execution'(read comments).

// include header files...
volatile sig_atomic_t flag = 0;
void f(){
    flag = 1;
}
int main(void){   
  pid_t x;
  (void) signal (SIGUSR1, f);
  (void) signal (SIGUSR2, f); // added one more signal
  x= fork ( );
  if(x == -1) 
    exit(EXIT_FAILURE);
  if (x != 0){// parent 
    kill(x, SIGUSR1);
    while(!flag); // in loop until flag == 0
  }
  if (x == 0){//child 
    kill(getppid(), SIGUSR2); // send signal to parent 
    while(!flag); // in loop until flag == 0
  }//  ^^^^ loop terminates just after signal-handler sets `flag` 
  if(flag)
    printf("%s signal received \n", x == 0 ? "Child:" : "Parent:"); 
  return EXIT_SUCCESS;
}

In above code, two signals are registered in both parent and child process. Parent process doesn't sleeps but busy in a while loop until a signal sets flag. Similarly child-process has a loop that breaks as flag becomes 1 in signal-handler. Now compile this code and run repeatedly. I frequently tried an got following output in my system.

@:~$ gcc -Wall  -pedantic -std=c99  x.c  -o x
@:~$ ./x
Child: signal received 
Parent: signal received 
@:~$ ./x
Child: signal received 
Parent: signal received 
@:~$ ./x
Child: signal received  
Parent: signal received 
@:~$ ./x
Parent: signal received   // <------
@:~$ Child: signal received 
./x
Child: signal received 
Parent: signal received 
@:~$ ./x
Parent: signal received   // <------
@:~$ Child: signal received 

@:~$ 

Notice output, one case is: "till child process created parent sent signal and enter in while-loop and when child-process get chance to execute(depends on CPU scheduling) it send back a signal to parents and before parent process get chance to execute child receives signal and prints message". But it also happens sometimes that before child printf print; parent receives and print message (that is I marked using arrow).

In last example I am trying to show child-process executes in parallel with parent- process and output can be differs if you don't applies concurrency control mechanism.

Some good resource To learn signals (1) The GNU C Library: Signal Handling (2) CERT C Coding Standard 11. Signals (SIG).

Community
  • 1
  • 1
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
0

One problem is that the child process doesn't do anything, but will return immediately from the main function, maybe before the parent process can send the signal.

You might want to call e.g. pause in the child.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • This is not the case. The child process is started, however, just because it has no statements doesn't mean it will stop immediately. Note the lack of an exit statement. As I mentioned in my comment above, if you try compiling and running, then you'll see that it does exactly what one would expect... once the compile errors are sorted out. – Achim Schmitz Feb 11 '14 at 17:02
  • @AchimSchmitz: If there are no more statements in the `main` function, that function will return. The OP's `main` returns `void` (for some reason... don't do that BTW), and the child will exit... just like `int main ( void ) { return 0; }`, though lacking an `exit` will exit almost immediately... equally so for the wrong `void main (void){}` program you might write – Elias Van Ootegem Feb 11 '14 at 17:06
  • @Elias Van Ootegem: I think you should try compiling and running it... I have a cleaned up version below (just compile errors fixed). You might be surprised at what happens. – Achim Schmitz Feb 11 '14 at 17:14
  • @AchimSchmitz It might be because of the zombie state the child process end up in when exiting (yes, the child process really exits immediately after the `if` statement). – Some programmer dude Feb 11 '14 at 17:23
  • @Joachim Pileborg: By "zombie state", do you mean that it has stopped but still appears when listing the jobs with `ps`? It's not a particularly sensible piece of code, I guess, but the value of x in the parent process will none-the-less contain the PID of the child, which is what you want for a simple (if dumb) example. – Achim Schmitz Feb 11 '14 at 18:31
  • @AchimSchmitz Yes, first as a zombie (when the child process exits) and then as an orphan as it's not reaped by the parent process (so will become a child of pid `1` (the init process) until reaped). – Some programmer dude Feb 11 '14 at 19:24
  • @AchimSchmitz: Joachim is right, even though the a process exits, it can still appear in the output of `ps`. It's all part of [the process life-cycle](http://www.thegeekstuff.com/2013/07/linux-process-life-cycle/) – Elias Van Ootegem Feb 11 '14 at 19:31
  • @Elias Van Ootegem: I was aware that a process can appear in the `ps` listing after it ends. I just wanted to know what was meant by "zombie state". Is this a technical term? :-) No worries, I understand now. I've taken these and other comments on board. I'm learning lots and that is what makes this so interesting. – Achim Schmitz Feb 12 '14 at 10:11
0

For the sake of the exercise, here is a corrected version of the original code which will compile and run.

#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <bits/signum.h>
void f ( );

int main ( )
{   int x;
    signal (SIGUSR1, f);
    x= fork ( );
    if (x == -1) exit (1);
    if (x != 0)
{   kill (x, SIGUSR1) ;
        sleep (2);
        exit (0);
    }
}
void f ( )
{
    printf ("signal received\n");
    exit (0);
}

This does exactly what the original question suggested the program should do. Try it out and see what happens if you don't believe me.

BTW: I'm not very experienced at C. There are a number of comments asserting that using printf() in the child process is unsafe. Why?? The child process is a duplicate of the parent including virtual address space. So why is printf() unsafe?

Achim Schmitz
  • 498
  • 1
  • 7
  • 18
  • The `printf` is not unsafe because it's in the child process. It's unsafe because it's in an interrupt handler. – Shahbaz Feb 11 '14 at 17:26
  • Also, just because you observed parts of the behavior of a program (it's output on `stdout`) that was run on a single instance of a single architecture with a single configuration of a single operating system at a very specific load, and that observation matched your expectation, it doesn't mean that the program is correct and the behavior is guaranteed to be just that on every architecture with every configuration of every operating system on every load. Trying a program is a good idea, but beware not to generalize the results. – Shahbaz Feb 11 '14 at 17:30
  • @Shahbaz: Ah, of course... the `printf()` isn't in the child process... silly me. As for the generalisation, well, the signal handling should work the same everywhere, shouldn't it? I thought that sort of behaviour was standardised. I'm not advocating this style of coding if that's what you mean, but I figure this is just a simple example of how signals work. – Achim Schmitz Feb 11 '14 at 18:18
  • 1
    Even if it was in the child process, that wouldn't have been a problem. Signal handling to some degree works the same everywhere (yet there are still a lot of details that are different on different platforms). Still, the problem with `printf` here is not related to `signal`. It's related to the internals of `printf`. The signal can arrive at any point of the program, which includes any time during another execution of `printf`, which can cause trouble because `printf` is non-entrant. – Shahbaz Feb 11 '14 at 18:25
  • @AchimSchmitz Not safe! if second signal comes while your signal handler executes. The problem is signals can come asynchronously(because processes runs concurrently) Second printf is not safe because it allocates some resources (like memory..) if second signal terminate execution of signal-handler then behavior of process will be undefined. -- remember the signal-handler is called in-different ways then we calls simple functions. – Grijesh Chauhan Feb 11 '14 at 18:25
  • Think about the following situation: let's say the program has a bug and it has corrupted the `stdout` variable. When you receive a signal, you attempt to write to `stdout`, which causes a `SIGSEGV` signal due to corruption. You again go to the handler and retry the `printf` only to cause that signal again. You'd be in a loop forever. – Shahbaz Feb 11 '14 at 18:27
  • OK, I'll take all that on board, guys. Like I said: I'm not a C-expert. Interestingly, this kind of example for how signals work crops up all over the place in tutorials. They should probably mention the dangers in those tutorials... for unwitting programmers who don't know the whole story, like me. – Achim Schmitz Feb 11 '14 at 18:44
  • @AchimSchmitz To learn signals read: [Signal Handling](http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_21.html#SEC330) and CERT C Coding Standard [11. Signals (SIG)](https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=3903) Your answer is not very much correct read my comment to question also @ dvnrrs's comment – Grijesh Chauhan Feb 11 '14 at 18:50