Search code examples
cpipefork

C - Piping and forking - Weird memory junk


I'm trying to accomplish the following task:

There are two processes, a parent and a child. The parent sends a 'location' (New York in the code) to the child on a pipe, which then signals the parent process, that the location has arrived, via SIGUSR1. Then, the parent process sends the list of registered visitors to the child process (visitordata* V), which consists of entries of the struct visitordata:

typedef struct visitordata {
    char name[80];
    char email[80];
    int id;
    char reg_time[9];
} visitordata;

Up until now, everything works fine in my code. And now, the child process is supposed to send a random number back to the parent (deemed 'quality'), and the actual visitors (each registered visitor has a 90% chance to actually attend the event), and this is where my code fails. I'm trying to send the data back to the parent process the same way I sent it to the child:

int pipefd[2];
if (pipe(pipefd) < 0) { perror("Pipe error!\r\n"); exit(1); }   

//int numactualvisitors is the actual number of visitors that went to the event
quality = rand() % 10 + 1;
visitordata* actualvisitors = (visitordata*)malloc(numactualvisitors * sizeof(visitordata));
write(pipefd[1], &numactualvisitors, sizeof(numactualvisitors));
printf("ee\n");             
write(pipefd[1], actualvisitors, numactualvisitors * sizeof(visitordata));
printf("ff\n");
write(pipefd[1], &quality, sizeof(quality));
printf("gg\n");

But instead of writing to the pipe, it seems as if the writing actually occurs on the console, and I get an output like:

dd
ee
userfirstname lastnameemail@email-15:22:38firstname2 lastname2email@email▒15:22:49ff
gg

Meanwhile, the parent process is supposed to read this (I need sleep(1) because otherwise the reading occurs sooner than the writing in the other process):

printf("first\n");
sleep(1);
int dv;
int qual;
printf("debug1");

read(pipefd[0], &dv, sizeof(int));
printf("%d\n", dv);
printf("debug2");

visitordata* A;
A = (visitordata*)malloc(dv * sizeof(visitordata));         
printf("debug3");
read(pipefd[0], A, dv * sizeof(visitordata));
printf("dv: %d\n", dv);
read(pipefd[0], &qual, sizeof(int));

However, from this, only the first string gets written to the console. The program doesn't finish and it's hung. What am I doing wrong? I can't understand why the parent won't go past the first point, and why the child writes the struct array to the console instead of sending it. I'm currently testing with just 2 lines of input, so basically it put both registered attendees to the console. I don't quite get it.

You can find more of the code here, to have a better overview. I'll leave my printf-s in so we can better reference the parts of the code.

Thank you for helping!


Solution

  • The original error is in the parent code:

    visitordata* V;
    …
      write(pipefd[1], &V, ds * sizeof(visitordata));
    

    By using &V, it's trying to write not the visitor data, but the corresponding amount of bytes from the address of the pointer V to the data. At that address, there may be not this amount of accessible memory, so the write can fail, causing the child to wait forever to read the data. Correct:

      write(pipefd[1], V, ds * sizeof (visitordata));
    

    Moreover, since you sleep(1) in both the parent and the child, there's no guarantee that the child gets to read the visitor data before the parent wants to read the number of actual visitors, and so, because you use the same pipe for the communication from parent to child as in reverse, the parent might read the very same data it has written. Better use one pipe for the direction parent-to-child and an other pipe for child-to-parent; you don't need sleep() then, which is an unreliable synchronisation method anyway.