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");
}
CodePudding user response:
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");
}
CodePudding user response:
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)