The overall design of my program is:
The code is roughly like this (and just in case someone would like to check the complete version, it can be found here and a Makefile
is also prepared):
volatile sig_atomic_t ev_flag = 0;
static void signal_handler(int signum) {
ev_flag = 1;
char msg[] = "Signal caught\n";
write(STDOUT_FILENO, msg, strlen(msg));
}
void install_signal_handler() {
struct sigaction act;
act.sa_handler = signal_handler;
act.sa_flags = SA_RESETHAND;
if (sigaction(SIGINT, &act, 0) + sigaction(SIGABRT, &act, 0) +
sigaction(SIGQUIT, &act, 0) + sigaction(SIGTERM, &act, 0) +
sigaction(SIGPIPE, &act, 0) + sigaction(SIGCHLD, &act, 0) +
sigaction(SIGSEGV, &act, 0) + sigaction(SIGTRAP, &act, 0) < 0) {
perror("sigaction()");
abort();
}
}
int main(void) {
install_signal_handler();
FILE *child_proc;
child_proc = popen(child_proc_cmd, "w");
while (ev_flag == 0) {
if (fwrite(data, 1, data_size, child_proc) != data_size) {
perror("fwrite()");
break;
}
}
printf("\nThe evloop quitted, gracefully\n");
pclose(child_proc);
return 0;
}
This design works well for most cases, except one: If the child process is somehow killed by kill <pid>
or kill -KILL <pid>
, my parent process won't reach
printf("\nThe evloop quitted, gracefully\n");
as expected, even if my signal_handler()
is invoked. Any thoughts? Or any bugs in my current design?
You never call install_signal_handler()
, so your signal handler is never executed.
In signal handler you would write from null pointer: write(STDOUT_FILENO, 0, strlen(msg));
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
volatile sig_atomic_t ev_flag = 0;
static void signal_handler(int signum) {
ev_flag = 1;
char msg[] = "Signal caught :";
char *sig = strsignal(signum);
write(STDOUT_FILENO, msg, strlen(msg)); // Write from buffer
write(STDOUT_FILENO, sig, strlen(sig)); // Write signal string
write(STDOUT_FILENO, "\n", 1);
}
void install_signal_handler()
{
struct sigaction act;
act.sa_handler = signal_handler;
act.sa_flags = SA_RESETHAND;
if (sigaction(SIGINT, &act, 0) + sigaction(SIGABRT, &act, 0) +
sigaction(SIGQUIT, &act, 0) + sigaction(SIGTERM, &act, 0) +
sigaction(SIGPIPE, &act, 0) + sigaction(SIGCHLD, &act, 0) +
sigaction(SIGSEGV, &act, 0) + sigaction(SIGTRAP, &act, 0) < 0) {
perror("sigaction()");
abort();
}
}
int main(void)
{
const char data[] = "Lorem ipsum dolor sit amet\n";
size_t data_size = strlen(data);
const char child_proc_cmd[] = "wc -l";
install_signal_handler(); // Install signal handlers
FILE *child_proc;
child_proc = popen(child_proc_cmd, "w");
while (ev_flag == 0) {
if (fwrite(data, 1, data_size, child_proc) != data_size) {
perror("fwrite()");
break;
}
}
printf("\nThe evloop quitted, gracefully\n");
pclose(child_proc);
return 0;
}
Output:
Signal caught :Child exited
Signal caught :Broken pipe
fwrite(): Broken pipe
The evloop quitted, gracefully