1

on receiving a SIGUSR1 signal, I want to display the value read by the child from the pipe.

Having a little issue. It is always displaying 0 despite getppid() was written to pipe by parent process. Any solution? `

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

char bufP[10], bufC[10];
int gpid;

void handler(int signum){
    signal(SIGUSR1, handler);
    if (signum == SIGUSR1){
        printf("SIGUSR1 received\n");
        gpid = atoi(bufC);
        printf("Grandparent: %d\n", gpid);
        exit(0);
    }   
}

int main(void){
    int pid, fd[2];
    pipe(fd);
    pid = fork();

    signal(SIGUSR1, handler);

    if (pid == 0){
        //child
        close(fd[1]);       
        read(fd[0], bufC, sizeof(bufC));                
        close(fd[0]);
    }else{
        //parent
        close(fd[0]);
        sprintf(bufP, "%d", getppid());
        write(fd[1], bufP, sizeof(bufP));
        kill(pid, SIGUSR1);     
        close(fd[1]);
    }

}

`

Thanks for your response.

alk
  • 69,737
  • 10
  • 105
  • 255
Akzwitch
  • 113
  • 1
  • 2
  • 13
  • Never use `printf` inside a signal handler. It's not [async signal safe](http://stackoverflow.com/questions/9547949/printf-is-not-working-in-c-signal-handler) – JeremyP Mar 09 '15 at 14:30

2 Answers2

1

You seem to assume that the signal will always be handled after the read() has completed, which is not the case. Signals are asynchronous by nature and can arrive anytime (even halfway through the read()!). Basically you are building your program upon a so-called race condition, which you should really avoid.

SukkoPera
  • 621
  • 4
  • 8
  • There is a 2nd race introduced by setting the signal handler **after** forking off the child. – alk Mar 09 '15 at 11:21
  • Also the child could already have ended **before** any writes had been performed, or the signal had been sent, or delivered. – alk Mar 09 '15 at 11:24
  • 1
    @alk: Sure there is, and I don't see even why the OP is also setting the signal handler up in the parent as well. But I don't see how the child could end *before* the `write()` has been performed, since it will be blocked on the `read()` call until data is available. Still, it might end before the signal is sent, I agree on this. – SukkoPera Mar 09 '15 at 11:27
  • Correct, the `read()` blocks the child. So the child defintily won't end before the parent's write ended. My bad. – alk Mar 09 '15 at 11:32
0

While there certainly is a race condition here, it's not what causing trouble. The problem is that your signal is triggered while the read() call in the child process is blocked. You can add a sufficiently long pause in the parent process to let child's read() complete:

if (pid == 0){
    //child
    close(fd[1]);       
    read(fd[0], bufC, sizeof(bufC));                
    close(fd[0]);
    sleep(10); // wait for the signal to arrive
}else{
    //parent
    close(fd[0]);
    sprintf(bufP, "%d", getppid());
    write(fd[1], bufP, sizeof(bufP));
    close(fd[1]); // close right away to be sure the buffers are flushed
    sleep(1); // make sure the child has finished reading the buffer
    kill(pid, SIGUSR1);     
}

Of course, remarks about race conditions and the fact that you should avoid them are still true. This code is not "production quality", it will fail if the load on your system is so heavy that 1 second is not enough to schedule the child process and finish that read() call.

Dmitry Grigoryev
  • 3,156
  • 1
  • 25
  • 53