Reaping zombie process - child - c

I am taking command line arguments to main from parent to child and counting them and printing. My question is that i am not sure that i am reaping the child? dont i just need an exit 0
or do i need to call fork again?
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int length = 0;
int i, n;
int fdest[2]; // for pipe
pid_t pid; //process IDs
char buffer[BUFSIZ];
if ((pid = fork()) < 0) /* attempt to create child / parent process */
{
printf("fork error");
}
if (pipe(fdest) < 0) /* attempt to create pipe */
printf("pipe error");
/* parent process */
else if (pid > 0) {
close(fdest[0]);
for(i = 1; i < argc; i++) /* write to pipe */
{
write(fdest[1], argv[i], strlen(argv[1]));
}
} else {
/* child Process */
close(fdest[1]);
for(i = 1; i < argc; i++)
{
length +=( strlen(argv[i])); /* get length of arguments */
}
n = read(fdest[0], buffer, length);
printf("\nchild: counted %d characters\n", n);
}
exit(0);
}

No, you are not reaping the child correctly. In your case, if the child process finishes before the parent process exits, the child will become a zombie. Then, when the parent process finishes, the child will be reparented to init (whether it has finished and is a zombie, or is still running). init is then reaping the child for you.
To reap the child, add a call to wait() before exit.
By the way, you have another bug - you are creating the pipe after the fork, so the parent and child each create a (different) pipe - they're not connected. Move the if (pipe(... up before the fork().

Related

Fork(), wait for all child process to finish vs wait for one child to finish

I don't understand as to where should I use the wait(NULL) or while(pid = wait(&status))>0). I am very confused and I get weird results please help!.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char *argv[]) {
pid_t childpid = 0;
int i, n;
if (argc != 2){ /* check for valid number of command-line arguments */
fprintf(stderr, "Usage: %s processes\n", argv[0]);
return 1;
}
n = atoi(argv[1]);
for (i = 1; i < n; i++)
if ((childpid = fork()) <= 0)
break;
fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n",
i, (long)getpid(), (long)getppid(), (long)childpid);
return 0;
}
How would you modify this code so that the original process prints out its information after all children have exited?
How would you modify this code so that a process prints its information after its child process has exited?
The same modification can do both jobs.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
pid_t childpid = 0;
int i, n;
if (argc != 2)
{ /* check for valid number of command-line arguments */
fprintf(stderr, "Usage: %s processes\n", argv[0]);
return 1;
}
n = atoi(argv[1]);
for (i = 1; i < n; i++)
{
if ((childpid = fork()) <= 0)
break;
}
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
fprintf(stderr, "%d: child %d exited with status 0x%.4X\n",
(int)getpid(), corpse, status);
}
fprintf(stderr, "i:%d process ID:%ld parent ID:%ld child ID:%ld\n",
i, (long)getpid(), (long)getppid(), (long)childpid);
return 0;
}
When a child process executes wait(), it immediately fails since there are no grandchildren to be waited for. Therefore, the child prints its output after "its children" (all zero of them) have exited.
When the parent process executes the wait() loop, it reports on each child as the information is made available, and prints its own information afterwards.
You've got more than one child in general, so the second question is a bit ambiguous. However, if you want it to wait for one child (and you don't care which), then remove the loop from around the wait(). If you care which child, use waitpid() instead of just wait().
You can make the output more interesting by returning i or a number calculated from i in the child processes. Note that before the forking loop runs from 1 rather than 0, so if you specify 4 on the command line, you get 3 child processes plus the original parent process.

C program that tells the user which child process finished first

I am working on an assignment that involves using fork. The program runs two separate programs simultaneously and tells the user which one finished first. If a child finishes, the other child still running should be killed immediately.
My code so far is this...
int main(int argc, char **argv) {
if (argc != 2) {
perror("Invalid number of arguments!");
exit(1);
}
pid_t pid;
pid_t wpid;
int status = 0;
for (int i = 0; i < 2; i++) {
if ((pid = fork()) == 0) {
execv("/bin/sh", argv[i+1]);
}
}
while ((wpid = wait(&status)) > 0);
printf("%s finished first!", <Insert winning program here>);
return 0;
}
From my understanding, this runs the programs and will not let the parent process continue until the child processes have finished. Now I'm wondering how I can terminate another child and return the winning process.
But how can I immediately get the pid of the losing process so that I can kill it?
Just as TonyB told: the "parent" saves the pid of the new child. 2) wait will tell you the pid of the winning process. More verbose: Save the PID of both children, wait for any one, compare the return value to (one of) the saved PIDs; the matching one is the winner, the non-matching one is the loser. E. g.:
#define _POSIX_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
int main(int argc, char **argv)
{
if (argc != 3) // with two program arguments, argc is 3
fputs("Invalid number of arguments!\n", stderr), exit(EXIT_FAILURE);
pid_t pid[2]; // to store both child pids
pid_t wpid;
for (int i = 0; i < 2; i++)
if ((pid[i] = fork()) == 0)
execl("/bin/sh", "sh", "-c", argv[i+1], NULL),
perror(argv[i+1]), exit(EXIT_FAILURE);
wpid = wait(NULL); // wait for first
int wi = wpid==pid[0] ? 0 : 1; // get index of winner
kill(pid[!wi], SIGKILL), wait(NULL); // kill and reap loser
printf("%s finished first!\n", argv[wi+1]);
return 0;
}

Creating multiple processes via "fork" for one parent process

I would like to create a small program that will accept user input from stdin for the number of processes they would like, and then, my program will fork the n number of processes as specified by the user. Later on, I would like to pipe data from the child to the parent.
However, I want only one parent process. I have been trying to figure out the algorithm for this, and perhaps I am overcomplicating it, but I am stuck.
Do note I can only use the fork and pipe features in C (so nothing too crazy!)
Here is my algorithm.
Loop only if I am a parent process, and do not loop if I am a child process.
If I am a parent process entering the loop, then I will call fork(). Otherwise, I am a child, and I will do some child-related tasks (which I may then pipe back to the parent later on). The child should not re-enter the loop as to avoid creating children-of-children processes.
Does that make any sense?
What would you advise me to do?
Let's say n is the number of children you get as input. Let's see what you could do, if you use one pipe for each child.
In the parent process:
pid_t pid;
int fd[n][2];
for(i = 0; i < n; i++) {
pipe(fd[i]);
pid = fork();
if (pid < 0) {
perror("whatever");
exit(1);
}
else if (pid == 0) {
for(j = 0; j < i; j++) {
if (close(fd[j][0]) < 0) {
perror("closing fd[0]");
exit(1);
}
if (close(fd[j][1]) < 0) {
perror("closing fd[1]");
exit(1);
}
}
func(fd[i]);
}
}
// other parent stuff next && close file discriptors not needed
And your func() should be what the children have to do. It takes as arguments the 2 file descriptors of the child's pipe. Note that in the end of func you should exit().
A solution making a pipe for each child would be a little better but a little more complex than that (hint: you may pass fd's as arguments, also close all fd's with caution!)
Also, you may keep each child's pid by defining pid_t pid[n]; instead of pid, and refer to each pid as pid[i].
Don't forget to wait for every child to die!
If it were me, I would move all of the fork() and pipe() stuff into its own subroutine, with clear semantics, and call that subroutine from a loop in main().
In the example below, spawn() forks, invokes the work function in child, ensures that the child exits appropriately, and returns in the parent.
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
/* Launch a child. This routine exit()s in the child and
* return()s in the parent */
void spawn(void (*fn)(int), int *fd) {
int pipefd[2];
int pid;
if(pipe(pipefd) < 0) {
perror("pipe");
exit(1);
}
switch(pid = fork()) {
case -1: /* Error */
perror("fork");
exit(1);
break;
case 0: /* Child */
close(pipefd[0]); /* Kids only talk */
fn(pipefd[1]); /* Put the kid to work */
exit(0); /* Kill the kid */
break;
default: /* Parent */
close(pipefd[1]); /* Parents only listen */
*fd = pipefd[0];
printf("Spawning PID=%d, FD=%d\n", pid, *fd);
break;
}
}
int
get_number_of_children() {
/* TODO: Do stdin-reading here and return a good number */
return 3;
}
void do_work(int fd) {
/* TODO: Whatever work the children might do */
/* For example: */
write(fd, "hello", 5);
}
int main (int ac, char **av) {
int nkids = get_number_of_children();
int fd_array[nkids];
int pid;
/* Birth the children */
for(int i = 0; i < nkids; i++) {
spawn(do_work, &fd_array[i]);
}
/* TODO: Read the data from the file descriptors in fd_array */
/* Finally, wait for all children to die */
while((pid = wait(0)) != -1) {
printf("Waited PID=%d\n", pid);
}
}

How to implement pipes for multiple processes?

I am creating multiple processes and I need to create two unnamed pipes for each process.
For each child, one pipe will be used to get int value from parent; one for sending to int arrays to parent. Parent will do some things while getting new data from childs.
The base code:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for reaching unix operations
int main(int argc, char *argv[]){
pid_t main = getpid();
int N = 30;
int i;
pid_t* children = (pid_t*) malloc(sizeof(pid_t) * N);
for(i = 0; i < N; i++){
pid_t child = fork();
if ( child == 0){
pid_t me = getpid();
printf("I'm a child and my pid is: %d\n", me);
sleep(1);
// exit(4);
return me * 2;
} else if ( child < 0){
// printf("Could not create child\n");
} else {
children[i] = child;
// printf("I have created a child and its pid %d\n", child);
}
}
// The child never reaches here
for(i = 0; i < N; i++){
int status;
waitpid(children[i], &status, 0);
printf("Process %d exited with return code %d\n", children[i], WEXITSTATUS(status));
}
return 0;
}
I tried many things with no success and I'm lost. Can you help me to continue?
Any help is appreciated! Thank you.
Here's how to set up one pipe for each child process so that each child writes to the parent:
Since you need two file descriptors for each child, declare:
int fd[2 * N];
Initialize them appropriately:
for (int i = 0; i < N; i++) {
pipe(&fd[2*i]);
}
Inside the i-th child process, use:
write(fd[2*i + 1], write_buffer, SIZE)
to write to the parent, and in the parent use:
read(fd[2*i], read_buffer, SIZE)
to read from the i-th child.
To close the pipes:
Inside the i-th child, you can use
close(fd[2*i])
right away, seeing as you're only writing. After you're done writing call
close(fd[2*i + 1])
to close the write end of the pipe.
The situation is parallel in the parent: when reading from the i-th child you can
close(fd[2*i + 1])
right away, since you're not writing, and after you're done reading call
close(fd[2*i])
to close the read end of the pipe.
Since you need two pipes per child process, create two arrays - one containing pipes for the children writing to the parent, and one containing pipes for the parent writing to the children.

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.

Resources