Reputation: 139
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);
}
}
Upvotes: 0
Views: 2155
Reputation: 754880
This code works for me (on Mac OS X 10.7.5):
#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);
}
}
}
#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;
}
}
}
$ (./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
$
Various changes, but the key ones are:
n
into a volatile sig_atomic_t
variable; that's what the C standard says you can access in a signal handler.pause()
and then print. The pause()
system call only returns when interrupted by a signal.SIGTERM
rather than SIGINT
to terminate the producer. If the producer is run in background, it is ignoring interrupts.kill()
calls fail.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.
Upvotes: 2
Reputation: 3069
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
Upvotes: 1