Akzwitch
Akzwitch

Reputation: 113

signal handler reading incorrect value

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.

Upvotes: 1

Views: 67

Answers (2)

Dmitry Grigoryev
Dmitry Grigoryev

Reputation: 3203

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.

Upvotes: 0

SukkoPera
SukkoPera

Reputation: 621

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.

Upvotes: 1

Related Questions