The waitpid() parameters - c

I have a question about the waitpid parameters.
I'm supposed to start p[1] (process 1) when p[0] is done.
This is what starts p0:
if(p[0] == 0){
process(0,1); //(process, duration(time))
return 0;
}
Now I want p1 to start as soon as p0 ends (after 1 sec)
if(p[1] == 0){
process(1,2);
return 0;
}
waitpid(p[0], NULL, 0);
Here's my question: what do the parameters in waitpid mean? should the last parameter be set to 1, since p[0] ends after 1 sec and this is when I want p[1] to start?

what does the parameters in waitpid means?
You can look up the manual of waitpid(3) for the meanings of its arguments.
In your case,
waitpid(p[0], NULL, 0);
means
p[0]: wait for the pid hold on p[0]
NULL: don't care about status
0: no flags
should the last parameter be set to 1, since p[0] ends after 1 sec and this is when I want p[1] to start?
To achieve your goal, starting process 1 as soon as process 0 ends, you should put the waitpid(...); statement before the fork() used to create process 1, and use right parameters in your call to waitpid().

Full documentation is on the manpage or here: http://linux.die.net/man/2/waitpid
Basically you have 3 parameters:
pid_t waitpid(pid_t pid, int *status, int options);
pid is the process you are waiting for. Unless you are waiting for multiple children (in which case specify 0, -1, or a number less than -1 - details in the manpage), specify the pid of your process here.
status is a pointer to an integer which will be filled in with the exit status. This is a combination of the process's exit status and a description of how it has (or has not) exited. The manpage gives you macros you can use to understand this.
options can be filled in with a number of flags, ored together. The most useful of these is the somewhat oddly named W_NOHANG, which makes waitpid simply tell you whether the process has finished (and if so what its exit status was) rather than wait for it to finish.

It's used generally to wait until a specific process finishes (or otherwise changes state if you're using special flags), based on its process ID (otherwise known as a pid).
It can also be used to wait for any of a group of child processes, either one from a specific process group or any child of the current process.
for example
pid_t child_pid;
int status;
child_pid = fork();
if (child_pid == 0) {
// in child; do stuff including perhaps exec
} else if (child_pid == -1) {
// failed to fork
} else {
if (waitpid(child_pid, &status, 0) == child_pid) {
// child exited or interrupted; now you can do something with status
} else {
// error etc
}
}
No regarding to parameter in waitpid is as follows
first argument: pid_t pid
It is the pid of process for which you Wait for the process to exit
second argument : int *status
it is the current status of the program, you can use the macros to test for each condition, such as WIFEXITED , WIFSIGNALED
Third argument: int options
The options argument should be 0. You are not required to implement any options. (However, your system should check to make sure that options you do not support are not requested.)

Related

Best practice for waiting for a child process termination in C

I am writing a C library that at some point forks another process and then waits for its completion.
I'd like to write the code that waits for the child process completion in the most robust and generic way, to take care of all possible scenarios, such as the calling process spawning other child processes, receiving signals etc.
Does the following C code use waitpid properly, i.e. in the most robust way?
void waitForChildProcess(int child_pid) {
int rc, err;
do {
//waiting only for my own child and only for its termination.
//The status value is irrelevant (I think) because option '0' should mean
//to only wait for a child termination event
// and I don't care about the child's exit code:
rc = waitpid(child_pid, NULL, 0);
err = errno;
} while (rc == -1 && err == EINTR); //ignoring a signal
}
Yes, waitpid(child_pid, ...) is the most robust way.
It will return child_pid if the child process has exited, -1 with errno set if an error occurs (ECHILD if the child process does not exist (was never created or has already been reaped) or is not a child of this process, EINVAL if the options (third parameter) had an invalid value, or EINTR if a signal was delivered to a signal handler that was not installed with SA_RESTART flags), or 0 if WNOHANG option (third parameter) was specified and the child process has not yet exited.
I would recommend a slight change, however:
/* Wait for child process to exit.
* #child_pid Process ID of the child process
* #status Pointer to where the child status
* is stored; may be NULL
* #return 0 if success
* -1 if an error occurs, see errno.
*/
int waitForChildProcess(pid_t child_pid, int *status)
{
int rc;
if (child_pid <= 1) {
errno = EINVAL;
return -1;
}
do {
rc = waipid(child_pid, status, 0);
} while (rc == -1 && errno == EINTR);
if (rc == child_pid)
return 0;
/* This should not happen, but let's be careful. */
if (rc != -1)
errno = ECHILD;
return -1;
}
In Linux and POSIXy systems, process ID's are positive integers. As you can see in the man 2 waitpid man page, zero and negative PIDs refer to process groups, and -1 to any child process. Process 1 is special, init; it is the one that never exits and sets up the rest of the userspace. So, the smallest PID a child of the current process can ever have is 2.
I do consider it sensible to use the proper types for these: pid_t for process IDs, and for example size_t for memory sizes of objects (including the return value of say strlen().)
Providing the status pointer (so that the caller can check it with WIFEXITED()+WEXITSTATUS() or WIFSIGNALED()+WTERMSIG()) is a convenience, since any callers not interested in it can provide a NULL. (NULL is explicitly allowed for the status pointer for wait() and waitpid().)
Technically, with options==0, waitpid() should only ever return either the child PID, or -1 (with errno set). However, since the check is so cheap, I prefer to treat everything else as an ECHILD error, since that gives the most robust results.
The caller is free to ignore the return value. However, if they want to know, the return value is 0 if successful, otherwise -1 with errno set (and strerror(errno) provides the textual reason).

fork and waitpid in C

I have this piece of code, maybe I'm missing something:
const int NPROCESSES = 32;
pid_t pids[128];
for (int i = 0; i < NPROCESSES;i ++) {
pids[i] = fork();
if (!pids[i]) {
/*... other code ...*/
exit(0);
}
}
for (int i = 0; i < NPROCESSES; i++)
waitpid(pids[i], 0, 0);
The program should launch 32 processes and wait until all processes are terminated. But sometimes the program get blocked with child zombie processes.
Where am I wrong?
Using:
waitpid(pids[i], 0, 0);
you specify an exact order in which the parent will reap its children: it will be the same order as they were created.
As a result, if one of the children blocks or delays for any reason, and some other child which was created later has already finished (and called exit()), the latter will remain in a zombie state, until the parent reaps the former child first.
So if, for example, the process created in the first iteration of the loop needs 1min to complete and the rest 31 processes are completed in 1sec, you're be able to observe 31 zombie processes waiting to be reaped by their parent, who (the parent) will wait to reap that one delayed process first.
To change this behavior, the parent can use:
waitpid(-1, NULL, 0);
instead. A value equal to -1 in the first argument of waitpid() means it will reap any of the child processes, quoting from man 2 waitpid:
The value of pid can be:
< -1
meaning wait for any child process whose process group ID is equal to
the absolute value of pid.
-1
meaning wait for any child process.
0
meaning wait for any child process whose process group ID is equal to
that of the calling process.
> 0
meaning wait for the child whose process ID is equal to the value of
pid.
Alternatively, you can just use:
wait(NULL);
which is the same as waitpid(-1, NULL, 0).

C - using exec() instead of system()

In the following code:
int main ( int argc, char *argv[] ) {
int i, pid, status;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
if(pid < 0) {
printf("Error occured");
exit(1);
} else if (pid == 0) {
status = system("./frun test.txt 1");
if (status != 0)
printf("ERROR, exited with %d\n", status);
else
printf("SUCCESS, exited with %d\n", status); // 0
exit(0);
} else {
wait(NULL);
}
}
return 0;
}
I am using system() to run a program called 'frun'
My question is - how would I change the code to use one of the exec() family functions instead?
My main problem is that I need to get the exit code of the program and I can't find a way to do it with exec(), while system() just returns the exit status.
Read the manual pages for wait and exec.
You wait on the process created from forking and execing (recall that exec replaces the current process, so you must fork to get its exit code). This is from the man page for wait:
Regardless of its value, this information may be interpreted using the following
macros, which are defined in <sys/wait.h> and evaluate to integral expressions; the
stat_val argument is the integer value pointed to by stat_loc.
WIFEXITED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that
terminated normally.
WEXITSTATUS(stat_val)
If the value of WIFEXITED(stat_val) is non-zero, this macro evaluates to the
low-order 8 bits of the status argument that the child process passed to _exit()
or exit(), or the value the child process returned from main().
WIFSIGNALED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that
terminated due to the receipt of a signal that was not caught (see <signal.h>).
WTERMSIG(stat_val)
If the value of WIFSIGNALED(stat_val) is non-zero, this macro evaluates to the
number of the signal that caused the termination of the child process.
WIFSTOPPED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that is
currently stopped.
WSTOPSIG(stat_val)
If the value of WIFSTOPPED(stat_val) is non-zero, this macro evaluates to the
number of the signal that caused the child process to stop.
WIFCONTINUED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that
has continued from a job control stop.
In your case you'd probably want to use WEXITSTATUS(stat_val) to get the 8 bit exit code.
You call waitpid(pid, stat_loc, options) where you'd pass the pid returned from fork(), a pointer to a local int (where the status is stored), and your options flags (or 0). You would do this is in the branch where pid != 0, since this is the original process. The original process calling fork() (where pid == 0) would call exec and thus be replaced by the exec'd command.
Here is a pseudo-example that you can adapt to your code:
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
exec(/*look up the different functions in the exec family and how to use them*/);
}
else if (pid < 0)
{
//uh oh
}
else
{
waitpid(pid, &status, 0);
printf("Exited with %d\n", WEXITSTATUS(status));
}
Though you should check the result of waitpid.

How to use fork() in an if statement

Can someone please explain to me what does fork() != 0 mean? From what I understand I think it means if fork is not false? Or if fork is true then.... I don't understand how Fork() can be true or false, seeing that it just creates a copy of a process into a parent and child. Also if a program where to say if (Fork() == 0) what would that mean?
#include "csapp.h"
int main(void)
{
int x = 3;
if (Fork() != 0)
printf("x=%d\n", ++x);
printf("x=%d\n", --x);
exit(0);
}
fork() returns -1 if it fails, and if it succeeds, it returns the forked child's pid in the parent, and 0 in the child. So if (fork() != 0) tests whether it's the parent process.
From man fork
Return Value
On success, the PID of the child process is returned in the parent,
and 0 is returned in the child. On failure, -1 is returned in the
parent, no child process is created, and errno is set appropriately.
Assuming success, fork returns twice: once in the parent, and once in the child.
OK, I did the OP a disservice: I don't know where csapp.h comes from, but if it's this one then it isn't doing you any favours. I guess it is a thin wrapper on POSIX (eg. around fork()), but maybe works on other platforms too?
Because you mentioned fork() before Fork(), I assumed the latter was a typo, whereas it's actually a library function.
If you had been using fork() directly, it would be reasonable to expect you to check the manpage.
Since you're using a Fork() function provided by some library, that library really ought to document it, and doesn't seem to.
Standard (non csapp) usage is:
pid_t child = fork();
if (child == -1) {
printf("fork failed - %d - %s\n", errno, strerror(errno));
exit(-1);
}
if (child) {
printf("I have a child with pid %d, so I must be the parent!\n", child);
} else {
printf("I don't have a child ... so I must be the child!\n")
}
exit(0);
Let's try explaining it differently... When the function starts there's 1 process, this process has a int x = 3
Once you hit this line of code:
if (fork() != 0)
Now, assuming the fork() worked, we have two processes. They both have the same execution space, they both are going to run the same code (to a point), but the child will get its own copy of x to play with.
fork() will return a 0 to the child process, so from the child processes' prospective, the rest of the function is this:
printf(("x=%d\n", --x);
exit(0);
The parent process on the other hand, will get a valid value back from the fork() command, thus it will execute:
printf("x=%d\n", ++x);
printf("x=%d\n", --x);
exit(0);
What the output at this point will be is anyone's guess... You can't tell if parent or child will run first
But if we assume the parent hits the ++x is the next operation then the output is:
x=4
x=3
x=2
As both parent and child will hit the --x. (the parent's x was 4 after the ++x, will be 3 at the end. The child's x was 3, will be 2 at the end)
From fork() manual:
Upon successful completion, fork() returns a value of 0 to the child process and returns the process ID of the child process to the parent
process. Otherwise, a value of -1 is returned to the parent process, no child process is created, and the global variable errno is set to indi-
cate the error.
After the code execution you have two execution threads. Into the if statement you have the parent process' thread and in else statement you have the child process' thread.
if ( fork() ) {
printf("I am the parent!\n");
} else {
printf("I am the child\n");
}
EDIT
For clarification purpose: fork starts a process, which has a thread, memory and may have other resources. I tried (it seems like that without success) to emphasize the flows of execution by adding the "thread" word.
However, by no means, one can say that "parent" relates to "thread" in "parent process' thread".
Of course, my answer could be improved but I think there are already enough good answers here.
Fork returns 0 for the child process and the process id of the child to the parent process. Hence commonly code has if(fork){ }else code. Which implies that the code inside the if is going to be executed only in a parent.
The better way to deal with it is
pid = fork()
if(pid){
// I am parent. Let us do something that only the parent has to do
}else{
// I am child. Let us do something only the child has to do
}
// This code is common to both
The child pid may be useful to wait upon later or to detach from the parent.
I recommend replacing the if with a switch because there are 3 possible results:
#include <sys/types.h>
#include <unistd.h>
pid_t pid;
switch ((pid = fork ())) {
case -1: /* error creating child. */
break;
case 0: /* I am the child process. */
break;
default: /* I am the parent process. */
break;
}

What is the difference between fork()!=0 and !fork() in process creation

Currently, I am doing some exercises on operating system based on UNIX. I have used the fork() system call to create a child process and the code snippet is as follows :
if(!fork())
{
printf("I am parent process.\n");
}
else
printf("I am child process.\n");
And this program first executes the child process and then parent process.
But, when I replace if(!fork()) by if(fork()!=0) then the parent block and then child block executes.Here my question is - does the result should be the same in both cases or there is some reason behind this? Thanks in advance!!
There is no guaranteed order of execution.
However, if(!fork()) and if(fork()!=0) do give opposite results logically: if fork() returns zero, then !fork() is true whilst fork()!=0 is false.
Also, from the man page for fork():
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
So the correct check is
pid_t pid = fork();
if(pid == -1) {
// ERROR in PARENT
} else if(pid == 0) {
// CHILD process
} else {
// PARENT process, and the child has ID pid
}
EDIT: As Wyzard says, you should definitely make sure you make use of pid later as well. (Also, fixed the type to be pid_t instead of int.)
You shouldn't really use either of those, because when the child finishes, it'll remain as a zombie until the parent finishes too. You should either capture the child's pid in a variable and use it to retrieve the child's exit status:
pid_t child_pid = fork();
if (child_pid == -1)
{
// Fork failed, check errno
}
else if (child_pid)
{
// Do parent stuff...
int status;
waitpid(child_pid, &status, 0);
}
else
{
// Child stuff
}
or you should use the "double-fork trick" to dissociate the child from the parent, so that the child won't remain as a zombie waiting for the parent to retrieve its exit status.
Also, you can't rely on the child executing before the parent after a fork. You have two processes, running concurrently, with no guarantee about relative order of execution. They may take turns, or they may run simultaneously on different CPU cores.
The order in which the parent and child get to their respective printf() statements is undefined. It is likely that if you were to repeat your tests a large number of times, the results would be similar for both, in that for either version there would be times that the parent prints first and times the parent prints last.
!fork() and fork() == 0 both behave in the same way.
The condition itself cannot be the reason the execution sequence is any different.
The process is replicated, which means that child is now competing with parent for resources, including CPU. It is the OS scheduler that decides which process will get the CPU.
The sequence in which child and parent processes are being execute is determined by the scheduler. It determines when and for how long each process is being executed by the processor. So the sequence of the output may vary for one and the same program code. It is purely coincidental that the change in the source code led to the change of the output sequence.
By the way, your printf's should be just the other way round: if fork() returns 0, it's the child, not the parent process.
See code example at http://en.wikipedia.org/wiki/Fork_%28operating_system%29. The German version of this article (http://de.wikipedia.org/wiki/Fork_%28Unix%29) contains a sample output and a short discusion about operation sequence.

Resources