Question

I would like to:

Parent process:

  • Write data to a pipe
  • Send a signal to child process

Child process:

  • Read data after signal is caught.

Here is my tryout:

#include<stdio.h>
#include<string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h> 
#include <signal.h>

int fd[2];   


//Handler - Exiting process, OR reading from pipe
void sigHandler(int signumber){

   if(signumber == SIGUSR1) {

    printf("SIGUSR1 catched.\n");


    //So lets read from pipe
    int read_data = -1;
    close(fd[1]);
    read(fd[0], &read_data, sizeof(read_data));

    //This printf never gets called
    printf("Received data: %s", read_data);


   }
   else  {

   printf("SIGQUIT catched.\n");
    exit(3);
   }
}

//This is handles parent process to NOT exit on sending a signal
//maybe not the best workaround but i could only do this in this way.
void sigDummy(int signumber){
    printf("SigDummy catched\n");
}


int main(){    

fflush(stdout);

pipe(fd);
char option=-1;

pid_t child_a;
pid_t child_b;

child_a = fork();

//A Child Proc which is not used atm, it will be
if (child_a == 0) {

    signal(SIGQUIT ,sigHandler); 
    signal(SIGUSR1 ,sigHandler); 

    while(1) {
      //idle    
        sleep(1);
        printf("child_a iddle work\n");

    }


} 

    //Child B Proc for reading form the PIPE after got SIGUSR1 signal
    else {
    child_b = fork();

    if (child_b == 0) {

        signal(SIGQUIT ,sigHandler); 
        signal(SIGUSR1 ,sigHandler); 

        while(1) {
        //idle
            sleep(1);
            printf("child_b iddle work\n");

        }

    } 
    //Parent Proc for writing to a pipe and sending signals to child B to read the pipe
    else {

            signal(SIGUSR1 ,sigDummy); 

            //MENU WHILE
            while(option!=0){

                scanf("%d", &option);
                printf("input was: %d\n", option);
                kill(child_b,SIGUSR1); 

                close(fd[0]);
                write(fd[1], &option, sizeof(option));
            }

        }//End of Menu while

        //Exiting child prcoesses then exiting parent prcoess
        if(option==0){

            int status_a, status_b;

            waitpid(child_b, &status_b, WNOHANG|WUNTRACED);
            waitpid(child_a, &status_a, WNOHANG|WUNTRACED);

            kill(child_b,SIGQUIT); 
            kill(child_a,SIGQUIT); 

        }

    }

    return 1;

} 

Output:

child_b iddle work
child_a iddle work
child_b iddle work
child_a iddle work
child_b iddle work
child_a iddle work
child_b iddle work
child_a iddle work
4
input was: 4
SigDummy catched
SIGUSR1 catched.
SIGUSR1 catched. //I wait here several seconds, child_a and b processes are not printing anything anymore....
3
input was: 3
SigDummy catched
1
input was: 1
SigDummy catched

And if i remove the pipe writing the pipe reading parts i have nice working code:

Output without pipe write and read:

child_a iddle work
child_b iddle work
3
input was: 3
SigDummy catched
SIGUSR1 catched.
child_a iddle work
SIGUSR1 catched.
child_b iddle work
child_a iddle work
child_b iddle work
2
input was: 2
SigDummy catched
SIGUSR1 catched.
child_b iddle work
SIGUSR1 catched.
child_a iddle work
child_b iddle work
child_a iddle work
1
input was: 1
SigDummy catched
SIGUSR1 catched.
child_b iddle work
SIGUSR1 catched.
child_a iddle work
child_b iddle work
child_a iddle work
4
input was: 4  //Inputs are always catched with my signal handler func, and child processes does not stop printing.
SigDummy catched
SIGUSR1 catched.
child_b iddle work
SIGUSR1 catched.
child_a iddle work
child_b iddle work
child_a iddle work
child_b iddle work
child_a iddle work
0
input was: 0
SigDummy catched
SIGUSR1 catched.
SIGQUIT catched.
SIGUSR1 catched.
SIGQUIT catched.
Exiting

The method i found out is working well without the write-read pipe part. But after adding it it is simply randomly wrong.

So why my code behaviours other way when i try to do the pipe sending thing? I just started to learn c, and the code may be really messed up, be nice please.

Was it helpful?

Solution

The problem is the printf("Received data: %s", read_data); statement. By putting %s in the format string, the read_data variable is being treated as a pointer and dereferenced (you probably wanted %d instead or similar).

When you put in a value of 4. You end up trying to access address 0xffffff04 which ordinarily would cause a segmentation fault, but in the context of a signal handler, it just seems to kill the child process silently.

A few other things:

  • You shouldn't close a file more than once. The file descriptor number may be re-used elsewhere and you might even inadvertently close something you didn't expect to.

  • Be careful about the data you're writing and reading. You're writing a char sized piece of memory, but reading into an int. Make sure that's what you actually want or you'll get unexpected values.

  • Generally, signal handlers aren't a great place to do lots of heavy work. A lot of operations aren't very safe here and can interfere with what the program was doing when it was interrupted in unexpected ways. It's usually better to use the signal handler to simply inform the rest of your program that something needs attention, and have the main program do the majority of the work.

  • Even better than using signals when you're dealing with files, you can synchronise with poll() or select() calls (or if your code is simple enough, just block on the file with the read()... your example code be re-factored to remove the signal handlers entirely and still work the same way, but your real code might be more complex than this).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top