Problems sending/handling signals across two processes on same computer - C programming - c

I'm having trouble handling signals between two process I have running on my computer. scheduler.c is sending the signals and producer.c receiving them. The producer is supposed to print "Printing n" where n is incremented by one each time a SIGUSR1 is received. I have tried using both signal and sigaction to handle the signals but neither is working for me.
scheduler.c:
/*
* scheduler.c
*/
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int n = 1;
int main(int argc, char *argv[])
{
int a = 0; // This variable will be used for the switch later
// Check to ensure correct number of command line arguments
if(argc != 2){
printf("Usage error. Wrong number of arguments\n");
return 1;
}
// Grab PID of producer.c
int producer_pid = atoi(argv[1]);
while(1){
printf("Choose an Option: \n");
printf("1. Request_Production\n");
printf("2. Stop_Producer\n");
printf("3. Stop_Scheduler\n");
scanf("%d", &a);
switch( a )
{
case 1:
kill(producer_pid, 16); //Send SIGUSR1 to producer.c
break;
case 2:
kill(producer_pid, 2); //Send SIGINT to producer.c
break;
// Successfully exit program
case 3:
return 0;
// Invalid Choice
default :
printf("Invalid choice\n");
}
}
}
producer.c:
/*
* producer.c
*/
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int n = 1;
void sigusr1(int signo)
{
printf("Producing %d", n);
n++;
}
int main()
{
struct sigaction act;
sigset_t block_mask;
sigfillset(&block_mask);
act.sa_handler = sigusr1;
act.sa_mask = block_mask;
act.sa_flags = 0;
if(sigaction(SIGUSR1, &act, NULL) == 0){
printf("success");
}
while(1) {
sleep(2);
fflush(stdout);
}
}

This code works for me (on Mac OS X 10.7.5):
producer.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static volatile sig_atomic_t n = 0;
static void sigusr1(int signo)
{
n += signo / SIGUSR1;
}
int main(void)
{
struct sigaction act;
sigset_t block_mask;
sigfillset(&block_mask);
act.sa_handler = sigusr1;
act.sa_mask = block_mask;
act.sa_flags = 0;
if (sigaction(SIGUSR1, &act, NULL) == 0)
{
printf("success %d\n", (int)getpid());
while (1)
{
pause();
printf("Producer: %d\n", n);
fflush(stdout);
}
}
}
scheduler.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int a = 0; // This variable will be used for the switch later
// Check to ensure correct number of command line arguments
if (argc != 2)
{
fprintf(stderr, "Usage: %s pid\n", argv[0]);
return 1;
}
// Grab PID of producer.c
int producer_pid = atoi(argv[1]);
while(1)
{
printf("Choose an Option: \n");
printf("1. Request Production\n");
printf("2. Stop Producer\n");
printf("3. Stop Scheduler\n");
scanf("%d", &a);
switch (a)
{
case 1:
if (kill(producer_pid, SIGUSR1) != 0)
fprintf(stderr, "Failed to send signal %d to %d\n", SIGUSR1, producer_pid);
break;
case 2:
if (kill(producer_pid, SIGTERM) != 0)
fprintf(stderr, "Failed to send signal %d to %d\n", SIGTERM, producer_pid);
break;
// Successfully exit program
case 3:
return 0;
// Invalid Choice
default :
fprintf(stderr, "Invalid choice (%d)\n", a);
break;
}
}
}
Sample output
$ (./producer &)
$ success 40119
$ ./scheduler 40119
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 1
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 2
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 3
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 4
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 5
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 6
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 7
1
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
Producer: 8
2
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
1
Failed to send signal 30 to 40119
Choose an Option:
1. Request Production
2. Stop Producer
3. Stop Scheduler
3
$
What changed?
Various changes, but the key ones are:
Ensure that output messages end with a newline.
Make n into a volatile sig_atomic_t variable; that's what the C standard says you can access in a signal handler.
Have the main loop in the producer pause() and then print. The pause() system call only returns when interrupted by a signal.
Use symbolic signal names in the scheduler too.
Have the scheduler send SIGTERM rather than SIGINT to terminate the producer. If the producer is run in background, it is ignoring interrupts.
Have the scheduler identify when the kill() calls fail.
Have the producer identify its PID.
I've removed the superfluous headers from the file headings.
The funny signo / SIGUSR1 in the signal handler avoids warnings about unused arguments; it serves no other purpose. As shown, the programs compile cleanly under:
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition scheduler.c -o scheduler
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition producer.c -o producer
This is using GCC 4.7.1.

One remark:
There are functions which are safe and others which are not safe to be called from signal handlers.
printf may not be called from a signal handler. write on the other hand is safe.
The list is specified by POSIX-1, but details may vary between operating systems. For Linux, you will find the list in the signal(7):
http://linux.die.net/man/7/signal

Related

Hard time with lldb and signals. SIGSTOP issue

I am used to gdb. Now, as I had switched to FreeBSD, I try to use lldb.
The program uses kqueue to wait on SIGINT, SIGTERM, SIGQUIT signals. Now if lldb attaches to the process, or runs target with command line arg, the debugger sends SIGSTOP signal. One thing is that SIGSTOP can't be ignored and wait on.
The problem is, that kevent returns -1 on process resume and proceeds to quit. I can not see no output to stderr, that is another question being asked in different post.
What is a practice to deal with signals when lldb is a debugger?
Update
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
#include <yma/yerror.h>
#include <yma/ybsd_sock.h>
#define TERMINATE_SET(s, v, l) { EXPAND(s) = v; PRINT_ERROR() goto EXPAND(l); }
#define NSIGNALS (5)
#define NSOCKETS (2)
#define SIGNALS {SIGINT, SIGQUIT, SIGTERM, SIGCONT, SIGPIPE}
#define NKEVBACKLOG (NSIGNALS + (NSOCKETS * 4)) /* signals + socket reads/writes + socket error + eof */
#define BUFSIZE (1024)
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
/* program status */
int status = 0;
/* restore signals at program exit ? */
bool b_restore_procmask = false;
/* signal masks */
sigset_t mask_block_sigs, mask_save_sigs, mask_kqueue_sigs;
struct kevent chlist[10]; /* events to monitor */
struct kevent evlist[NKEVBACKLOG]; /* events that were triggered */
int kq = -1, i, n;
/* signals being monitored by kqueue */
int signals[] = SIGNALS;
/* create kqueue descriptor */
if((kq = kqueue()) < 0){
TERMINATE_SET(status, -1, l_end)
}
/* set up signals */
sigemptyset(&mask_block_sigs);
/* these signals will be blocked. the signals will arrive */
/* to kqueue and not to a default signal handler. */
for(i = 0; i < NSIGNALS; ++i){
sigaddset(&mask_block_sigs, signals[i]);
}
/* save old sigmask, replace it with new sigmask */
status = sigprocmask(SIG_BLOCK, &mask_block_sigs, &mask_save_sigs);
TERMINATE_IF(status < 0, l_end)
b_restore_procmask = true;
/* set signal event */
for(i = 0; i < NSIGNALS; i++){
EV_SET(&chlist[i], signals[i], EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
}
/* end of signal setup */
/* add signals change list to kqueue */
n = kevent(kq, chlist, NSIGNALS, NULL, 0, NULL);
if(n < 0){
TERMINATE_SET(status, -1, l_end)
}
/* event loop */
while( 1 ) {
/* see event list */
n = kevent(kq, NULL, 0, evlist, NKEVBACKLOG, NULL);
switch(n) { /* switch on kevent return */
/* timeout */
case 0:
break;
/* error */
case -1:
TERMINATE_SET(status, -1, l_end);
/* some events */
default: {
int ev_id;
/* process events */
for(i = 0; i < n; ++i){
ev_id = evlist[i].ident;
/* check if signal has arrived */
switch(ev_id){
case SIGINT:
printf(" ! got SIGINT\n");
goto l_end;
case SIGQUIT:
printf(" ! got SIGQUIT\n");
goto l_end;
case SIGTERM:
printf(" ! got SIGTERM\n");
goto l_end;
case SIGPIPE:
printf(" ! got SIGPIPE\n");
break;
default: break;
}
} break; /* end process events */
} /* end kevent return switch */
} /* end event loop */
l_end:
/* restore procmask */
if(b_restore_procmask && (sigprocmask(SIG_SETMASK, &mask_save_sigs, NULL) < 0)){
PRINT_ERROR()
}
/* close kqueue */
CLOSE(kq);
return status;
}
The above is a complete source of a program that waits on POSIX signals.
I do not want to include my makefile, as it is irrelevant here. Something like clang -std=c2x -Wall -Wpedantic -Wextra -Wfatal-errors -O0 -g3 -glldb -fpic -c kevent.c -o outp should go.
Update
The program is indeed exits with "Interrupted system call"
Update
As I read again through the code, I've found an error. The error was in misplaced ev_id initialization. The initialization were before for event loop. So the above code reacts to SIGINT as expected.
Update
But again, when I attach to process, and not run it as an argument to lldb, I am being confused again. If I send SIGINT to the process, lldb is ignoring the fact that process handle SIGINT -s false -p true and quits with "Interrupted system call."

how to immediately wake up the daemon by sending him a SIGUSR1 signal

I wrote a program deamon which copy files with one folder to another .I have to implement SIGUSR1 which immediately wake up the daemon by sending him a SIGUSR1 signal. I do not know what I did wrong ,I use command kill -SIGUSR1 ,maybe wrong command?.Somebody know what is wrong with this code ?I did not have any warning after compiled this program,but just nothing happend
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#define _XOPEN_SOURCE ;
int recursion = 0; //1 if enabled, otherwise 0
int sleepTime = 300;
int fileLimit = 0;
int signaL = 0;
int exitSignal = 0;
int buffer = 1000;
//Returns 0 if arguments are correct otherwise returns 1
int readArguments(int number, char **argv, char *source, char *goal);
int checkFileType(struct stat file);
int copy(char *source, char *target, mode_t mask);
int copy_map(char *source, char *target, struct stat *Source);
void syncCopy(char *source, char *target);
void syncRemove(char *source, char *target);
void my_handler(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR1\n");
signaL = 1;
}
void exitFunction(int sig)
{
syslog(LOG_INFO, "Daemon received signal SIGUSR2\n");
exitSignal = 1;
}
int main(int argc, char **argv)
{
//char tables for paths
char source[500], goal[500];
struct stat Source, Goal;
struct sigaction my_action, old_action;
//checking and reading arguments
if (readArguments(argc, argv, source, goal) == 1)
exit(-1);
//checking paths
//checking if argv[1] and argv[2] are existing paths
if (lstat(source, &Source) != 0 || lstat(goal, &Goal) != 0) //bad result
{
printf("One of the paths or both dont exist\n");
exit(-1);
}
if (checkFileType(Source) != 0)
{
printf("Source path is not path to folder");
exit(-1);
}
if (checkFileType(Goal) != 0)
{
printf("Goal path is not path to folder");
exit(-1);
}
//forking the parent process
pid_t pid;
// Fork off the parent process and create new
pid = fork();
//if failure
if (pid < 0)
{
exit(-1);
}
// if it is native process
else if (pid > 0)
{
return 0;
}
//if pid==0 then it is childs process
//now we have to umask in order to write to any files(for exmaple logs)
umask(0);
openlog("logFile", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "Deamon has just started running\n");
pid_t sid = setsid();
if (sid < 0)
{
syslog(LOG_ERR, "Error with session opening\n");
exit(-1);
}
//SIGNAL SIGUSR1
my_action.sa_handler = my_handler;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR1, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR1 signal\n");
exit(-1);
}
//SIGNAL SIGUSR2 for exiting daemon
my_action.sa_handler = exitFunction;
sigfillset(&my_action.sa_mask);
my_action.sa_flags = 0;
if (sigaction(SIGUSR2, &my_action, &old_action) < 0)
{
syslog(LOG_ERR, "Error with the use of SIGUSR2 signal\n");
exit(-1);
}
while (!exitSignal)
{
sleep(sleepTime);
switch (signaL)
{
case 0:
syslog(LOG_INFO, "Demon started working after %ds\n", sleepTime);
break;
case 1:
{
syslog(LOG_INFO, "Demon started working after SIGUSR1 signal\n");
signaL = 0; //Need to reeset signaL
break;
}
}
syncCopy(source, goal);
syncRemove(source, goal);
syslog(LOG_INFO, "Demon has just gone to sleep");
}
//at the end of program we need to close log using
syslog(LOG_INFO, "Demon has stopped\n");
closelog();
return 0;
}
Use command as kill -10 <pid> for SIGUSR1 and kill -12 <pid> for SIGUSR2.
kill -l // command to know the signal number.
Also make variable signaL , exitSignal as volatile sig_atomic_t type.
WHY volatile?
when a global variable updated in signal handler is periodically checked in some other function for appropriate action, we should always declare them using the volatile attribute in order to prevent the compiler from performing optimizations that result in the variable being stored in a register. In worst case, updated value of variable(updated in handler context) won't be visible to function polling for the variable.
WHY sig_atomic_t?
Reading and writing global variables may involve more than one machine- language instruction, and a signal handler may interrupt the main program in the middle of such an instruction sequence. (We say that access to the variable is nonatomic.) For this reason, the C language standards and SUSv3 specify an integer data type, sig_atomic_t, for which reads and writes are guaranteed to be atomic. Thus, a global flag variable that is shared between the main program and a signal handler should be declared as follows:
volatile sig_atomic_t signaL;

macOS `sigaction()` handler with `SA_SIGINFO` does not include `si_pid`

I'm trying to write a signal handler which needs to know the pid of the process that sends the signal. I'm having no luck with getting anything useful from the siginfo_t passed into my handler on macOS 10.14 with Xcode 10.
I've reduced my code to the below minimal sample to demonstrate the issue. In this sample I spawn a child process to send the signal I want to test which is defaulted to SIGTERM, but no other signal I've tried works any better.
Assuming you want to build and test this on a mac, you probably want to tell lldb to not stop when receiving a signal. You can use this lldb command: pro hand -p true -s false SIGTERM.
I'm also compiling with C++, but I believe I have excised all of that and the sample code should be pure C now.
Note that it doesn't matter if the signal originates from a child, terminal, or another process the result is always that si_pid is always 0 (along with everything other than the si_signo and si_addr). It doesnt matter how many times I send the signal, so it seems to not be simply a race condition.
How can I get the pid of the process sending the signal on macOS 10.14? I don't recall having this issue on 10.12 which is what I was using before.
This is just a sample to demostrate the problem, so please ignore anything that isn't actually causing a problem.
If the code seems like it should work as I expect, then I would be interested in seeing comments about systems that it works on too.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
volatile sig_atomic_t histogram[3] = {0,0,0};
volatile sig_atomic_t signaled = 0;
const int testsig = SIGTERM;
void sigaction_handler(int sig, siginfo_t* info, void* context)
{
switch (info->si_pid) {
case 0:
case 1:
histogram[info->si_pid]++;
break;
default:
histogram[2]++;
break;
}
signaled = 1;
}
int main(int argc, const char * argv[]) {
pid_t mainpid = getpid();
pid_t pid = fork();
if (pid == 0) {
while (kill(mainpid, 0) == 0) {
sleep(1);
kill(mainpid, testsig);
}
_exit(0);
}
struct sigaction sigAction;
memset( &sigAction, 0, sizeof( sigAction ) );
sigAction.sa_sigaction = sigaction_handler;
sigemptyset (&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigaction(testsig, &sigAction, NULL);
while (1) {
if (signaled) {
printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
signaled = 0;
}
sleep(1);
}
}
I'm currently using macOS Mojave 10.14.1.
How can I get the pid of the process sending the signal on macOS
10.14? I don't recall having this issue on 10.12 which is what I was using before.
The following code meets your wish simply. If you send SIGTERM, you can see pid of sender process.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
static void hdl (int sig, siginfo_t *siginfo, void *context)
{
printf ("Sending PID: %ld, UID: %ld\n",
(long)siginfo->si_pid, (long)siginfo->si_uid);
}
int main (int argc, char *argv[])
{
struct sigaction act;
fprintf(stderr, "%i pp %i\n",getpid(), getppid());
memset (&act, '\0', sizeof(act));
/* Use the sa_sigaction field because the handles has two additional parameters */
act.sa_sigaction = &hdl;
/* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGTERM, &act, NULL) < 0) {
perror ("sigaction");
return 1;
}
while (1)
sleep (10);
return 0;
}
For your code,
Rule of thumb: Don't forget to carry burial procedures out even though you are sure that child process ends prior parent process. By invoking wait(...) you tell the operating system that I'm done my things for my child so now you can clean allocated fields etc.
I'd prefer initialize signal utilities prior forking what if the parent process doesn't have a chance to register signal action? Moreover, I don't understand why you handle 0 and 1 cases in switch. Intrinsically the cases aren't hit, so always omitted.
In addition, you didn't use break in your if condition within main(). It doesn't go in if after a while yet the following circumstance which is not anticipated and desirable is that the program stays forever in while() loop. I'd prefer to put signaled into condition of while() loop.
At last but not least, due to sleep() call in child process until signaled is turned out 0, SIGTERM is caught several times successfully. When signaled is 0, the loop stops.
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <memory.h>
#include <sys/wait.h>
volatile sig_atomic_t histogram[3] = {0,0,0};
volatile sig_atomic_t signaled = 0;
const int testsig = SIGTERM;
void sigaction_handler(int sig, siginfo_t* info, void* context)
{
switch (info->si_pid) {
case 0:
case 1:
histogram[info->si_pid]++;
break;
default:
fprintf(stderr, "sender pid -> %i\n", info->si_pid);
histogram[2]++;
break;
}
signaled = 1;
}
int main(int argc, const char * argv[]) {
struct sigaction sigAction;
memset( &sigAction, 0, sizeof( sigAction ) );
sigAction.sa_sigaction = sigaction_handler;
sigemptyset (&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigaction(testsig, &sigAction, NULL);
pid_t mainpid = getpid();
pid_t pid = fork();
if (pid == 0) {
fprintf(stderr, "my pid -> %i parent's pid-> %i\n", getpid(), getppid());
if (kill(mainpid, 0) == 0) { // signals are not queued not need loop
sleep(1);
kill(mainpid, testsig);
}
_exit(0);
} else {
wait(NULL); // play with this line to see what the difference is
while ( signaled ) {
printf("pid 0: %d, pid 1: %d, others: %d\n", histogram[0], histogram[1], histogram[2]);
signaled = 0;
sleep(1);
}
// wait(NULL); // play with this line to see what the difference is
}
}
It turns out that debugging via Xcode LLDB is the culprit. If I build and run the program normally it works fine. If I find out why I will update this answer.
I already have the "PASS" set for SIGTERM in lldb as noted in the question, so it seems like somehow there is a bug in the version of lldb shipped with Xcode 10.0 and it is "passing" the signal by creating a new struct and setting the signal number rather then the structure that would have normally been received. As I stated before this did used to work fine in whatever version of lldb shipped with macos 10.12
If somebody has a better explaination, please post an answer and I will accept and award bounty.

Print message before SIGINT

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
/* A signal handling function that simply prints
a message to standard error. */
void handler(int code) {
fprintf(stderr, "Signal %d caught\n", code);
}
int main() {
// Declare a struct to be used by the sigaction function:
struct sigaction newact;
// Specify that we want the handler function to handle the
// signal:
newact.sa_handler = handler;
// Use default flags:
newact.sa_flags = 0;
// Specify that we don't want any signals to be blocked during
// execution of handler:
sigemptyset(&newact.sa_mask);
// Modify the signal table so that handler is called when
// signal SIGINT is received:
sigaction(SIGINT, &newact, NULL);
// Keep the program executing long enough for users to send
// a signal:
int i = 0;
for (;;) {
if ((i++ % 50000000) == 0) {
fprintf(stderr, ".");
}
}
return 0;
}
When I press ctrl-c, I want my program to print "Signal %d caught\n" message then exit normally as it would when pressing ctrl-c.
./test
..............................^CSignal 2 caught
.................^CSignal 2 caught
..........................................^Z
[2]+ Stopped ./test
Right now it just prints the message but doesn't exit the program right after.
That is because the default behavior of ctrl+c is to exit the program. But by using sigaction() you are managing the behavior yourself. So if you want the program to end, you can add an exit() call.
void handler(int code) {
fprintf(stderr, "Signal %d caught\n", code);
exit(code);
}

3 Player game in C using Signals

I have been trying to develop a 3 player game in C using signals but it is not giving desired output.
#define _POSIX_SOURCE //to use functionality from the POSIX.1 standard as ANCI C does not support kill()
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
void action(){}
void child(char *);
int main(){
pid_t pid1, pid2, pid3;
printf("This is a 3-players game with a referee\n\n");
if((pid1=fork()) == 0) child("TOTO");
sleep(1);
if((pid2=fork()) == 0) child("TITI");
sleep(1);
if((pid3=fork()) == 0) child("TUTU");
sleep(1);
while(1){
signal(SIGUSR1, action);
printf("Refree: TOTO plays\n\n");
kill(pid1, SIGUSR1);
pause();
printf("Refree: TITI plays\n\n");
kill(pid2, SIGUSR1);
pause();
printf("Refree: TUTU plays\n\n");
kill(pid3, SIGUSR1);
pause();
}
}
void child(char *s){
int points=0, dice;
srand(time(NULL));
while(1){
signal(SIGUSR1, action); // block myself
pause();
sleep(1);
printf("%s: playing my dice\n", s);
dice = rand() % 10 + 1;
printf("%s: got %d points\n", s, dice);
points+=dice;
printf("%s: Total so far %d\n\n", s, points);
sleep(3);
if(points >= 100){
printf("%s: game over I won\n", s);
kill(0, SIGTERM);
}
kill(getppid(), SIGUSR1);
}
}
Output I get is:
This is a 3-players game with a referee
Refree: TOTO plays
TOTO: playing my dice
TOTO: got 8 points
TOTO: Total so far 8
Refree: TITI plays
TITI: playing my dice
TITI: got 2 points
TITI: Total so far 2
User defined signal 1
It never shows "TUTU" playing dice and terminates using User Defined Signal 1 which is registered as a blank signal. The program should terminate only after a player wins.
Any suggestions?
When the referee catches TOTO's signal, it's disposition is reset to SIG_DFL, so TITI's signal really kills him. The referee must call signal(SIGUSR1, action) three times per loop, before each kill().
An alternative is to #define _BSD_SOURCE (read the Portability section of man 2 signal carefully), which imposes a BSD semantics of not resetting a disposition

Resources