I'm trying to learn how to handle signals. In my program I have an array of pids of earlier created subprocesess. No I want to every couple seconds send a sigtstp signal to one of them. He just have to send sigchld to parent process and exit. Parent process should print an exit code of exited process and create next one in the place of exit one. Everything works fine in first loop but it hangs in second. So on output get:
loop
slept
forking
in to array
loop
Zakonczyl sie potomek 3934 z kodem 0.
So it's seems that sleep works in first loop but not in second. Or just main process didn't get back control after handling signal but this should't happen. So I have no idea whats may be wrong here.
while(1) {
printf("loop\n");
sleep(5);
printf("slept\n");
int r = rand() % n;
if(kill(process_tab[r],SIGTSTP) < 0) {
printf("Error while sending sigtstp signal.\n");
} else {
printf("forking\n");
if((child = fork()) < 0) {
printf("Fork failed.\n");
} else if(child == 0) {//to sie dzieje w procesie
if(signal(SIGTSTP,&catch_sigtstp)) {
printf("Error while setting signal handler.\n");
_exit(EXIT_FAILURE);
}
while(1) {
}
} else { //to sie dzieje w parencie
process_tab[r] = child;
printf("in to array\n");
}
}
}
And here are handlers.
void catch_sigtstp(int signal) {
kill(ppid,SIGCHLD);
_exit(EXIT_SUCCESS);
}
void catch_sigchld (int signal) {
int status;
pid_t child = wait(&status);
printf("Zakonczyl sie potomek %d z kodem %d.\n",child,status);
}
Add fflush after printf.
printf("Something\n");
fflush(stdout);
Otherwise you may not get the output as stdio is buffered by default.
Edit: Issues of handler
It is pretty unsafe to use printf function in signal handler, as it is not reentrant. Also, the catch_sigchild function can be modified:
void catch_sigchld (int signal) {
int status;
pid_t child;
while ((child = waitpid(-1, &status, WNOHANG)) > 0)
{
// may be something else?
// ...printf("Zakonczyl sie potomek %d z kodem %d.\n",child,status);
}
}
The reason is that one signal can be delivered for multiple dead children.
Edit: blocking signal when printing.
To avoid deadlock inside stdio, you should block the signal:
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHILD);
...
sigprocmask(SIG_BLOCK, &set, NULL);
printf("my output");
sigprocmask(SIG_UNBLOCK, &set, NULL);
...
Edit: as #Barmar has pointed, you parent process will receive SIGCHILD signal twice: once from your child'd signal handler, and one from OS.
To fix, it might be sufficient to remove your own signal source:
void catch_sigtstp(int signal) {
// kill(ppid,SIGCHLD); //< This one causes two signals per one child
_exit(EXIT_SUCCESS);
}
Related
I'm trying to create a program where a process forks, creating a child process, and the parent must always finish printing to the screen before the child is finished printing to the screen, no matter what. I also wish to accomplish this using signals instead of pipelining.
It is a similar problem to the question asked here: Explanation of sigsuspend needed
I understand that kill(pid,signal); is to send a signal to that pid and tell it to finish executing and terminate.
The problem is, when it executes, the child doesn't print after the suspend. Heres the code:
int main(void){
pid_t pid;
int i;
pid = fork();
if(pid==0){
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
sigsuspend(&mask);
printf("The child is now complete \n");
}
else{
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
}
exit(0);
}
}
I have managed to accomplish my task (printing the parent before the child) by using a global variable int x = 0; and a signal handler method void handle1(int s){x = 1;}before the main. In the main I added signal(SIGUSR1,handle1); In the child I removed all the sigset and sigsuspend lines and instead wrote while(x==0){/*do_nothing*/} 1 line before the printf statement. So when the parent executes kill(pid,SIGUSR1) the signal handler which is inherited by the child process also gets executed and sets x=1. So the child now leaves the while loop and can print it's statement.
However I believe it would be helpful to know how to accomplish this task using sigmask_t and sigsuspend() but i cant get it to work that way.
There are 3 problems in your code:
SIGUSR1 is the signal you want to deliver to the child. You can't use sigaddset(&mask,SIGUSR1);, it does exactly the opposite of your intention.
According to POSIX standard sigsuspend() below, you should install a signal handler for SIGUSR1 to make sigsuspend() continue the following code, since the default behavior of SIGUSR1 is termination.
The sigsuspend() function shall replace the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspend the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process.
It would be better if you collect the child from the parent, otherwise there is a race condition.
The code below will work:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void handler(int sig) {}
int main(void){
pid_t pid;
int i;
pid = fork();
signal(SIGUSR1, handler);
if(pid==0){
sigset_t mask;
sigemptyset(&mask);
//sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
sigsuspend(&mask);
printf("The child is now complete \n");
}
else{
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
}
wait(NULL);
exit(0);
}
}
You have a few issues.
Your parent process should wait for the child to complete. This allows for diagnostics (such as properly waiting for the child to print), but is otherwise a bookkeeping task that is a good habit even when the waiting process will just exit:
printf("This is the parentProcess id = %d \n",getpid());
printf("The parentProcess is complete\n");
sleep(1);
int j = kill(pid,SIGUSR1);
if (j!=0)
{
perror(NULL);
exit(0);
}
waitpid(pid, NULL, 0);
exit(0);
Now, you have set SIGUSR1 in your mask to sigsuspend(), which causes the signal to be ignored. This is now more obvious once the parent is made to wait, because the parent will never exit. So, remove the line of code that sets SIGUSR1.
Finally, the default handler for SIGUSR1 will simply cause the process to exit, and so the printf will not get a chance to print. If you want it to print, you should add a signal handler for SIGUSR1. It doesn't have to do anything.
void h (int s) {}
...
sigset_t mask;
sigemptyset(&mask);
//sigaddset(&mask,SIGUSR1);
printf("This is the child Process id = %d \n",getpid());
struct sigaction sa = { .sa_handler = h };
sigaction(SIGUSR1, &sa, NULL);
sigsuspend(&mask);
printf("The child is now complete \n");
I'm trying to implement a producer-consumer application using 1 parent process and 1 child process. The program should work like this:
1 - The parent process is the producer and the child process is the consumer.
2 - The producer creates a file, the consumer removes the file.
3 - After the file has been created, the parent process sends a SIGUSR1 signal to the child process which then removes the file and sends a SIGUSR2 signal to the parent, signaling it that the file can be created again.
I've tried implementing this problem but I keep getting this error:
User defined signal 1: 30.
I don't really understand what could be the problem. I've just started learning about process and signals and maybe I'm missing something. Any help would be appreciated. Here's my implementation:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
pid_t child, parent;
void producer()
{
system("touch file");
printf("File was created.\n");
}
void consumer()
{
system("rm file");
printf("File was deleted.\n");
kill(parent, SIGUSR2); // signal -> file can created by parent
}
int main(void)
{
system("touch file");
pid_t pid = fork();
for(int i = 0; i < 10; ++i)
{
if(pid < 0) // error fork()
{
perror("fork()");
return -1;
}
else if(pid == 0) // child proces - consumer
{
child = getpid();
signal(SIGUSR1, consumer);
pause();
}
else // parent process - producer
{
parent = getpid();
signal(SIGUSR2, producer);
// signal -> file can be deleted by child
kill(child, SIGUSR1);
}
}
return 0;
}
Edit: I forgot to mention that there can only be one file at a time.
...Any help would be appreciated.
Regarding the Error: User defined signal 1: 30, it is possible that the speed of execution is precipitating a race condition, causing termination before your handler functions are registered. Keep in mind, each signal has a default disposition (or action). For SIGUSR1 and SIGUSR2S the disposition is term, (from table in signal(7) page linked below)
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
(Note the value 30 listed by SIGUSR1 matches the exit condition you cite.)
The implication here would be that your handler functions had not registered before the first encounter with SIGUSR1, causing the default action of terminating your application and throwing the signal related error.
The relationship between synchronization and timing come to mind as something to look at. I found several things written on synchronization, and linked one below.
Timing may be implicitly addressed with an adequate approach to synchronization, negating the need for any explicit execution flow control functions. However, if help is needed, experiment with the sleep family of functions.
Here are a couple of other general suggestions:
1) printf (and family) should really not be used in a signal handler.
2) But, if used, a newline ( \n ) is a good idea (which you have), or use fflush to force a write.
3) Add a strace() call to check if any system call traffic is occurring.
Another code example of Synchronizing using signal().
Take a look at the signal(7) page.. (which is a lot of information, but implies why using printf or fprintf inside a signal handler in the first place may not be a good idea.)
Another collection of detailed information on Signal Handling.
Apart from what #ryyker mentioned, another problem is that by the time your parent process tries to signal the child using global variable child, the child has not got a chance to run and collect the pid. So the parent will send signal to a junk pid. A better approach is to use the pid variable in the parent and getppid() in the child. Here is the code which seems to give desired output
void producer()
{
system("touch file");
printf("File was created.\n");
}
void consumer()
{
system("rm file");
printf("File was deleted.\n");
kill(getppid(), SIGUSR2); // signal -> file can created by parent
}
int main(void)
{
system("touch file");
pid_t pid = fork();
if(pid < 0) // error fork()
{
perror("fork()");
return -1;
}
if(pid > 0) { //parent
signal(SIGUSR2, producer);
}
else { //child
signal(SIGUSR1, consumer);
}
for(int i = 0; i < 10; ++i)
{
if(pid == 0) {// child proces - consumer
pause();
}
else // parent process - producer
{
printf("Iter %d\n",i);
kill(pid, SIGUSR1);
pause();
}
}
return 0;
}
Try using semaphores in c++ instead of signals.
Signals truly serve special purposes in OS whereas semaphores serve process synchronization.
Posix named semaphores in c++ can be used across processes.
The following pseudocode will help.
Semaphore Full,Empty;
------
Producer() //producer
{
waitfor(Empty);//wait for an empty slot
system("touch file");
printf("File was created.\n");
Signal(Full); //Signal one slot is full
}
Consumer() //Consumer
{
WaitFor(Full); //wait for producer to produce
system("rm file");
printf("File was deleted.\n");
Signal(Empty);//Signal that it has consumed, so one empty slot created
}
After a lot of research and reading all of the suggestions I finally managed to make the program work. Here is my implementation. If you see any mistakes or perhaps something could have been done better, then feel free to correct my code. I'm open to suggestions.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void signal_handler(int signal_number)
{
sigset_t mask;
if(sigemptyset(&mask) == -1 || sigfillset(&mask) == -1)
{// initialize signal set || block all signals
perror("Failed to initialize the signal mask.");
return;
}
switch(signal_number)
{
case SIGUSR1:
{
if(sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
{ // entering critical zone
perror("sigprocmask(1)");
return;
} //---------------------
sleep(1);
system("rm file"); /* critical zone */
puts("File was removed.");
//--------------------
if(sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
{// exiting critical zone
perror("1 : sigprocmask()");
return;
}
break;
}
case SIGUSR2:
{
if(sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
{// entering critical zone
perror("2 : sigprocmask()");
return;
} //---------------------
sleep(1);
system("touch file");
puts("File was created."); /* critical zone */
// --------------------
if(sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
{// exiting critical zone
perror("sigprocmask(2)");
return;
}
break;
}
}
}
int main(void)
{
pid_t pid = fork();
struct sigaction sa;
sa.sa_handler = &signal_handler; // handler function
sa.sa_flags = SA_RESTART;
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
if(pid < 0)
{
perror("fork()");
return -1;
}
for(int i = 0; i < 10; ++i)
{
if(pid > 0) // parent - producer
{
sleep(2);
// signal -> file was created
kill(pid, SIGUSR1);
pause();
}
else // child - consumer
{
pause();
// signal -> file was removed
kill(getppid(), SIGUSR2);
}
}
return 0;
}
I forked a child and I am trying to synchronize them so they print
child 0
parent 0
child 1
parent 1
I have to use sigsuspend though, this is my code for the moment and all I get is parent suspend. There is no trace of the child.
int c=0, receivedP=0, receivedC=0;
sigset_t setParent, setChild;
void handler(int s){
if(s==SIGUSR1){
receivedC=1;
printf("parent --sig1--> child\n");
c++;
}
else{
receivedP=1;
printf("child --sig2--> parent\n");
}
}
void child(){
sigfillset(&setChild);
sigdelset(&setChild,SIGUSR1);
sigdelset(&setChild,SIGINT); //this makes me able to terminate the program at any time
while(1){
if(receivedC==0){
printf("child suspend\n");
sigsuspend(&setChild);
}
receivedC=0;
printf("child %d\n",c);
kill(getppid(),SIGUSR2);
}
}
void parent(pid_t pf){
sigfillset(&setParent);
sigdelset(&setParent,SIGUSR2);
sigdelset(&setParent,SIGINT); //this makes me able to terminate the program at any time
kill(pf,SIGUSR1);
while(1){
if(receivedP==0){
printf("parent suspend\n");
sigsuspend(&setParent);
}
receivedP=0;
printf("parent %d\n",c);
kill(pf,SIGUSR1);
}
}
int main(){
signal(SIGUSR1,handler);
signal(SIGUSR2,handler);
pid_t p;
p= fork();
if(!p)child();
else parent(p);
return 0;
}
Anybody knows what's causing this?
I think you are running foul of one of the classic problems with signals.
while(1){
if(receivedP==0){
printf("parent suspend\n");
sigsuspend(&setParent);
}
receivedP=0;
printf("parent %d\n",c);
kill(pf,SIGUSR1);
}
Imagine what happens if the signal from the child arrives in between the instructions for if(receivedP==0) and sigsuspend(&setParent). The handler will execute, and will set receivedP to one, but the main loop won't check it again; it will go into sigsuspend and never come out.
In order to use sigsuspend safely, you need to have the signals you care about be blocked at all times when the program is not calling sigsuspend. You do that with sigprocmask. It's also necessary to ensure that the signals are blocked during the execution of the handler, which requires you to use sigaction instead of signal (but you should do that anyway, as signal is severely underspecified and system-to-system variations will bite you in the ass).
Once you ensure that the signal can only be delivered during a sigsuspend, you no longer need the receivedP and receivedC variables; you know that the signal happened, or sigsuspend would not have returned. (This would not be true if your program was waiting for more than a single signal in each process, but at that point things get much more complicated; don't worry about it till it comes up.)
In fact, once you ensure that, you don't need to do anything in the signal handler. Your counter variable can be local to parent and child. It's always best to do as little in a signal handler as possible; the letter of the C standard allows you to do almost nothing without risking undefined behavior, and POSIX only opens it up a little bit more. (Exercise for you: change this program to use sigwaitinfo so that it doesn't need handler functions at all.)
This modification of your program works reliably for me. I also corrected a number of other style problems and minor errors: note the loops in parent and child doing things in different orders, the error checking in main, and that I am only blocking SIGUSR1 and SIGUSR2, because there are several other signals that should be allowed to terminate the process (SIGTERM, SIGHUP, SIGQUIT, SIGSEGV, …) and you don't want to have to maintain a list. It is sufficient to block the signals that the program has installed handlers for.
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static void handler(int unused)
{
}
static void child(sigset_t *ss)
{
unsigned int c = 0;
pid_t parent_pid = getppid();
sigdelset(ss, SIGUSR1);
for (;;) {
sigsuspend(ss);
printf("child %u\n", c++);
kill(parent_pid, SIGUSR2);
}
}
static void parent(sigset_t *ss, pid_t child_pid)
{
unsigned int c = 0;
sigdelset(ss, SIGUSR2);
for (;;) {
printf("parent %u\n", c++);
kill(child_pid, SIGUSR1);
sigsuspend(ss);
}
}
int main(void)
{
// Ensure line-buffered stdout.
if (setvbuf(stdout, 0, _IOLBF, 0)) {
perror("setvbuf");
return 1;
}
// This signal mask is in effect at all times _except_ when sleeping
// in sigsuspend(). Note that _only_ the signals used for IPC are
// blocked. After forking, each process will modify it appropriately
// for its own use of sigsuspend(); this does not affect the kernel-side
// copy made by sigprocmask().
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGUSR1);
sigaddset(&ss, SIGUSR2);
if (sigprocmask(SIG_BLOCK, &ss, 0)) {
perror("sigprocmask");
return 1;
}
// Always use sigaction(), not signal(); signal() is underspecified.
// The mask here is the signal mask to use _while the handler is
// executing_; it should also block both IPC signals.
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_mask = ss;
sa.sa_flags = SA_RESTART;
if (sigaction(SIGUSR1, &sa, 0) || sigaction(SIGUSR2, &sa, 0)) {
perror("sigaction");
return 1;
}
pid_t child_pid = fork();
if (child_pid < 0) {
perror("fork");
return 1;
}
if (child_pid == 0)
child(&ss);
else
parent(&ss, child_pid);
// we never get here but the compiler might not know that
return 0;
}
I recommend you read the GNU C Library Manual's section on signal handling all the way through; it contains several other bits of helpful advice on using signals safely.
I am trying to write a function to install a signal handler on a process to ignore a SIGQUIT signal the first time it is called and then exit on the second SIGQUIT signal. I am intend to use a global variable for the counter to count the number of times SIGQUIT signal is sent.
However I am having issues implementing this. I have found SIG_IGN which would ignore the first SIGQUIT signal, but how would I then detect the first signal to increment the counter (and maybe change the signal() to call the signal handler)?
My code is as below:
// global var counter
int signal_counter = 0;
int main (int argc, const char * argv[]) {
pid_t child_pid = 0;
int child_status = 0;
/* fork a child process... */
child_pid = fork();
if(child_pid < 0 ) { /* fork() and check if there were errors */
perror("fork"); /* print a system-defined error message */
exit(EXIT_FAILURE);
}
else if(child_pid == 0) { /* Child code */
install_handler();
for(; ;sleep(1)); /*loop forever*/
}
else { /* Parent code */
printf("Parent processing starts\n");
printf("\nPARENT: sending first SIGQUIT\n\n");
kill(child_pid,SIGQUIT);
printf("\nPARENT: doing something\n\n");
sleep(3);
printf("\nPARENT: sending SIGQUIT again\n\n");
kill(child_pid,SIGQUIT);
}
return EXIT_SUCCESS;
}
void sigquit() {
printf("SIGQUIT\n");
sleep(2);
exit(0);
}
void install_handler(){
if (signal_counter == 0){
signal(SIGQUIT, sigquit);
signal_counter+=1;
}
else{
signal(SIGQUIT, sigquit);
}
}
Any help would be appreciated.
A way to solve it is to use the posix standard. According to it, a signal installed is one shot.
The first time that the signal will arrive, it will start the method specified. Therefore, if another signal arrives, then it will be executed normally (i.e. it will quit your application for a sigquit).
What I want to do is create a parent process that lasts for 5 seconds. I also want it to send a SIGUSR1 signal every second. On this signal I want the child to do something.
The code that I put together so far is:
void alarmHandler(int sig) {
printf("\nalarm called\n");
exit(0);
}
void childHandler(int sig) {
printf("child called");
signal(SIGUSR1, childHandler);
}
int main() {
pid_t val;
if((val = fork())) { //parinte
signal(SIGALRM, alarmHandler);
printf("parent");
alarm(5);
while(1) {
kill(val, SIGUSR1);
sleep(1);
}
}else {
signal(SIGUSR1, childHandler);
printf("child");
}
return 0;
}
What I get is:
child
parent
alarm called
What I want:
child
parent
child called
child called
child called
child called
child called
alarm called
Your parent has the while loop. The child does the following:
signal(SIGUSR1, childHandler);
printf("child");
And then exits.
If it does receive SIGUSR before the exit, this will also be executed
printf("child called");
signal(SIGUSR1, childHandler);
Therefore you have a race condition as the number of child called is printed.
Just put a while (1) {} after the printf("child");
Base on the original code, add two blocks:
flush the printf: setbuf(stdout, NULL);
keep the child running: while (1) pause();
The code list as follow:
#include "stdio.h"
#include "stdlib.h"
#include <signal.h>
/* For a real-world program, printing from a signal handler is not very safe.
* A signal handler should do as little as it can, preferably only setting a flag here or there.
* And the flag should be declared `volatile`.
* Real-world example:
* I once worked on a system that used an Access database as a back end,
* and under certain circumstances a printf() call in a signal handler would write to the .mdb file instead of stdout,
* hosing the database beyond repair.
*/
void alarmHandler(int sig)
{
printf("\nparent signal alarm handler: times up\n");
exit(0);
}
void childHandler(int sig)
{
printf("\nchild signal handler\n");
// The old style should install the handler again.
signal(SIGUSR1, childHandler);
}
int main()
{
pid_t val;
signal(SIGALRM, alarmHandler);
// If not set this, we cann't the child's output.
// The stdout stream is buffered, so will only display what's in the buffer after it reaches a newline (or when it's told to).
setbuf(stdout, NULL);
if ((val = fork())) { //parinte
printf("\nparent\n");
// #Note that there is only one alarm clock per process.
// the alarm() function will return a value if another alarm has been previously set.
//
// sets a timer that generates the SIGALARM signal when times up.
// If we ignore or don’t catch this signal, the process is terminated.
alarm(5);
while(1) {
sleep(1);
kill(val, SIGUSR1);
}
printf("\nparent exit\n");
} else {
signal(SIGUSR1, childHandler);
printf("\nchild\n");
while (1)
pause(); // The pause() function suspends the process until a signal is caught.
printf("\nchild exit\n");
}
return 0;
}
And the output:
parent
child
child signal handler
child signal handler
child signal handler
child signal handler
parent signal alarm handler: times up