3

as an exercise I need to use a signal handler, and pipes to send some messages between two processes, when getting a signal. Below is my sourcecode. When I'm running it, I can get the pipes to work, both processes can talk, as long as I call the pipe in their main-method (in this case process1() and process2() ). But I want to use the pipes inside the signalhandlers. But now the pipes don't work. This is some output I got:

3 - 4 and 5 - 6
Segv at 8825
USR1 at 8824
898 sent to 4
130 received on 3
130

The '898' and '130' should be equal, but aren't. I know the pipes are working correctly, so I think it has something to do with the signalstuff... But what...?

Sourcecode:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

int fd1[2], fd2[2], status;
int cpid, cpoid;

void process1() {   
    cpid = getpid();        /*What's my process ID?*/
    cpoid = cpid + 1;       /*And what's the other process ID?*/

    close(fd1[0]);
    close(fd2[1]);

    while (1) {}
}

void process2() {   
    cpid = getpid();
    cpoid = cpid - 1;

    close(fd1[1]);
    close(fd2[0]);

    raise(SIGSEGV);         /*Start with a SegV signal*/

    while (1) {}
}

/*Method to send a message to the other process, by pipe*/
void send (int msg) {
    if (cpid < cpoid) {
        write(fd1[1], &msg, 1);
        printf("%d sent to %d\n", msg, fd1[1]);
    } else {
        write(fd2[1], &msg, 1);
        printf("%d sent to %d\n", msg, fd2[1]);
    }
}

/*Method to receive a message from the other process*/
int receive () {
    int msg = 0;
    if (cpid < cpoid) {
        read(fd2[0], &msg, 1);
        printf("%d received on %d\n", msg, fd2[0]);
    } else {
        read(fd1[0], &msg, 1);
        printf("%d received on %d\n", msg, fd1[0]);
    }
    return msg;
}

/*The SegV Signal handler*/
void segvHandler() {
    int y = -1;
    printf("Segv at %d\n", cpid);
    kill(cpoid, SIGUSR1);           /*Send an USR1 Signal to the other proces*/

    while (y != 898) {
        y = receive();
        printf("%d\n", y);
    }
}

/*The Usr1 Signal handler*/
void usr1Handler() {
    int x = 898;
    printf("USR1 at %d\n", cpid);

    send(x);
}

int main (int argc, char *argv[]) {

    if (pipe(fd1) < 0) {
        fprintf (stderr, "Could not make pipe\n");
        return (EXIT_FAILURE);
    }
    if (pipe(fd2) < 0) {
        fprintf (stderr, "Could not make pipe\n");
        return (EXIT_FAILURE);
    }
    printf("%d - %d and %d - %d\n", fd1[0], fd1[1], fd2[0], fd2[1]);    /*Pipe numbers*/

    signal(SIGUSR1, usr1Handler);   /*Signal handlers*/
    signal(SIGSEGV, segvHandler);

    if (fork() != 0) {
        process1();
    } else {
        process2();
    }
    waitpid(-1, &status, 0);

    return EXIT_SUCCESS;
}
  • 2
    You aren't supposed to do any significant I/O in a signal handler. Should just set a flag somewhere and then have a main loop that acts on that. Not sure if this is your problem, but it's the standard guidance. – chrisdowney Jun 16 '11 at 11:03
  • 1
    As a teaser, 898 is 0x382 and 130 is 0x82. Edited: So if send and receive only operate on single bytes (char type) then the integer would be chopped off as it is implicitely casted to the char type. – Tobias Wärre Jun 16 '11 at 11:05
  • 3
    `printf()` isn't async safe, don't use it inside signal handlers. – Šimon Tóth Jun 16 '11 at 11:10
  • 2
    You cannot rely on the pids differing by only one. To get the pid of the other process, you must keep track of it at the fork or write it through the pipe. – William Pursell Jun 16 '11 at 11:35
  • And of course it's not that brilliant code, but it's just for me to see how it's working, and why it isn't. But I'll keep your advice in mind while continuing. Thanks! – Sietse Ludger G Jun 16 '11 at 11:49

2 Answers2

3

Some faults based on a quick look.

  • printf() is not async-signal-safe; don't call it in a signal handler.

  • You're reading and writing 1 byte, which is most likely less than sizeof(int).

  • You cannot assume that PID's are consecutive. In the parent, the return value of fork() gives the PID of the child. In the child, if the parent stored the return value of getpid() before fork(), there you have it; otherwise see getppid().

janneb
  • 36,249
  • 2
  • 81
  • 97
2

As mentioned in the comments, you should not invoke printf in a signal handler, but that is probably not the problem. Unless ints are one byte on your machine, the issue is that you are not writing or reading the whole int, since you only write one byte into the pipe. (Change the code to: write( fd[ 1 ], &msg, sizeof msg ) and make the same change on the read.)

William Pursell
  • 204,365
  • 48
  • 270
  • 300