Lost signals from child to parent - c

I'm creating several child processes which send a signal to their parent process and die. I simply count them. But I never get the right count. Some signals never get caught by the handler.
How should I code this?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int ended = 0;
void handler(int sig){
ended++;
}
int main(int argc, char **argv){
int i;
pid_t pid, ppid;
if (signal(SIGUSR1, handler) < 0) {
fprintf(stderr, "signal failed.\n");
exit (-1);
}
ppid = getpid();
for (i = 0; i < 50; i++){
if ((pid = fork()) < 0){
fprintf(stderr, "fork failed.\n");
exit(-1);
}
if (pid == 0){
kill(ppid, SIGUSR1);
exit(0);
}
}
while (wait(NULL) > 0);
printf("ended = %d\n", ended);
return 0;
}
The output for this program is sometimes 47, others 39... but never 50

The problem here is that a signal acts as a hardware interruption where your handler function would be the ISR (Interrupt Service Routine). Then if multiple signals of the same value happens "at the same time" linux kernel treat them as only one signal. Signal are not designed to be used in this manner. A signal should be used to inform of the state of a process to another. To achieve communications between processes you should use IPC (InterProcess Communications) mechanisms such as queue, sockets, or pipes.

Thanks,
I found the problem can be solved using Real Time Signals. Just changing SIGUSR1 with SIGRTMIN. Real Time Signals are queued (http://man7.org/linux/man-pages/man7/signal.7.html).
Are there any negative side effects in this solution?

it was working..
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int ended = 0;
void handler(int sig)
{
ended++;
}
int main(int argc, char **argv)
{
int i;
pid_t pid, ppid;
if (signal(SIGUSR1, handler) < 0)
{
fprintf(stderr, "signal failed.\n");
exit (-1);
}
ppid = getpid();
for (i = 0; i < 50; i++)
{
if ((pid = fork()) < 0)
{
fprintf(stderr, "fork failed.\n");
exit(-1);
}
if (pid == 0)
{
kill(ppid, SIGUSR1);
exit(0);
}
}
while (wait(NULL) > 0);
printf("ended = %d\n", ended);
return 0;
}

Related

Linux shuts down after compiling basic children process

In this simple C code, I am trying to create 10 children. Then do some work (such as printing the time) in them individually. Then I try to kill all of them in parent process. You will easily understand the code below. The problem is that, whenever I run this, first it gives the various outputs from children then Linux shuts down. Then I start from passing user password and everything is closed. Why this happens?
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
int main() {
pid_t pids[10];
int i;
int n= 10;
for (i= 0; i<n; ++i) {
if ((pids[i] = fork()) <0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
struct timeval tv;
time_t t;
struct tm*info;
char buffer[64];
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
}
}
int status;
pid_t pid;
sleep(5);
while (n >0) {
pid = wait(&status);
kill((long)pid, SIGTERM);
printf("CHILD %d killed.",pid);
--n;
}
}
In process created by fork() all variables have the same value as before fork. After fork in this your code
for (i= 0; i<n; ++i) {
if ((pids[i] = fork()) <0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
...
}
}
i in child process is the same as it was in parent before fork, so for loop continue to execute and spawn a lot of grand children processes.
After loop is executed all spawned processes call wait(). Processes which are spawned on last iteration (with i==9) have no children, so wait() indicates error by returning -1 (and errno==ECHILD). Then you call kill() with pid==-1, which is:
If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init)
If you want child processes to terminate by themself then you should exit explicitly, e.g. with _exit() function. In this case you don't need to send TERM signal:
int main(void)
{
pid_t pids[10];
int i;
int n = 10;
for (i = 0; i<n; ++i)
{
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
// abort() never return, "else" is not needed
}
if (pids[i] == 0)
{
struct timeval tv;
time_t t;
struct tm*info;
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
_exit(0); // terminate process explicitly
}
}
int status;
pid_t pid;
sleep(5);
while (n > 0)
{
pid = wait(&status);
// No kill needed for already exited process
// kill((long)pid, SIGTERM);
if (pid == -1)
{
perror("wait");
abort();
} else {
printf("CHILD %d killed.\n", pid);
}
--n;
}
}
If you want to terminate child processes from parent process then children should wait until terminated, but you should send signal before waiting for child process termination:
int main(void)
{
pid_t pids[10];
int i;
int n = 10;
for (i = 0; i<n; ++i)
{
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
// abort() never return, "else" is not needed
}
if (pids[i] == 0)
{
struct timeval tv;
time_t t;
struct tm*info;
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
// wait until terminated
for (;;)
pause();
}
}
int status;
pid_t pid;
sleep(5);
for (i = 0; i<n; ++i) {
if (kill(pids[i], SIGTERM) == -1) {
perror("kill");
}
}
while (n--)
{
pid = wait(&status);
if (pid == -1)
{
perror("wait");
abort();
} else {
printf("CHILD %d killed.\n", pid);
}
}
}

Blocking signals in C

I am currently trying to write a program that calls fork() to spawn a child process which sends a random number of signals to the parent process. Both the child and the parent process should show the same number, but I have an issue with blocking the signals when incrementing the counter.
I tried multiple methods of blocking the signals but I have failed. Anybody with a suggestion? Thanks a lot.
int nreceived = 0;
void handler(int sig)
{
nreceived++;
signal(SIGUSR1,handler);
}
int main()
{
int nsignals;
pid_t pid;
srand(time(NULL));
nsignals = rand() % 256;
signal(SIGUSR1,handler);
if((pid = fork()) > 0)
{
wait(NULL);
printf("Received %d signals from process %d\n",nreceived,pid);
}
else if (pid == 0)
{
for(int i = 0; i < nsignals; i++)
kill(getppid(),SIGUSR1);
printf("Sent %d signals to process %d\n", nsignals, getppid());
}
return 0;
}
As discussed extensively in the comments, it is important to use POSIX function sigaction() rather than the standard C function signal() because there are many implementation-defined aspects to signal() (primarily because there were many divergent implementations before the C standard was created, and the standard tried to accommodate existing implementations without breaking any of them).
However, the system is not obligated to queue signals that are not real-time signals (signal numbers in the range SIGRTMIN..SIGRTMAX). SIGUSR1 is not a real-time signal. Frankly, even with signal queueing, I'm not sure whether implementations would handle up to 255 pending signals of a specific type for a process — it isn't an area I've experimented with.
This is the best code I was able to come up with:
#include <assert.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifndef SEND_SIGNAL
#define SEND_SIGNAL SIGUSR1
#endif
static const char *arg0;
static volatile sig_atomic_t nreceived = 0;
static _Noreturn void err_syserr(const char *syscall);
static void handler(int sig)
{
assert(sig == SEND_SIGNAL);
nreceived++;
}
int main(int argc, char **argv)
{
if (argc != 1)
{
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(EXIT_FAILURE);
}
arg0 = argv[0];
struct sigaction sa = { .sa_handler = handler, .sa_flags = SA_RESTART };
/* Block all blockable signals */
if (sigfillset(&sa.sa_mask) != 0)
err_syserr("sigfillset");
if (sigaction(SEND_SIGNAL, &sa, 0) != 0)
err_syserr("sigaction");
pid_t pid = fork();
if (pid > 0)
{
int status;
int corpse = wait(&status);
if (corpse != -1)
printf("Child process %d exited with status 0x%.4X\n", corpse, status);
else
fprintf(stderr, "%s: wait() failed: (%d) %s\n", argv[0], errno, strerror(errno));
printf("Caught %d signals from process %d\n", nreceived, pid);
}
else if (pid == 0)
{
srand(time(NULL));
int nsignals = rand() % 256;
for (int i = 0; i < nsignals; i++)
kill(getppid(), SEND_SIGNAL);
printf("Sent %d signals to process %d\n", nsignals, getppid());
}
else
err_syserr("fork");
return 0;
}
static _Noreturn void err_syserr(const char *syscall)
{
fprintf(stderr, "%s: %s() failed: (%d) %s\n", arg0, syscall, errno, strerror(errno));
exit(EXIT_FAILURE);
}
When run as program sig53 (source code sig53.c) on a Mac running macOS Monterey 12.3.1, I got variable numbers of signals received:
$ sig53
Sent 50 signals to process 37973
Child process 37974 exited with status 0x0000
Caught 14 signals from process 37974
$: sig53
Sent 39 signals to process 38442
Child process 38443 exited with status 0x0000
Caught 16 signals from process 38443
$: sig53
Sent 28 signals to process 38478
Child process 38479 exited with status 0x0000
Caught 6 signals from process 38479
$
Sometimes, the number received reached near 100, but never very near to all the signals sent.
YMMV on Linux. There may be alternative mechanisms for handling signals on Linux. But for portable code, sending a myriad signals to a single process at full tilt is not a reliable way of communicating between processes. Some of the signals will be delivered, but it may not be all of them.

System Calls in C signals and fork

Hi I've this problem to solve with a functional program in C.
"Write a C program where a process F create a childprocess C.
The childprocess C waits the user to type the password, if is correct sends a signal SIGUSR1 to the father, if after 3 attempts the password is still incorrect it will send a SIGUSR2 signal to the father and terminate; if it receives from the father SIGUSR1 signal must stop viewing the "timeout" message.
His father after 30 seconds (if it has not received any signal from the child) must send the signal SIGUSR1 to the child and end with exit(1); if it receives the SIGUSR1 signal must end with exit(0); if it receives the signal SIGUSR2 must end with exit (2)."
I'm trying to solve it but I'm stuck. This is what I've done:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
void fatherprocess(int mysignal){
if (mysignal == SIGUSR1) {
printf("ACCESS GRANTED!\n");
exit(0);
}
if (mysignal == SIGUSR2){
printf("ACCESS DISCARDED! More than 3 tentatives!\n");
exit(2);
}
}
void childprocess(int mysignal){
if (mysignal == SIGUSR1) {
printf("TIMEOUT\n");
exit(1);
}
}
int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[], password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;
fatherpid = getpid();
childpid = fork();
if (childpid == 0) {
printf("Child Process waiting for a password\n");
while (1){
if (i < 3) {
printf("Enter Password: ");
scanf("%s", enteredpassword);
if (enteredpassword == password)
signal(SIGUSR1, fatherprocess);
} else {
signal(SIGUSR2, fatherprocess);
exit(1);
}
i++;
}
} else {
printf("Father Process\n");
while(time_to_sleep){
time_to_sleep = sleep(time_to_sleep);
signal(SIGUSR1, childprocess);
}
}
return 0;
}
I've edited my program in this way:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
void fatherprocess(int mysignal, int fatherpid){
if (mysignal == SIGUSR1) {
printf("ACCESS GRANTED!\n");
kill(fatherpid, SIGUSR1);
exit(0);
}
if (mysignal == SIGUSR2){
printf("ACCESS DISCARDED! More than 3 tentatives!\n");
kill(fatherpid, SIGUSR2);
exit(2);
}
}
void childprocess(int mysignal, int childpid){
if (mysignal == SIGUSR1) {
printf("TIMEOUT\n");
kill(childpid, SIGUSR1);
exit(1);
}
}
int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[] = "test", password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;
fatherpid = getpid();
childpid = fork();
if (childpid == 0) {
printf("Child Process waiting for a password\n");
while (1){
if (i < 3) {
printf("Enter Password: ");
scanf("%s", enteredpassword);
if (strcmp(enteredpassword, password) == 0)
fatherprocess(SIGUSR1, fatherpid);
} else {
fatherprocess(SIGUSR2, fatherpid);
exit(1);
}
i++;
}
} else {
printf("Father Process\n");
while(time_to_sleep){
time_to_sleep = sleep(time_to_sleep);
childprocess(SIGUSR1, childpid);
}
}
return 0;
}
Now it works perfectly but I don't know if I've respected the exercise text.
As was mentioned in the comments (by Jonathan Leffler), you need to use the kill() system call (to send the signals) and register a signal handler using a call like sigaction(). I have linked these two calls to online manual pages that provide additional information about them.
Here's some code that demonstrates how these can be used towards achieving your stated goal. You will still need to add/modify the code for things like the prompts you want and the acceptable input string. Please note that I'm not claiming this to be the best way to do it, only that it's an example of how it could be done (it compiled and worked for me):
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
static void get_password(char* buf, int maxbuf)
{
fgets(buf, maxbuf, stdin);
}
static int is_password_correct(char* buf)
{
return buf[0] == 'a';
}
volatile int got_signal = 0;
volatile int child_signal = 0;
static void parent_sig_handler(int signum)
{
if (!got_signal)
{
got_signal = signum;
printf("parent_sig_handler: got sig %d\n", signum);
}
}
static void child_sig_handler(int signum)
{
if (!child_signal)
{
child_signal = signum;
printf("child_sig_handler: got sig %d\n", signum);
}
}
int main()
{
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_handler = parent_sig_handler;
sigaction(SIGALRM, &act, NULL);
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
pid_t child_pid = fork();
if (child_pid == -1)
{
perror("error forking");
exit(3);
}
if (child_pid == 0)
{
printf("child running\n");
act.sa_handler = child_sig_handler;
sigaction(SIGUSR1, &act, NULL);
pid_t parent_pid = getppid();
for (int i = 0; i < 3; ++i)
{
char passwd[64];
passwd[0] = '\0';
get_password(passwd, sizeof(passwd));
if (is_password_correct(passwd))
{
kill(parent_pid, SIGUSR1);
exit(0);
}
}
kill(parent_pid, SIGUSR2);
exit(2);
}
printf("parent running\n");
alarm(30); /* sets parent up to receive a SIGALRM signal in 30 seconds */
sigset_t sigmask;
sigemptyset(&sigmask);
while (!got_signal)
{
sigsuspend(&sigmask);
}
switch (got_signal)
{
case SIGALRM:
kill(child_pid, SIGUSR1);
exit(1);
case SIGUSR1:
exit(0);
case SIGUSR2:
exit(2);
default:
exit(3);
}
exit(3);
}

Fork() and Posix Queues. Send and Receive strings

what I want is this:
1 main process that create 4 children process where:
-> The main process receive messages from the children through the queue and print the message recieved.
-> The children send messages (a string with priority+message) through the queue and finish.
All in a while (1), so, when you CTRL+C, the children finish first (the signal is in the children code) and then, the parent finish.
For the moment, I am having problem with mq_send() and mq_recieve().
Well, this is my code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
void sigint_handler()
{
/*do something*/
printf("killing process %d\n",getpid());
exit(0);
}
int main ()
{
mqd_t mqd;
struct mq_attr atributos;
// atributos.mq_maxmsg = 10;
//
// atributos.mq_msgsize = 50;
printf ("This is the parent. PID=%d\n",getpid ());
int num_children = 4;
int i;
int pid;
int status;
char buffer [50];
while (1){
for (i=0; i<num_children ;i++){
if ((pid=fork()==0)){
signal(SIGINT, sigint_handler);
int prio = rand () % 3;
printf ("%d\n",prio);
char * msg= "Hi dude";
char * priority=NULL;
if (prio == 0){
priority = "NORMAL";
}
else {
priority = "URGENT";
}
char* toSend=NULL;
toSend = malloc(strlen(msg)+1+strlen(priority));
strcpy (toSend,priority);
strcat (toSend,msg);
printf ("%s\n",toSend);
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
if (mq_send(mqd, msg , strlen(toSend), prio) == -1) {
printf ("Error mq_send\n");
exit (-1);
}
mq_close(mqd);
printf ("This is children %d\n",getpid());
sleep(1);
exit(0);
}
}
if ((mqd=mq_open("/queue.txt", O_CREAT|O_WRONLY, 0777, &atributos))==-1){
printf ("Error mq_open\n");
exit(-1);
}
//Rest Parent code
if (mq_receive(mqd, buffer, strlen(buffer),0)==-1){
printf ("Error mq_recieve\n");
exit(-1);
}
printf("Received: %s\n",buffer);
sleep (1);
waitpid(pid,&status,0);
printf ("This is the parent again %d, children should have finished\n",getpid());
mq_close(mqd);
}
}
I don't know why both mq_send() and mq_receive() returns -1, what am I doing wrong¿?
And you you see something wrong in my code in order to do what I intend apart from the error I am talking about, let me know.
Thank you in advance, I appreciate any help.
user58697 touched upon the biggest problems.
(1) Your queue opens were failing with EINVAL because you wee passing uninitialized attributes because you commented out assignments.
(2) You were opening both queues for write-only. The parent queue needed to be opened in read mode.
(3) Execute permissions don't mean anything to a queue so 777 permissions while not invalid are unnecessary.
(4) Your sends/receives were failing because of invalid lengths. In many if not most cases it is just easier and safer to allocate your buffers to the length attribute of the queue. In this case you know the length before hand but in programs that don't you can get the value via mq_getattr.
(5) You weren't calling srand to seed the RNG before calling rand.
(6) You had a memory leak where you allocate space (unnecessarily) for the message but never freed it.
(7) What you were trying to do with passing priorities is redundant. POSIX MQs have priorities already built in. You can just use those.
I took out some of the fluff (mainly the loops & signals) to concentrate more on the queue aspects of your program.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
#include <mqueue.h>
int main()
{
srand(time(NULL));
mqd_t mqd;
struct mq_attr atributos = {.mq_maxmsg = 10, .mq_msgsize = 50};
int i;
int pid;
int status;
int num_children = 4;
char buffer[atributos.mq_msgsize];
for (i = 0; i < num_children; i++)
{
if ((pid = fork() == 0))
{
int prio = rand () % 3;
char* msg = "Hi dude";
strncpy (buffer, msg, sizeof(buffer));
if ((mqd = mq_open("/queue.txt", O_CREAT | O_WRONLY, 0666, &atributos)) == -1)
{
perror("child mq_open");
exit(1);
}
if (mq_send(mqd, buffer, sizeof(buffer), prio) == -1)
{
perror("mq_send");
exit(1);
}
mq_close(mqd);
exit(0);
}
}
// parent
if ((mqd = mq_open("/queue.txt", O_CREAT | O_RDONLY, 0666, &atributos)) == -1)
{
perror("parent mq_open");
exit(1);
}
int priority;
for (int i = 0; i < num_children; ++i)
{
if (mq_receive(mqd, buffer, sizeof(buffer), &priority) == -1)
{
perror("mq_recieve");
exit(1);
}
printf("Received (%s): %s\n", (priority == 0) ? "NORMAL" : "URGENT", buffer);
pid_t childpid;
if ((childpid = waitpid(-1, &status, 0)) > 0)
{
if (WIFEXITED(status))
printf("PID %d exited normally. Exit status: %d\n",
childpid, WEXITSTATUS(status));
else
if (WIFSTOPPED(status))
printf("PID %d was stopped by %d\n",
childpid, WSTOPSIG(status));
else
if (WIFSIGNALED(status))
printf("PID %d exited due to signal %d\n.",
childpid,
WTERMSIG(status));
}
}
mq_close(mqd);
}
First and foremost, when a system call fails, print errno (and strerror(errno)).
Now, obvious mistakes:
as was mentioned, you need a read access to be able to mq_receive()
what is strlen(buffer)?
you are passing attributes without initializing them.
To summarize, print errno and see what is wrong.

Ping-pong using kill and flags in POSIX

I'm trying to implement interprocess communication by using POSIX signals in C, especially I'm writing Ping-Pong problem. So here's my source code:
#define CHILD 0
#define PARENT 1
int flag[2];
void handler(int sig) {
if (sig == SIGUSR1) {
flag[PARENT] = 1;
} else {
flag[CHILD] = 1;
}
return;
}
void child_process() {
while (1) {
printf("Ping!\n");
kill(getppid(), SIGUSR2);
while (flag[PARENT] == 0) { }
}
return;
}
void parent_process(pid_t t) {
while (1) {
//kill(t, SIGUSR1);
while (flag[CHILD] == 0) { }
printf("Pong!\n");
kill(t, SIGUSR1);
}
return;
}
void setup() {
flag[CHILD] = 0;
flag[PARENT] = 0;
signal(SIGUSR1, handler);
signal(SIGUSR2, handler);
}
int main(int argc, char* argv[]) {
setup();
pid_t t = fork();
if (t == 0) {
child_process();
} else {
parent_process(t);
}
return 0;
}
My program is not working properly, because sometimes I get "Pong!" "Pong!" "Pong!" or "Ping!" "Ping!" output. What's the problem?
And one more question, is my way of handling signals correct? Or there are more advanced ways to do it?
(1) Parent and child do not share the same memory. flag[CHILD] and flag[PARENT] will never know about each other because they are different copies in different processes.
(2) Yes, pretty much everything about your signal handling is wrong for what you are trying to do. You are trying to synchronize the signals so you need to use a mechanism that actually synchronizes them e.g. sigsuspend.
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
void sig_hand(int sig) {}
sigset_t saveMask, blockMask;
void child_process()
{
int x = 0;
while(x < 10)
{
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
printf("Pong %d!\n", ++x);
kill(getppid(), SIGUSR1);
}
return ;
}
void parent_process(pid_t pid)
{
int y = 0;
while (y < 10)
{
printf("Ping %d!\n", ++y);
kill(pid, SIGUSR1);
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
}
return ;
}
int main(int argc, char* argv[])
{
//block SIGUSR1 in parent & child until ready to process it
sigemptyset(&blockMask);
sigaddset(&blockMask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &blockMask, &saveMask) == -1)
errExit("sigprocmask");
//set up signal handler for parent & child
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sig_hand;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
errExit("sigaction");
pid_t pid = fork();
if (pid == 0)
child_process();
else
parent_process(pid);
return 0;
}
Although it may not be your problem, remember anytime you are modifying variables asynchronous to program flow, you need to make those variables volatile so that the compilers does not optimize the accesses to them away.
I would think that semaphore.h has much more useful tools (sem_open, sem_post, sem_wait, sem_trywait).
I'd use the sigaction() and pause() functions, along with nanosleep() to rate-limit the activity.
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
enum { MAX_PINGS = 10 };
static sig_atomic_t sig_num;
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, ": (%d) %s", errnum, strerror(errnum));
putc('\n', stderr);
}
static void catcher(int sig)
{
sig_num = sig;
}
static void child_process(void)
{
struct timespec nap = { .tv_sec = 0, .tv_nsec = 100000000 };
while (1)
{
pause();
printf("Pong!\n");
nanosleep(&nap, 0);
kill(getppid(), SIGUSR1);
}
}
static void parent_process(pid_t pid)
{
struct timespec nap = { .tv_sec = 0, .tv_nsec = 100000000 };
for (int pings = 0; pings < MAX_PINGS; pings++)
{
printf("Ping %d!\n", pings);
nanosleep(&nap, 0);
kill(pid, SIGUSR1);
pause();
}
kill(pid, SIGTERM);
}
int main(void)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = catcher;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
err_exit("Failed to set SIGUSR1 handler");
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork()");
else if (pid == 0)
child_process();
else
parent_process(pid);
return 0;
}
The variable sig_num is there to quell complaints from the compiler about unused arguments (to the catcher function). The signal catcher is set before the fork(). The child process pauses until a signal arrives; then prints 'Pong!', takes a nap for 1/10 seconds, and then signals the parent process to wake. The parent process prints 'Ping!', takes a nap, signals the child process, and pauses until a signal arrives. It limits the loops to 10 (enough to show it is working), and when it is done, terminates the child before exiting.
Example output
$ ./pingpong
Ping 0!
Pong!
Ping 1!
Pong!
Ping 2!
Pong!
Ping 3!
Pong!
Ping 4!
Pong!
Ping 5!
Pong!
Ping 6!
Pong!
Ping 7!
Pong!
Ping 8!
Pong!
Ping 9!
Pong!
$
Clearly, it would not be hard to print a counter on the 'Pong' values too.

Resources