Practicing Writing Fork Processes using close() and open() functions - c

I'm practicing writing fork processes and I got stuck in the area where parent passes the process off to the child. I seem to get a bit lost there.
I was thinking the child opens /dev/null and then writes a lot of data to this file. Each iteration of the loop writes 10 bites to /dev/null.
More specifically I want to write a 10-character array and run the loop a bunch of times like 100,000,000 iterations!
In the meantime the parent will be in standby mode until the child process has finished. This is what I currently have:
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
int fd = open("/dev/null",O_WRONLY);
pid_t newPid = fork();
if (newPid <0) {
perror("fork() failed");
exit(1);
}
if (newPid > 0) { //Parent
pid[procIdx] = newPid;
} else { //Child
//write 10 bytes to /dev/null
write(fd, "ABCDEFGHIJ", 10)
exit(0);
close (fd);
}
// Wait for processes to complete
for (int i = 0; i < // unsure what to write here; i++) {
if (waitpid(pid[i], NULL, 0) == -1) {
perror("waitpid() failed");
exit(1);// process termination status value 1
}
}
exit(0); // process termination status value 0
}

Related

Clarification about Parent process writing message to Child process using simple pipe

This is a C program where the Parent process tries to write a message to its child process using a simple pipe. The expected output is obtained.
According to the code, the parent calls wait() and waits until the child process exits(returns).
Also, the child process calls read(), which waits for something to be written through the other pipe end?
Thus, shouldn't both processes keep waiting for each other and cause a deadlock? How is it possible that the program works properly?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MSGSIZE 16
char *msg1 = "Hello,Once";
char *msg2 = "Hello,Twice";
char *msg3 = "Hello,Thrice";
int main()
{
char buff[MSGSIZE];
int pi[2],pid,nbytes;
if(pipe(pi) < 0) _exit(1);
if((pid=fork()) > 0)
{
close(pi[0]);
write(pi[1],msg1,MSGSIZE);
write(pi[1],msg2,MSGSIZE);
write(pi[1],msg3,MSGSIZE);
close(pi[1]);
wait(NULL);
}
else
{
close(pi[1]);
while((nbytes = read(pi[0],buff,MSGSIZE)) > 0) printf("%s\n",buff);
printf("Reading Completed\n");
close(pi[0]);
if(nbytes != 0) _exit(2);
}
return 0;
}

Data transmitted in a pipe are garbage

I am using these two programs of this answer. This answer uses named-pipes and not pipes, am I correct?
I have written main.c, which is actually the code of my actual project, minimized to this specific question (that's why I have a for loop for example).
#include <unistd.h>
#include <sys/wait.h>
#include <stddef.h>
#include <limits.h>
#include <stdio.h>
int main(void) {
pid_t pid;
int i;
for(i = 0; i < 2; ++i) {
pid = fork();
if (pid == -1) {
// error, failed to fork()
perror("failed to fork()");
return 1;
} else if (pid == 0) {
// child code
if(i < 1) {
// the writer.c
char* arg_list[] = { "w", NULL };
execv( "w", arg_list );
printf("exec FAILED\n");
} else {
// the reader.c
char* arg_list[] = { "r", NULL };
execv( "r", arg_list );
printf("exec FAILED\n");
}
}
}
// parent code
int status;
// wait for all children to terminate
while ((pid = wait(&status)) > 0) {
if (status == 1) {
printf("The child process terminated with an error!\n");
return -1;
}
}
printf("All children are done\n");
return 0;
}
The problem is that sometimes, the reader receives garbage (or most likely nothing) and it hangs up.
Sample output:
Received: Hi
All children are done
samaras#samaras-A15:~/test$ ./m
Received: Hi
All children are done
samaras#samaras-A15:~/test$ ./m
Received: <----------------- This is garbage, that is not reproducible
^C
So, what am I missing?
No need to read below that point.
My guesses are (not checked, so if I am correct, I still need clarification):
The reader runs before writer, that's why it has garbage, but then why it hangs?
or
I need to write a wrapper function read_all() (and one for the write case as well?) that collects all the data that the pipe spits, but then why if I replace "Hi" with "H", I have the same behaviour?
EDIT:
In case my first guess is the case, I put a loop for reading, but it will execute forever in the case that reader starts first.
In the case that I see garbage, after running with strace -f I got this:
...
[pid 3326] read(-1, 0xbfddd80c, 1024) = -1 EBADF (Bad file descriptor)^C
Process 3324 resumed
Process 3325 detached
Process 3326 detached
Your loops (or lack of) have nothing to do with it. When your reader opens (open()) the pipe for reading before writer creates the pipe, then the file descriptor your readers waits on is invalid (-1). So even when writer writes something later on, reader just waits on an invalid fd (-1) and is never going to read anything. Trivially, you could solve it with:
while( (fd = open(myfifo, O_RDONLY)) == -1);
in reader so that it waits until pipe is available. I am actually wondering if there can be a better approach than this. One other way I can think of is a loop over access(), but it's not massively different to this...

Using a pipe to read array of strings with C

I am learning about using pipes with C right now, and I am having some difficulty writing a list of strings, one-by-one, to the pipe in the child process, and then read them from the pipe in the parent process. Here is my current code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main()
{
int pfd[2];
char buf[1000];
int cfork;
if (pipe(pfd) == -1) {
exit(1);
}
cfork = fork();
if (cfork == -1) {
printf("Fork Failed\n");
exit(1);
}
else if (cfork == 0) {
printf("Child Process\n");
char *fruit[] = {
"Orange", "Apple",
"Banana", "Pear"
};
int num_fruit = 4;
for (int i = 0; i < num_fruit; i++) {
printf("Current fruit: %s\n", fruit[i]);
write(pfd[1], fruit[i], (strlen(fruit[i])));
}
_exit(0);
}
else {
printf("Parent Process\n");
read(pfd[0], buf, sizeof(buf));
printf("Fruit Fetched: %s\n", buf);
wait(NULL);
}
return 0;
}
What I am trying to do, is in the child, read a fruit string, write it to the pipe, and have the parent read this string and print it, until all the strings have been printed. My trouble is that the child, since it's in a loop, just keeps adding each string to the buffer, so the program, as it stands, prints out "OrangeAppleBanana". I am pretty sure I will need a loop in the parent as well, but when I've tried a while loop that waits for some end condition string sent by the child (for example "done"), my program still gets stuck in an infinite loop.
What is the most straightforward way, for someone new to C, to write strings in the child one -by-one, and have the parent process print them out one-by-one?
EDIT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main()
{
int pfd[2];
int cfork;
if (pipe(pfd) == -1) {
exit(1);
}
cfork = fork();
if (cfork == -1) {
printf("Fork Failed\n");
exit(1);
}
else if (cfork == 0) {
int numbers[] = {
1, 2,
3, 4
};
int limit = 4;
close(pfd[0]);
for (int i = 0; i < limit; i++) {
printf("Child - Current Number: %d\n", numbers[i]);
write(pfd[1], &numbers[i], sizeof(numbers[i]));
}
close(pfd[1]);
_exit(0);
}
else {
int temp;
int reads = 4;
close(pfd[1]);
for (int i = 0; i < reads; i++) {
read(pfd[0], &temp, sizeof(temp));
printf("Parent - Number Fetched: %d\n", temp);
}
close(pfd[0]);
waitpid(-1, NULL, 0);
}
return 0;
This is my new code, where I use integers instead of strings. Seems to work so far. Still not sure what I was doing wrong with strings though.
I believe your problem is with "strings". Strings in C are null terminated, so when you are sending them via pipe, receiver(parent) doesn't know where a string ends. Strlen does count the number of characters in a string, but not the null charatter. You should do:
write(pfd[1], fruit[i], (strlen(fruit[i]))+1);
Parent can now know when and where to split your string.
The other problem is that you need to loop in the parrent as well. You need to set up a condition in the loop, which checks for EOF. In your example, where you know you are going to receive 4 fruits, you can just loop 4 times.
It's a good practice to close read and write end of pipes you don't need. In your example, child should close the reading end, while parent should close the writing end. You can do this with:
close(pfd[0]); //use this in child
close(pfd[1]); //use this in parent
You should also get used to closing all descriptors you don't need. In your example, you should close the pipe in both child and parent process after you are finished with writing / reading. This way, you could create a read loop condition, which closes after EOF. (When child closes pipe, receiver can end)
As an extra tip, try error reporting with "perror"
http://www.tutorialspoint.com/c_standard_library/c_function_perror.htm
//Child
close(pfd[0]); // Close read end this blocks if parent is reading from pipe
write(pfd[1]...); // write data into pipe
close(pfd[1]); // close write end of pipe now the pipe is ready to read
// Parent
close(pfd[1]); // close write end of pipe blocks if child is writing to pipe.
read(pfd[0] ...);
close(pfd[0]..); // close read end so pipe is ready to write to.

Working with pipes in Unix C

I am having serious trouble working with pipes in C. I'm supposed to take in arguments from the command line (example: ./myprogram 123 45 67), read the arguments one character at a time into a buffer, send the character to the child process to be counted, and then return the total number of characters read to the parent process. My code is as follows(note: the comments are what I'm supposed to be doing):
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
// Child process counts number of characters sent through pipe.
// Child process returns number of characters counted to parent process.
// Parent process prints number of characters counted by child process.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
static int toChild[2];
static int fromChild[2];
static char buffer;
int main(int argc, char **argv)
{
int status;
int nChars = 0;
pid_t pid;
pipe(toChild);
pipe(fromChild);
if ((pid = fork()) == -1) {
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
close(toChild[1]);
close(fromChild[0]);
// Receive characters from parent process via pipe
// one at a time, and count them.
int count = 0;
printf("child about to read\n");
while(read(toChild[0], &buffer, 1)){
count++;
}
// Return number of characters counted to parent process.
write(fromChild[1], &count, sizeof(count));
close(toChild[0]);
close(fromChild[1]);
printf("child exits\n");
}
else {
close(toChild[0]);
close(fromChild[1]);
// -- running in parent process --
printf("CS201 - Assignment 3 - Chris Gavette\n");
write(toChild[1], &argv[1], 1);
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
read(fromChild[0], &nChars, 1);
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
close(toChild[1]);
close(fromChild[0]);
waitpid(pid, &status, 0);
printf("child counted %d chars\n", nChars);
printf("parent exits\n");
return 0;
}
}
The child process seems to hang even though I've closed both ends of both pipes.
For starters, this is wrong.
write(toChild[1], &count, 1)
It will eventually contribute to your problem. count is a int, not char or unsigned char. You need to send sizeof(count). Also, the read-function upon hitting an error will return EOF, which is non-zero, so your child exit condition is not appropriate. it should look something like this:
while(read(toChild[0], &buffer, 1) == 1)
Finally, your parent process should cycle through each argument in argv[] sending each as a strlen sized buffer.
I'm nearly certain this is what you're trying to do. Note that in order to maintain sanity in knowing which descriptor is used for a specific purpose, I prefer using a #define to note what each process uses for reading and writing. This can be extended to any number of processes, btw, which I'm sure is not too far down the line for your next assignment:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
// P0_READ - parent read source
// P0_WRITE - parent write target
// P1_READ - child read source
// P1_WRITE - child write target
#define P0_READ 0
#define P1_WRITE 1
#define P1_READ 2
#define P0_WRITE 3
#define N_PIPES 4
int main(int argc, char **argv)
{
int fd[N_PIPES], count = 0, i;
pid_t pid;
char c;
if (pipe(fd) || pipe(fd+2))
{
perror("Failed to open pipe(s)");
return EXIT_FAILURE;
}
// fork child process
if ((pid = fork()) == -1)
{
perror("Failed to fork child process");
return EXIT_FAILURE;
}
// child process
if (pid == 0)
{
// close non P1 descriptors
close(fd[P0_READ]);
close(fd[P0_WRITE]);
// get chars from input pipe, counting each one.
while(read(fd[P1_READ], &c, 1) == 1)
count++;
printf("Child: count = %d\n", count);
write(fd[P1_WRITE], &count, sizeof(count));
// close remaining descriptors
close(fd[P1_READ]);
close(fd[P1_WRITE]);
return EXIT_SUCCESS;
}
// parent process. start by closing unused descriptors
close(fd[P1_READ]);
close(fd[P1_WRITE]);
// send each arg
for (i=1; i<argc; ++i)
write(fd[P0_WRITE], argv[i], strlen(argv[i]));
// finished sending args
close(fd[P0_WRITE]);
// Wait for child process to return.
wait(NULL);
// wait for total count
if (read(fd[P0_READ], &count, sizeof(count)) == sizeof(count))
printf("Parent: count = %d\n", count);
// close last descriptor
close(fd[P0_READ]);
return 0;
}
Input
./progname argOne argTwo
Output
Child: count = 12
Parent: count = 12
Edit: Single Pipe with Child Return Status
It seems from the comments of the original question your assignment may call for reaping the return status of the child process as the result count rather than returning it in a pipe. In doing so, you can do this with a single pipe-descriptor pair. I prefer the first method, but this works as well:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
// P0_WRITE - parent write target
// P1_READ - child read source
#define P1_READ 0
#define P0_WRITE 1
#define N_PIPES 2
int main(int argc, char **argv)
{
int fd[N_PIPES], count = 0;
pid_t pid;
char c;
if (pipe(fd))
{
perror("Failed to open pipe(s)");
return EXIT_FAILURE;
}
// fork child process
pid = fork();
if (pid == -1)
{
perror("Failed to fork child process");
return EXIT_FAILURE;
}
if (pid == 0)
{
// close non P1 descriptors
close(fd[P0_WRITE]);
// Return number of characters counted to parent process.
while(read(fd[P1_READ], &c, 1) == 1)
++count;
close(fd[P1_READ]);
printf("Child: count = %d\n", count);
return count;
}
// parent process. start by closing unused descriptors
close(fd[P1_READ]);
// eacn each arg entirely
for (int i=1; i<argc; ++i)
write(fd[P0_WRITE], argv[i], strlen(argv[i]));
// finished sending args
close(fd[P0_WRITE]);
// Wait for child process to return.
if (wait(&count) == -1)
{
perror("Failed to wait for child process");
return EXIT_FAILURE;
}
printf("Parent: count = %d\n", WEXITSTATUS(count));
return 0;
}
The results are the same, but note this is a biach to to debug as most debuggers will signal-trip on your child process and the real exit status is lost. On my Mac, for example, running this under Xcode trips:
Failed to wait for child process: Interrupted system call
while running from the command line gives:
Child: count = 12
Parent: count = 12
One of the many reasons I prefer the two-pipe methodology.

headache with named pipes and forks

I need to write program that have construction like this:
Parent makes fifo, then fork()
child 1 reads message from stdin and writes it to named pipe (FIFO)
then in parent process I need to create pipe (unnamed) and another fork()
child number 2 reades from FIFO, counts length of message and send number to parent via pipe(unnamed).
I created a simple program with one fork where child can communicate with parent:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO "/tmp/my_fifo"
int main()
{
pid_t fork_result;
int pipe_fd;
int res;
char writer[3];
char reader[3];
res = mkfifo(FIFO,0777);
if (res == 0)
{
printf("FIFO created!\n");
fork_result = fork();
if (fork_result == -1)
{
fprintf(stderr, "fork error");
exit(EXIT_FAILURE);
}
if (fork_result == 0)
{
printf("CHILD 1\n");
pipe_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
scanf("%s", writer);
res = write(pipe_fd,writer,3);
if (res == -1)
{
fprintf(stderr,"error writing fifo\n");
exit(EXIT_FAILURE);
}
(void)close(pipe_fd);
exit(EXIT_SUCCESS);
}
else
{
printf("PARENT\n");
pipe_fd = open(FIFO, O_RDONLY);
res = read(pipe_fd, reader, 3);
printf("reader: 0: %c\n",reader[0]);
printf("reader: 1: %c\n",reader[1]);
printf("reader: 2: %c\n",reader[2]);
(void)close(res);
}
}
else
{
printf("deleting fifo... run program again!\n");
unlink(FIFO);
}
exit(EXIT_SUCCESS);
}
and it is working very well. So I created code that have architecture described above:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO "/tmp/my_fifo"
int main()
{
pid_t fork_result;
pid_t fork_result2;
int pipe_fd;
int res;
char writer[3];
char reader[3];
res = mkfifo(FIFO,0777);
if (res == 0)
{
printf("FIFO created!\n");
fork_result = fork();
if (fork_result == -1)
{
fprintf(stderr, "fork error");
exit(EXIT_FAILURE);
}
if (fork_result == 0)
{
printf("CHILD 1\n");
pipe_fd = open(FIFO, O_WRONLY | O_NONBLOCK);
scanf("%s", writer);
res = write(pipe_fd,writer,3);
if (res == -1)
{
fprintf(stderr,"error writing to fifo\n");
exit(EXIT_FAILURE);
}
(void)close(pipe_fd);
exit(EXIT_SUCCESS);
}
else
{
printf("PARENt 1\n");
//don't forget pipe!
fork_result = fork();
pipe_fd = open(FIFO, O_RDONLY);
if (fork_result == 0)
{
printf("CHILD 2\n");
res = read(pipe_fd, reader, 3);
printf("Odczytano: 0: %c\n",reader[0]);
printf("Odczytano: 1: %c\n",reader[1]);
printf("Odczytano: 2: %c\n",reader[2]);
(void)close(res);
}
}
}
else
{
printf("deleting fifo\n");
unlink(FIFO);
}
exit(EXIT_SUCCESS);
}
Running sequence is like this:
PARENT 1
CHILD 1
CHILD 2
so in Parent 1 I'm opening FIFO to read, in child 1 I'm writing to FIFO and child 2 should read it. I mean in code because when I run it I can't even write anything to FIFO. In blocks in scanf("%s", writer); which worked in first program.
Am I using open() correctly? Do I need to use getpid() somewhere? Why it's blocking when I try to write to fifo.
The problem is that CHILD1 is opening the fifo with O_NONBLOCK, which will fail (with EWOULDBLOCK or EAGAIN) if no other process has the fifo open for reading. Now in the first program, the parent continues running after the fork and opens the fifo for reading before the child gets going and opens the write end, so it works. But in the second case, the parent does an extra fork first, which slows it down just enough that CHILD1 gets to its open command before PARENT or CHILD2 has opened the fifo for reading, so the CHILD1 open fails.
Get rid of the O_NONBLOCK and it works just fine (though you do open the fifo for reading in both PARENT and CHILD2, which is probably not what you want).
You have another issue if you want to read from the keyboard. If you run this from the shell, PARENT will exit immediately (more or less), so the shell will go back to reading commands from the keyboard, which means that CHILD1 and the shell will be fighting over the input. If on the other hand, you do what you originally describe and have PARENT wait reading from a pipe from CHILD2, it should do what you want.
Isn't it because you use twice the same variable fork_result? As you created another variable fork_result2, which you don't use, it is probably unintended.
I don't know if this will solve your problem, but at least using fork_result2 at the second fork would make it easier to understand...

Resources