Nowadays, I'm learning signals by own efforts with concurrency. However, I have some problems while using them in action. In this program, I expect that there are two processes (one child - one parent), parent sends SIGHUP, SIGINT, SIGTSTP signals to its child respectively. I want the child to handle them in same order. I'm trying to apply synchronization with signals here. I have two major problems that
- When parent runs at first prior its child, it works but it misses
SIGINT, not go into its handler. - When child runs at first prior its parent, it blocks. I expect in either way the program runs well.
I really appreciate as well if you let me inform the other issues and their solutions along with the major ones'.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
char const * hupMsg = "CHILD: I have received a SIGHUP\n";
int hupMsgLen;
void sighup(int x) {
write(STDERR_FILENO, hupMsg, hupMsgLen);
}
char const * intMsg = "CHILD: I have received a SIGINT\n";
int intMsgLen;
void sigint(int x) {
write(STDERR_FILENO, intMsg, intMsgLen);
}
char const * die = "CHILD: My DADDY has Killed me!!!\n";
int dieLen;
void sigtstp(int x) {
write(STDERR_FILENO, die, dieLen);
exit(111); // <-- child dies with 111 exit code
}
char const * sigusr1Msg = "SIGUSR1 is being caught\n";
int sigusr1MsgLen;
void sigusr1(int x) {
write(STDERR_FILENO, sigusr1Msg, sigusr1MsgLen);
}
int main()
{
dieLen = strlen(die);
sigusr1MsgLen = strlen(sigusr1Msg);
hupMsgLen = strlen(hupMsg);
intMsgLen = strlen(intMsg);
int pid;
sigset_t allBlockedMask, prevMask, parentUSR1Mask,
sighupSet, sigintSet, sigtstpSet;
sigfillset(&sighupSet);
sigdelset(&sighupSet, SIGHUP);
sigfillset(&sigintSet);
sigdelset(&sigintSet, SIGINT);
sigfillset(&sigtstpSet);
sigdelset(&sigtstpSet, SIGTSTP);
sigfillset(&allBlockedMask);
sigfillset(&parentUSR1Mask);
sigdelset(&parentUSR1Mask, SIGUSR1);
struct sigaction saINT, saHUP, saTSTP;
memset(&saINT, 0, sizeof(saINT));
memset(&saHUP, 0, sizeof(saHUP));
memset(&saTSTP, 0, sizeof(saTSTP));
saINT.sa_flags = 0;
saINT.sa_handler = sigint;
saHUP.sa_flags = 0;
saHUP.sa_handler = sighup;
saTSTP.sa_flags = 0;
saTSTP.sa_handler = sigtstp;
struct sigaction saUSR1;
memset(&saUSR1, 0, sizeof(saUSR1));
saUSR1.sa_flags = 0;
saUSR1.sa_handler = sigusr1;
sigaction(SIGUSR1, &saUSR1, 0);
/* get child process */
if ((pid = fork()) < 0) {
perror("fork");
exit(1);
}
if (pid == 0) { /* child */
fprintf(stderr, "child pid %i\n", getpid());
/* critical section to set signal handlers */
sigprocmask(SIG_BLOCK, &allBlockedMask, &prevMask);
fprintf(stderr, "child in blocking\n");
/* set function calls */
sigaction(SIGHUP, &saHUP, 0);
sigaction(SIGINT, &saINT, 0);
sigaction(SIGTSTP, &saTSTP, 0);
/* let parent know, you can continue your process */
kill(getppid(), SIGUSR1);
fprintf(stderr, "child now UNblocked \n");
sigprocmask(SIG_SETMASK, &prevMask, 0);
/* here, I want to receive signals in turn */
sigsuspend(&sighupSet);
sigsuspend(&sigintSet);
sigsuspend(&sigtstpSet);
}
else {
/* parent */
//sleep(2);
fprintf(stderr, "parent pid %i\n", getpid());
fprintf(stderr, "parent is waiting\n");
sigsuspend(&parentUSR1Mask);
fprintf(stderr, "parent is running\n");
fprintf(stderr, "\nPARENT: sending SIGHUP\n");
kill(pid, SIGHUP);
fprintf(stderr, "\nPARENT: sending SIGINT\n");
kill(pid, SIGINT);
fprintf(stderr, "\nPARENT: sending SIGTSTP\n\n");
kill(pid, SIGTSTP);
wait(0);
}
return 0;
}
Sample output when parent runs at first:
parent pid 4628
parent is waiting
child pid 4629
child in blocking
child now UNblocked
SIGUSR1 is being caught
parent is running
PARENT: sending SIGHUP
PARENT: sending SIGINT
PARENT: sending SIGTSTP
CHILD: I have received a SIGHUP
CHILD: My DADDY has Killed me!!!
Process finished with exit code 0
Sample output when child runs at first:
child pid 4657
child in blocking
child now UNblocked
SIGUSR1 is being caught
parent pid 4656
parent is waiting
.
.
.
exit()is not async-signal-safe. You must not call it from a signal handler. You may use_exit()instead, but sure to understand the difference between the two. - John Bollingerexit()is like garbage collector, closes file descriptors, deallocate memory blocks before exiting whilst_exit()doesn't. Is there other point I missed? - snrexit()does that_exit()does not are to flush open streams and to call registered atexit handlers. - John Bollinger