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

void sighup()
{
    signal(SIGHUP,sighup);
    printf("Received SIGHUP! Happy Now ??\n");
}

void sigbus()
{
    signal(SIGBUS,sigbus);
    printf("received SIGBUS! Get a life dude !\n");
}

void sigquit()
{
    printf("I am done with you. Bye!!\n");
    fflush(stdout);
    exit(0);
}

int main()
{   
    int pid = fork();

    if (pid < 0)
    {
        perror("fork");
        exit(1);
    }

    if (pid == 0)
    {   
        printf("child\n");

        signal(SIGHUP,sighup);
        signal(SIGBUS,sigbus);
        signal(SIGQUIT,sigquit);
        while(1)
        {
            ;
        }
    }
    else
    {
        printf("parent\n");
        kill(pid, SIGHUP);
        kill(pid, SIGBUS);
        kill(pid, SIGQUIT);

        wait();
    }
}

I wrote this program as part of assignment on signal handling but the output of the program is kind of weird.

The output of the program is ::

parent

ideone link :: http://ideone.com/a1DCik

I have no clue how this can be the output. It seems the child process is not being created.

Please explain the output.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
ac-lap
  • 1,623
  • 2
  • 15
  • 27
  • 1
    Strictly, it is not safe to call `printf()` from within a signal handler. You'll probably get away with it here, but be aware of that. – Jonathan Leffler Dec 27 '13 at 15:20
  • I believe it's undefined behaviour to say `while(1){;}`; at least in C++11 it is. – Kerrek SB Dec 27 '13 at 15:21
  • Following on from @KerrekSB's point: since you want your child to pause until it gets a signal, you should use the [`pause()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html) system call to do non-busy waiting. The `pause()` function never returns normally; it only ever returns with an error and `errno` set to `EINTR`. That doesn't matter much to you, but calling it in place of your `while (1) {}` loop avoids any issues with undefined behaviour. – Jonathan Leffler Dec 27 '13 at 15:24

1 Answers1

5

There is no synchronization between your two processes. It's entirely conceivable that the child process receives an unhandled signal and dies before it gets to execute any of its signal calls.

In fact, that's extremely likely: The parent process continues execution immediately after the fork() and performs the kills, while the child process first needs to be created and scheduled. Both of those take a very long time compared to the kill calls in the parent, and if you're on a single-core machine, you'd have to be very lucky if you wanted to see the parent be suspended before it gets to the kill() line.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Good point; a fix is to set the signal handlers before forking. – Jonathan Leffler Dec 27 '13 at 15:25
  • How the child and parent get scheduled as the `fork()` returns is platform dependent, and also load dependent. Your hypothesis that the parent kills the child before the signal handlers are installed is very plausible, but the execution schedule is not as deterministic as your comments imply. In fact, the way it seems to work is that the kernel scrutinizes the code and decides which way around will cause the most nuisance and least expected/helpful results, and then schedules the parent and child processes accordingly. With a multi-processor machine, they might even get to run simultaneously. – Jonathan Leffler Dec 27 '13 at 15:32
  • 2
    @Kerrek I made the changed to the code, now I am scheduling the signals before forking but still the output is pretty wired. http://ideone.com/AS1xor – ac-lap Dec 27 '13 at 15:33
  • 1
    OK I get it. After I removed the kill(pid, SIGQUIT), the output makes sense now. Thanks a lot for your help. – ac-lap Dec 27 '13 at 15:37