Only receiving parent printf when runnnig GeeksforGeeks sample signal code - c

I am trying to wrap my mind around signals so I started out by running the code on GeeksforGeeks signals page. On their page it is showing output from the parent and the child but when I run in CLion, 9/10 times I am only receiving output from the parent and the child prints nothing. Every once in a while the child will print, but I don't know why or how to get it to consistently print.
https://www.geeksforgeeks.org/signals-c-set-2/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void sighup();
void sigint();
void sigquit();
void main() {
int pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
for(;;)
;
}
else {
printf("\nPARENT: sending SIGUP\n\n");
kill(pid, SIGHUP);
sleep(3);
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3);
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
void sighup() {
signal(SIGHUP, sighup);
printf("CHILD: I have received a SIGHUP\n");
}
void sigint() {
signal(SIGINT, sigint);
printf("CHILD: I have received a SIGINT\n");
}
void sigquit() {
printf("My parent has killed me");
exit(0);
}

That code is choc-full of errors. You should start by enabling warnings on your compiler. On GCC and clang this is done by passing the flags -pedantic and a warning level. I suggest using -Wall -Wextra -Werror — this gives fairly stringent warnings without getting in the way.
The first two errors, as noted in the commend, are that the prototype declarations are wrong, and that the main function signature is wrong.
The second error is that you cannot safely invoke printf inside a signal handler (you will encounter this relatively common in code, but it’s wrong). In fact, the set of actions you can safely perform inside a signal handler is severely restricted — read the documentation carefully.
Thirdly, the code’s attempt to reset the handlers is botched (and at any rate unnecessary). If you want to reset a handler, you need to pass SIG_DFL as the second argument, not a custom callback. This is also explained in the documentation.
And lastly, there is no guarantee that the code in the child process is executed before the code in the parent process — in particular, it’s not guaranteed that the signal handlers will be set up. In my testing, the child code ends up never being executed, despite the sleep statements in the parent code. That may seem weird but it’s entirely legal and needs to be anticipated.
Putting these pieces together leaves us with the following, which you may notice is a lot more complex than the non-working code you tried.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static volatile sig_atomic_t child_signal;
static volatile sig_atomic_t setup_done = 0;
void child_signal_handler(int);
void parent_signal_handler(int);
int main() {
const int parent_pid = getpid();
int pid;
// Set up BEFORE calling `fork`
signal(SIGCHLD, parent_signal_handler);
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
signal(SIGHUP, child_signal_handler);
signal(SIGINT, child_signal_handler);
signal(SIGQUIT, child_signal_handler);
kill(parent_pid, SIGCHLD);
for (;;) {
if (child_signal != 0) {
switch ((int) child_signal) {
case SIGHUP:
fprintf(stderr, "CHILD: I have received a SIGHUP\n");
break;
case SIGINT:
fprintf(stderr, "CHILD: I have received a SIGINT\n");
break;
case SIGQUIT:
fprintf(stderr, "My parent has killed me");
exit(1);
}
child_signal = 0;
}
}
} else {
while (! setup_done) { sleep(1); }
printf("\nPARENT: sending SIGUP\n");
kill(pid, SIGHUP);
sleep(1);
printf("\nPARENT: sending SIGINT\n");
kill(pid, SIGINT);
sleep(1);
printf("\nPARENT: sending SIGQUIT\n");
kill(pid, SIGQUIT);
}
}
void child_signal_handler(int signo) {
child_signal = signo;
}
void parent_signal_handler(int signo) {
if (signo == SIGCHLD) setup_done = 1;
}

Related

Linux Signal : Child not receiving

my code is a simple c code where have two processes first one the parents sends signals and print out what it send and the other is the child that receives the signals and print what it received
the output of my code is
PARENT: sending SIGHUP
PARENT: sending SIGINT
PARENT: sending SIGQUIT
it should be
PARENT: sending SIGHUP
child received SIGHUP
etc...
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
// driver code
int main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
return 0 ;
}
// sighup() function definition
void sighup(int signo)
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
}
// sigint() function definition
void sigint(int signo)
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
}
// sigsegv() function definition
void sigsegv(int signo)
{
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
}
// sigquit() function definition
void sigquit(int signo)
{
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
}
You have several "issues" with the logic of the code (apart from the use of the non async-signal-safe functions).
There is no guarantee which process will start working after the fork(). This depends on the kernel and on the system. Linux kernel allows you to make this a deterministic by setting a value in /proc/sys/kernel/sched_child_runs_first, where if value is 0 (default) the parent runs first, and if value is non-zero the child runs first. Nevertheless, it's not a good practice to depend on this switch for the synchronisation, since on multiprocessor environments, both can run at the same time if we have available CPUs.
The processes can be pre-empted at any given moment, either due to the use of system calls, or due to the cpu time. Therefore, there is no guarantee that the child had set all the signal handlers before the parent had issued the signals, so some of the signals are lost (actually on my tests I got cases where all signals ware lost, once sleep was removed).
For the same reason as 2, there is no guarantee that the child got the signal before parent sends the new signal.
To solve the problem and guarantee the order of execution, you need to create a synchronisation barrier(s). Here is example based on IPC pipes that assures the synchronisation. In the example, the parent waits for the child to set-up the signals, and than, for each signal it sends, it waits for the child to confirm that the signal was received.
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
int fd[2]; // communication pipe
// driver code
int main()
{
int pid;
if (pipe(fd)==-1)
{
fprintf(stderr, "Pipe Failed" );
exit(1);
}
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
close(fd[0]); // Close reading end
printf("Preparing the signals");
signal(SIGHUP, sighup);
printf(".");
signal(SIGINT, sigint);
printf(".");
signal(SIGQUIT, sigquit);
printf(".");
signal(SIGSEGV, sigsegv);
printf(".Signals ready\n");
write(fd[1],"ready\0", 6);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
char readb[1024];
readb[1023] = 0; //Safty stop
close(fd[1]); // Close writting end
printf("Waiting for child to finish\n");
read(fd[0], readb, 1023);
printf("Child sends %s", readb);
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
read(fd[0], readb, 1023);
printf("%s\n", readb);
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
read(fd[0], readb, 1023);
printf("%s\n", readb);
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
read(fd[0], readb, 1023);
printf("%s\n", readb);
close(fd[0]);
}
return 0 ;
}
// sighup() function definition
void sighup(int signo)
{
signal(SIGHUP, sighup); /* reset signal */
write(fd[1],"CHILD: 1 [sighub]\0",18);
}
// sigint() function definition
void sigint(int signo)
{
signal(SIGINT, sigint); /* reset signal */
write(fd[1],"CHILD: 2 [sigint]\0",18);
}
// sigsegv() function definition
void sigsegv(int signo)
{
signal(SIGSEGV, sigsegv); /* reset signal */
write(fd[1],"CHILD: 11 [sigsegv]\0",20);
}
// sigquit() function definition
void sigquit(int signo)
{
signal(SIGINT, sigquit); /* reset signal */
write(fd[1],"CHILD: 3 [sigquit]\0",19);
}
Probably the first signal is sent before the child has initialized it's signal handling. At least I could reproduce the behaviour by adding sleep(2); directly after if (pid == 0) {.
Try adding a sleep() in the parent process before you start sending signals

Linux signal parent and child [c]

im new to Linux and im still learning my code job is simple it receives a signal from the parent and the child have to ignore the signal and print the number of the signal like [1,3,4,9,11], but my problem is the child does not print anything after the signal plus I want the child to ignore the signals especially like[sigquit] here is my code.
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup();
void sigint();
void sigquit();
void sigsegv();
// driver code
void main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
}
// sighup() function definition
void sighup()
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
}
// sigint() function definition
void sigint()
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
}
// sigsegv() function definition
void sigsegv()
{
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
}
// sigquit() function definition
void sigquit()
{
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
}
Check signal.h in /usr/bin/include, signal handler
/* Type of a signal handler. */
typedef void (*__sighandler_t) (int);
so need to change both the forward declaration and function definition to match this prototype as
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup(int);
void sigint(int);
void sigquit(int );
void sigsegv(int );
// driver code
int main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
signal(SIGSEGV, sigsegv);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
return 0 ;
}
// sighup() function definition
void sighup(int signo)
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: 1 [sighub]\n");
}
// sigint() function definition
void sigint(int signo)
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: 2 [sigint]\n");
}
// sigsegv() function definition
void sigsegv(int signo)
{
signal(SIGSEGV, sigsegv); /* reset signal */
printf("CHILD: 11 [sigsegv]\n");
}
// sigquit() function definition
void sigquit(int signo)
{
signal(SIGINT, sigquit); /* reset signal */
printf("3 [sigquit]\n");
}
As mentioned in comments, stdio functions like printf() aren't safe to use in signal handlers. On Linux, you should also use sigaction() instead of signal() to install signal handlers, as that avoids some issues with an imprecise definition of how handlers work in the latter function (Which should only be used when targeting bare bones standard C, not POSIX, where what signal handlers can do is even more restricted than in POSIX).
However, when targeting Linux or Unix platforms, you don't need signal handlers at all for this task! Each process has a signal mask, which controls which signals are blocked from having the normal execution of a handler or default action go off. If a process blocking signal X gets that signal, it's considered pending, and there are other ways to receive it. One such way in Linux is to use a signalfd, a special file descriptor that can be read from to get information about pending signals. An example using it:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/signalfd.h>
#include <sys/types.h>
#include <sys/wait.h>
int child_main(const sigset_t *, int);
void send_signals(pid_t, int *);
int main(void) {
// The signals we want to catch
int signals[] = {SIGHUP, SIGINT, SIGQUIT, SIGSEGV, -1};
// Set up the signal mask
sigset_t sigs, oldmask;
sigemptyset(&sigs);
for (int i = 0; signals[i] >= 0; i++) {
sigaddset(&sigs, signals[i]);
}
// To avoid a race condition where the parent starts sending signals
// before the child is ready for them, block the signals before
// forking the child
if (sigprocmask(SIG_BLOCK, &sigs, &oldmask) < 0) {
perror("sigprocmask");
return EXIT_FAILURE;
}
pid_t child = fork();
if (child < 0) {
perror("fork");
return EXIT_FAILURE;
} else if (child == 0) {
// In the child process
return child_main(&sigs, (sizeof signals / sizeof signals[0]) - 1);
} else {
// Parent process. Restore the original signal mask and send child signals
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
perror("parent sigprocmask");
kill(child, SIGKILL);
return EXIT_FAILURE;
}
send_signals(child, signals);
// Wait for the child to finish
if (waitpid(child, NULL, 0) < 0) {
perror("parent waitpid");
return EXIT_FAILURE;
}
}
return 0;
}
void send_signals(pid_t proc, int *signals) {
for (int i = 0; signals[i] >= 0; i++) {
printf("Sending process %d signal %s (%d)\n", (int)proc,
strsignal(signals[i]), signals[i]);
if (kill(proc, signals[i]) < 0) {
printf("Failed: %s\n", strerror(errno));
}
}
}
int child_main(const sigset_t *sigs, int nsigs) {
// Create a signalfd that monitors the given signals
int fd = signalfd(-1, sigs, 0);
if (fd < 0) {
perror("child signalfd");
return EXIT_FAILURE;
}
struct signalfd_siginfo s;
// Loop up to nsigs times reading from the signal fd
int count = 0;
while (++count <= nsigs && read(fd, &s, sizeof s) == sizeof s) {
printf("Child received signal %s (%d)\n", strsignal(s.ssi_signo),
s.ssi_signo);
}
if (count <= nsigs && errno != EINTR) {
perror("child read");
close(fd);
return EXIT_FAILURE;
}
close(fd);
return 0;
}
Example output:
Sending process 17248 signal Hangup (1)
Sending process 17248 signal Interrupt (2)
Sending process 17248 signal Quit (3)
Sending process 17248 signal Segmentation fault (11)
Child received signal Hangup (1)
Child received signal Segmentation fault (11)
Child received signal Interrupt (2)
Child received signal Quit (3)
Your program is running perfectly in my machine, so I don't understand why do you say the child doesn't print anything.
Anyway, you have to be careful, as the child is printing the messages of the received signals, but running forever, this means that when the parent is done and exit()s you leave a child running... forever? (and you are running the child without stopping or blocking, so consuming all the available cpu)
You must devise a method to kill such a process, because if you don't you will end with lots of processes running in your behalf, doing nothing but ignoring the kill()s you do to them.
For that, there are some signals that are not ignorable, the SIGKILL is one, you cannot install a signal handler to it, for security reasons... :)
Also, when using signal(2) system call, the handler is executed on the reception of the first signal, and switches to the default behaviour (which depends on the signal) when the signal handler is done.
If you want it to be permanent, you need to reinstall the signal handler (this has a race condition, in case you receive a second signal while you are executing the signal handler and have not had time to install it again) or call sigaction(2) instead, that allows you to permanently (while the process is running, or up to the next call you do to sigaction) install a signal handler that doesn't need to be renewed. Look at the manual page of sigaction, as you need to learn how to use it.

Not receiving signal from the parent process

I am learning communication between two process using signals in C on GeeksForGeeks https://www.geeksforgeeks.org/signals-c-set-2/?ref=lbp. And I was trying to run the code provided on the website. I simply copy the code to an online C compiler.
// C program to implement sighup(), sigint()
// and sigquit() signal functions
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
// function declaration
void sighup();
void sigint();
void sigquit();
// driver code
void main()
{
int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
signal(SIGHUP, sighup);
signal(SIGINT, sigint);
signal(SIGQUIT, sigquit);
for (;;)
; /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid, SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid, SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid, SIGQUIT);
sleep(3);
}
}
// sighup() function definition
void sighup()
{
signal(SIGHUP, sighup); /* reset signal */
printf("CHILD: I have received a SIGHUP\n");
}
// sigint() function definition
void sigint()
{
signal(SIGINT, sigint); /* reset signal */
printf("CHILD: I have received a SIGINT\n");
}
// sigquit() function definition
void sigquit()
{
printf("My DADDY has Killed me!!!\n");
exit(0);
}
However, all I got is like this
PARENT: sending SIGHUP
PARENT: sending SIGINT
PARENT: sending SIGQUIT
I am wondering is it my computer problem?
The code incorrectly assumes that the child installs the handlers before the parent sends the signals. It could be so, but it is not guaranteed. Of course, if the handlers are not installed, the child is killed immediately. You may confirm that by testing that kill returns -1 and errno is set to ESRCH.
Also keep in mind that printf is not signal safe.
Not all online C compilers/environments are made equally. Try repl.it, I just tried it, and got the exact results that geeks4geeks posted.

SIGSTOP not working in c program

I am trying to write a C program in which the parent process suspends the child process and after a few seconds continues executing it.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sigstop();
void sigcont();
void sigquit();
int main()
{
int pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0)
{ /* child */
signal(SIGSTOP,sigstop);
signal(SIGCONT,sigcont);
signal(SIGQUIT, sigquit);
for(;;); /* loop for ever */
}
else {
printf("\nPARENT: sending SIGSTOP to suspend the process\n\n");
kill(pid, SIGSTOP);
sleep(5);
printf("\nPARENT: sending SIGCONT to continue the suspended process\n\n");
kill(pid, SIGCONT);
sleep(5);
printf("killing child");
kill(pid,SIGQUIT);
sleep(5);
}
}
void sigstop()
{
printf("CHILD: I've been suspended\n");
}
void sigcont()
{
printf("CHILD: I'm back\n");
}
void sigquit()
{
printf("My DADDY has Killed me!!!\n");
exit(0);
}
printf inside sigstop() never gets executed and sigquit() gets called before printf("killing child");. How does this happen and how can I get output in proper order ?
If you read the signal(7) manual page you will see that
The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
You simply can not catch that signal.
The last bit, about "Killing child" get printed in the wrong order is very easy to fix: Add a trailing newline to the string you print.
This is because output to stdout (which is what printf writes to) is by default line-buffered. This means that the internal buffer of stdout is flushed (i.e. actually written to the terminal) on a newline. If you don't have the newline, then the buffer will be flushed when the process exits, which is after you exit the child process.

sending signal from parent to child

I am using this tutorial from website http://www.code2learn.com/2011/01/signal-program-using-parent-child.html and trying to understand why signal is not recieved by child?
here is the code:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
void sighup(); /* routines child will call upon sigtrap */
void sigint();
void sigquit();
void main()
{ int pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0)
{ /* child */
signal(SIGHUP,sighup); /* set function calls */
signal(SIGINT,sigint);
signal(SIGQUIT, sigquit);
for(;;); /* loop for ever */
}
else /* parent */
{ /* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid,SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid,SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid,SIGQUIT);
sleep(3);
}
}
void sighup()
{ signal(SIGHUP,sighup); /* reset signal */
printf("CHILD: I have received a SIGHUP\n");
}
void sigint()
{ signal(SIGINT,sigint); /* reset signal */
printf("CHILD: I have received a SIGINT\n");
}
void sigquit()
{ printf("My DADDY has Killed me!!!\n");
exit(0);
}
output:
It's a race condition. Your code assumes that the child runs first and is not preempted by the parent until it installed all signal handlers and starts looping forever.
When that is not the case, the parent may send a signal to the child before the child had the chance to catch the signal. As such, the child process is killed, since the default action for SIGHUP, SIGINT and SIGQUIT is to terminate.
In your specific case, you never see any output from the child. This means that the parent sent SIGHUP to the child, and SIGHUP was delivered before the child changed the default behavior. So the child was killed.
Actually, if you did some error checking on the returning value of kill(2) - which you should - you would see ESRCH in the parent upon trying to send SIGINT and SIGQUIT, because the child is already gone (assuming no other process in the system was started and got assigned the same PID in the meantime).
So, how do you fix it? Either use some form of synchronization to force the child to run first and only let the parent execute after all signal handlers are installed, or set up the signal handlers before forking, and then unset them in the parent. The code below uses the latter approach:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sighup(int); /* routines child will call upon sigtrap */
void sigint(int);
void sigquit(int);
int main(void) {
int pid;
signal(SIGHUP,sighup); /* set function calls */
signal(SIGINT,sigint);
signal(SIGQUIT, sigquit);
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
/* child */
for(;;); /* loop for ever */
} else {
signal(SIGHUP, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
/* parent */
/* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid,SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid,SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid,SIGQUIT);
sleep(3);
}
return 0;
}
void sighup(int signo) {
signal(SIGHUP,sighup); /* reset signal */
printf("CHILD: I have received a SIGHUP\n");
}
void sigint(int signo) {
signal(SIGINT,sigint); /* reset signal */
printf("CHILD: I have received a SIGINT\n");
}
void sigquit(int signo) {
printf("My DADDY has Killed me!!!\n");
exit(0);
}
Also, you shouldn't be using signal(2): it is unreliable in many ways, and its exact semantics are platform dependent. To ensure maximum portability, you should use sigaction(2). Refer to the manpages to learn more. Here's the same code using sigaction(2) instead:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void sighup(int); /* routines child will call upon sigtrap */
void sigint(int);
void sigquit(int);
int main(void) {
struct sigaction sigact;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
sigact.sa_handler = sighup;
if (sigaction(SIGHUP, &sigact, NULL) < 0) {
perror("sigaction()");
exit(1);
}
sigact.sa_handler = sigint;
if (sigaction(SIGINT, &sigact, NULL) < 0) {
perror("sigaction()");
exit(1);
}
sigact.sa_handler = sigquit;
if (sigaction(SIGQUIT, &sigact, NULL) < 0) {
perror("sigaction()");
exit(1);
}
pid_t pid;
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) {
/* child */
for(;;); /* loop for ever */
} else {
sigact.sa_handler = SIG_DFL;
sigaction(SIGHUP, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
/* parent */
/* pid hold id of child */
printf("\nPARENT: sending SIGHUP\n\n");
kill(pid,SIGHUP);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGINT\n\n");
kill(pid,SIGINT);
sleep(3); /* pause for 3 secs */
printf("\nPARENT: sending SIGQUIT\n\n");
kill(pid,SIGQUIT);
sleep(3);
}
return 0;
}
void sighup(int signo) {
signal(SIGHUP,sighup); /* reset signal */
printf("CHILD: I have received a SIGHUP\n");
}
void sigint(int signo) {
signal(SIGINT,sigint); /* reset signal */
printf("CHILD: I have received a SIGINT\n");
}
void sigquit(int signo) {
printf("My DADDY has Killed me!!!\n");
exit(0);
}
Last, but not least, it is important to mention that you should always compile with -Wall. Your program has some mistakes:
The return type of main() should be int.
Signal handlers receive the signal number as an argument, please use the right prototype and declaration.
fork(2) returns a pid_t, not an int, please use the correct type.
You need to include unistd.h to get the right prototype for fork(2).
printf(3) is not async-signal safe and as such you shouldn't call it inside a signal handler. It's ok in this toy program to see how signals work together, but keep in mind that you should never do it in the real world. To see a list of async-signal safe functions, as well as the default actions for each signal, see man 7 signal.
Word of advice: stop learning from that website. If you want to learn this kind of stuff, read Advanced Programming in the UNIX Environment. Go straight to chaper 10 to learn why exactly signal(2) is considered unreliable and obsolescent. It's a big book, but it's well worth investing your time on it.

Resources