Reputation: 9
So I'm trying to setup communications between the parent (computer system) and its child (system bus) and between child (system bus) and grandchild (IO device). I am not trying to setup communications between the parent and the grandchild. My code worked fine when it was only the parent and the child, however, when I added in the pipes for the child->grandchild and grandchild->child, it doesn't work; specifically, the grandchild cannot communicate with the child.
I have placed "<---- ERROR" where the code that I add stops the program and exits. Without these lines the program works but only the parent and the child are communicating. Am I doing it wrong? Or is there a subtle error that I'm missing?
I apologize because I am pretty new to this piping stuff, and am thankful for any assistance provided. I will continue to try and find the issue tonight and hopefully one of you can help tomorrow.
Here is my code:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
void computer_system (int pipe_cpu_bus[], int pipe_bus_cpu[], int length);
void system_bus (int pipe_cpu_bus[], int pipe_bus_cpu[], char *filename);
void io_device (int pipe_bus_io[], int pipe_io_bus[], char *filename);
void transfer_device (int pipe_bus_tran[]);
void buffer (int pipe_bus_buf[]);
#define MSGSIZE 20
int
main (int argc, char **argv) {
// a pipe from cpu to bus,
// use 1 within cpu to write to bus
// use 0 within bus to read from cpu
int pipe_cpu_bus[2];
// a pipe from bus to cpu,
// use 1 within bus to write to cpu
// use 0 within cpu to read from bus
int pipe_bus_cpu[2];
// error checking for pipe
if (pipe(pipe_cpu_bus) < 0)
exit(1);
if (pipe(pipe_bus_cpu) < 0)
exit(1);
// error checking for fcntl
if (fcntl(pipe_cpu_bus[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
if (fcntl(pipe_bus_cpu[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
switch (fork()) {
// error
case -1:
exit(3);
// child process (COMPUTER SYSTEM)
case 0:
if (argc >= 3) {
int length = atoi(argv[2]);
computer_system(pipe_cpu_bus, pipe_bus_cpu, length);
}
else {
printf("Usage: %s <file_name> <number>", argv[0]);
}
break;
// parent process (SYSTEM BUS)
default:
if (argc >= 3) {
char* filename = argv[1];
system_bus(pipe_cpu_bus, pipe_bus_cpu, filename);
}
else {
printf("Usage: %s <file_name> <number>", argv[0]);
}
break;
}
return 0;
}
void
computer_system (int pipe_cpu_bus[], int pipe_bus_cpu[], int length) {
int nread;
char buf[MSGSIZE];
close(pipe_cpu_bus[0]); // close read end of cpu_bus
close(pipe_bus_cpu[1]); // close write end of bus_cpu
write(pipe_cpu_bus[1], "hello", 5);
while (1) {
memset(buf, 0, sizeof buf);
nread = read(pipe_bus_cpu[0], buf, MSGSIZE);
switch (nread) {
// case -1 means pipe is empty and errono set EAGAIN
case -1:
if (errno == EAGAIN) {
printf(" (pipe empty in cpu)\n");
sleep(1);
break;
}
else {
perror("read");
exit(4);
}
// case 0 means all bytes are read and EOF (end of conv.)
case 0:
close(pipe_bus_cpu[0]);
close(pipe_cpu_bus[1]);
exit(0);
// some bytes have been read
default:
printf("bus: %s\n", buf);
write(pipe_cpu_bus[1], "hello", 5);
sleep(1);
}
}
exit(0);
}
void
system_bus (int pipe_cpu_bus[], int pipe_bus_cpu[], char *filename) {
// ======== CREATE IO PROCESS ========
int pipe_io_bus[2], pipe_bus_io[2];
// error checking for pipe
if (pipe(pipe_io_bus) < 0)
exit(1);
if (pipe(pipe_bus_io) < 0)
exit(1);
// error checking for fcntl
if (fcntl(pipe_io_bus[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
if (fcntl(pipe_bus_io[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
switch (fork()) {
// error
case -1:
exit(3);
// child process (COMPUTER SYSTEM)
case 0:
io_device(pipe_io_bus, pipe_bus_io, filename);
break;
default:
break;
}
// ===================================
int nread;
char buf[MSGSIZE];
close(pipe_cpu_bus[1]); // close write end of cpu_bus
close(pipe_bus_cpu[0]); // close read end of bus_cpu
close(pipe_io_bus[1]); // <--- ERROR
close(pipe_bus_io[0]); // <--- ERROR
while (1) {
// ==== Read from IO ====
memset(buf, 0, sizeof buf);
nread = read(pipe_io_bus[0], buf, MSGSIZE);
switch (nread) {
// case -1 means pipe is empty and errono set EAGAIN
case -1:
if (errno == EAGAIN) {
printf(" (io pipe empty in bus)\n");
sleep(1);
break;
}
else {
perror("read");
exit(4);
}
// case 0 means all bytes are read and EOF (end of conv.)
case 0:
close(pipe_io_bus[0]);
close(pipe_bus_io[1]);
exit(0);
// some bytes have been read
default:
printf("io: %s\n", buf);
write(pipe_bus_io[1], "fuck off", 8);
sleep(1);
}
// ==== Read from CPU ====
memset(buf, 0, sizeof buf);
nread = read(pipe_cpu_bus[0], buf, MSGSIZE);
switch (nread) {
// case -1 means pipe is empty and errono set EAGAIN
case -1:
if (errno == EAGAIN) {
printf(" (cpu pipe empty in bus)\n");
sleep(1);
break;
}
else {
perror("read");
exit(4);
}
// case 0 means all bytes are read and EOF (end of conv.)
case 0:
close(pipe_cpu_bus[0]);
close(pipe_bus_cpu[1]);
exit(0);
// some bytes have been read
default:
printf("cpu: %s\n", buf);
write(pipe_bus_cpu[1], "fuck off", 8);
sleep(1);
}
}
}
void
io_device (int pipe_bus_io[], int pipe_io_bus[], char *filename) {
int nread;
char buf[MSGSIZE];
close(pipe_io_bus[0]); // close read end of bus_io
close(pipe_bus_io[1]); // close write end of io_bus
write(pipe_io_bus[1], "here is a message", 17);
while (1) {
memset(buf, 0, sizeof buf);
nread = read(pipe_bus_io[0], buf, MSGSIZE);
switch (nread) {
// case -1 means pipe is empty and errono set EAGAIN
case -1:
if (errno == EAGAIN) {
printf(" (pipe empty in io)\n");
sleep(1);
break;
}
else {
perror("read");
exit(4);
}
// case 0 means all bytes are read and EOF (end of conv.)
case 0:
close(pipe_bus_io[0]);
close(pipe_io_bus[1]);
exit(0);
// some bytes have been read
default:
printf("bus: %s\n", buf);
write(pipe_io_bus[1], "here is a message", 17);
sleep(1);
}
}
}
As you can see, without those two lines that cause the program to exit for some unknown reason, it works, but the bus (child) is not receiving anything from the io (grandchild) despite the io explicitly writing to it.
With the two lines not omitted, the debug print is as follows:
(pipe empty in cpu)
(io pipe empty in bus)
(pipe empty in cpu)
cpu: hello
bus: fuck off
Here is the debug output if you require it.
(pipe empty in cpu)
(io pipe empty in bus)
(pipe empty in io)
(pipe empty in cpu)
(pipe empty in io)
cpu: hello
bus: fuck off
(pipe empty in io)
(io pipe empty in bus)
(pipe empty in cpu)
(pipe empty in io)
cpu: hello
bus: fuck off
(io pipe empty in bus)
(pipe empty in io)
(pipe empty in cpu)
cpu: hello
(pipe empty in io)
^C⏎
Upvotes: 0
Views: 739
Reputation: 9
I apologize deeply for wasting your time fellows,
In the end i was sending the arguments to io_device() in the wrong order, thereby closing the wrong end pipes. So I was writing to a pipe that had closed, thereby making the program fail.
Changing the io_device function declaration from
void io_device (pipe_bus_io[], pipe_io_bus[], char *filename) {}
to
void io_device (pipe_io_bus[], pipe_bus_io[], char *filename) {}
has solved the problem.
Again, I apologize, these little details slip my mind despite me looking for them for hours on end. I guess writing this question here made me look for it differently.
Thank you tadman and david for helping me!
Upvotes: 1