Return type of vfork() - vfork

From the GNU manual:
The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(),
What does it mean? Does it mean the return value of vfork() cannot be assigned to a non-pid_t type variable?

The manual is quite confusing on this. Actually, both processes (the child and the father) shared the same address space, even the stack!
vfork() returns twice:
In the child process, returning 0
When the child is either finished or executed some other program, the second return is done in the father process with the child's process identifier. Meanwhile, the father process was suspended.
The return code of fork()/vfork() is typically stored in a variable (of type pid_t to follow the synopsis of the system calls):
pid_t pid = vfork();
As the address spaces are shared between the father and the child when we are running vfork(), the same variable is modified in both the father and the child! But it is set sequentially to 0 in the child process and after the latter either exits or executes a program, the variable is set a second time but with the child's pid in the father process.
NB: The manual says:
vfork() differs from fork(2) in that the calling thread is suspended
until the child terminates (either normally, by calling _exit(2), or
abnormally, after delivery of a fatal signal), or it makes a call to
execve(2).

Related

How to check if all child processes ended?

I am trying to create an assignment where I want to check if all child process created by students have exited. As I am not calling fork, I don't have access to thread ids. Is there a way to check if the current process doesn't have any children without knowing thread ids of child processes created?
I checked many questions but every solution consists of the use of return value from the fork call. Any help is appreciated.
Thank you.
You can call
int st = waitpid(-1, NULL, WNOHANG);
The first argument tells waitpid() to wait for any child process to exit, not for a specific pid.
The third argument is a flag, that makes waitpid() return immediately instead of blocking.
Now there are three possible outcomes:
return value is -1 and errno is ECHILD: this means, that there is no child process present at all
return value is >0: this denotes, that a child has exited in the past, but the return value was not yet collected (a so-called zombie process). Now iterate the process (call waitpid() again).
return value is 0: in this case, there are child processes available that are still running.
This should cover all cases you ask for.

How is the flow of control in this program involving fork() system call?

From what I read about fork() system call
Fork system call use for creates a new process, which is called child process, which runs concurrently with parent process
After a new child process created, both processes will execute the next instruction following the fork() system call
fork() returns 0 to the child process
fork() returns Process ID of newly created child process to parent process (Positive value)
fork() returns negative value if child process creation fails
In this piece of code
void foo() {
if (fork() == 0)
printf("Hello from Child!\n");
else
printf("Hello from Parent!\n");
}
int main() {
foo();
return 0;
}
The output is
Hello from Parent!
Hello from Child!
The child process was created when the control was inside the condition of if-else of function foo in main process.
So from where (which instruction) did the child process start executing?
As it can be observed from the output, Hello from Parent is printed when fork() returns 0. So from my understanding Hello from Parent was actually printed by the Child Process
fork() returned a positive value to the parent process and the parent process printed Hello from Child. Is my understanding about this correct?
And from which instruction exactly did the child process started executing? The function call to fork() was given inside the condition section of a if-else. So the child should have started executing after that if-else but that is not what is happening?
Let's start by identifying a primary misconception here:
As it can be observed from the output, Hello from Parent is printed when fork() returns 0. So from my understanding Hello from Parent was actually printed by the Child Process
The child and the parent are two separate processes running concurrently. The order of these two outputs isn't well-defined, will vary based on your kernel and other timing considerations, and isn't correlated with the fact that your code contains the if/else block written as you have it.1
Let's rewrite your code as a linear stream of "instructions" in an abstract sense:
0: Function foo():
1: Invoke system call fork(), no arguments, store result to $1
2: If $1 is non-zero, jump to label #1.
3: Invoke C function printf(), argument "Hello from Child!"
4: Jump to label #2.
5: Label #1:
6: Invoke C function printf(), argument "Hello from Parent!"
7: Label #2:
8: return control to calling function.
Once your program reaches 1:, the system call is invoked, transferring control to the kernel. The kernel duplicates the process, puts the PID of the child into the return value of fork in the parent process, and puts 0 into the return value of fork in the child. On x86, the return value is stored in register eax (rax for x64) as part of the syscall calling convention.
One of these two processes will eventually get scheduled to run by the kernel. In your case, the child process happened to be the first to get scheduled. Your user-mode code took control back from kernel mode, read the return value (out of eax/rax if on x86) which was zero, and did not jump to label #1. It printed Hello from Child!, and then returned from the function (to the caller of foo, since the child got a copy of the parent's stack).
The same happened for the parent, except the parent got a non-zero value back from the system call, and printed Hello from Parent!. It got scheduled to run, and your user-mode code took control from the kernel at the same point, just with a different value returned by the system call.
1 It's also possible that the two outputs might become interleaved in some way, but that's not as relevant to this discussion, and requires understanding how Linux processes perform I/O.
The child process is a second process that executes in parallel. You might just as easily have gotten
Hello from Child!
Hello from Parent!
For example, if you have a terminal window open, and you start firefox &, which runs “first,” the terminal window or the browser window? Both are running at the same time.
In fact, Linux starts the child process slightly before it resrarts the parent. This is because a large number of programs that call fork() immediately have the child exec() a program, which frees the parent from needing to share all its memory with the child. This is more efficient, because shared memory is copy-on-write.

Developing a correct understanding of waitpid() and getpid()

I am learning about forks, execl and parent and child processes in my systems programming class. One thing that is confusing me is waitpid() and getpid(). Could someone confirm or correct my understanding of these two functions?
getpid() will return the process ID of whatever process calls it. If the parent calls it, it returns the pid of the parent. Likewise for the child. (It actually returns a value of type pid_t, according to the manpages).
waitpid() seems more complex. I know that if I use it in the parent process, without any flags to prevent it from blocking (using WNOHANG), it will halt the parent process until the child process terminates. I'm a little unsure as to how waitpid() manages all this, however. waitpid() also returns pid_t. What is the value of the pid_t waitpid() returns? How does this change depending on whether or not a parent or child calls it, and whether or not a child process is still running, or has terminated?
Your understanding of getpid is correct, it returns the PID of the running process.
waitpid is used (as you said) to block the execution of a process (unless
WNOHANG is passed) and resume execution when a (or more) child of the process
ends. waitpid returns the pid of the child whose state has changed, -1 on
failure. It also can return 0 if WNOHANG has specified but the child has not
changed the state. See:
man waitpid
RETURN VALUE
waitpid(): on success, returns the process ID of the child whose state has changed; if WNOHANG
was specified and one or more child(ren) specified by pid exist, but have not yet changed state,
then 0 is returned. On error, -1 is returned.
Depending on the arguments passed to waitpid, it will behave differently. Here
I'l quote the man page again:
man waitpid
pid_t waitpid(pid_t pid, int *wstatus, int options);
...
The waitpid() system call suspends execution of the calling process until a child specified by pid argument
has changed state. By default, waitpid() waits only for terminated children, but this behavior is modifiable
via the options argument, as described below:
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.
The value of options is an OR of zero or more of the following constants:
WNOHANG: return immediately if no child has exited.
WUNTRACED also return if a child has stopped (but not traced via ptrace(2)).
Status for traced children which have stopped is provided even if this option is not specified.
WCONTINUED (since Linux 2.6.10) also return if a stopped child has been resumed by delivery of SIGCONT.
I'm a little unsure as to how waitpid() manages all this
waitpid is a syscall and the OS handles this.
How does this change depending on whether or not a parent or child calls it, and whether or not a child process is still running, or has terminated?
wait should only be called by a process that has executed fork(). So the parent
process should cal wait()/waitpid. If the child process hasn't called
fork(), then it doesn't need to call either one of these functions. If however
the child process has called fork(), then it also should call
wait()/waitpid().
The behaviour of these function is very well explained in the man page, I quoted the important parts of it. You should read the whole man page
to get a better understanding of it.
waitpid "shall only return the status of a child process" (from the POSIX spec). So the pid_t waitpid returns belongs to one of the current or former children of the process calling waitpid. For example, if a child has recently terminated, it returns that child's PID.
waitpid is only useful when called from a parent process. If called from a process that does not have any children, it returns ECHILD.
waitpid can check the status of children that have terminated, or that has recently stopped or continued (e.g., ^Z from a shell). The various pid/option argument combinations in the spec tell you the various types of information you can return. For example, the WCONTINUED option requests status of recently-continued children instead of recently-terminated children.

Determine if my application terminated due to a call to _exit()

I can determine if my application last terminated due to a call to exit() by using atexit or a destructor function. Is there any way to determine if my application last terminated due to _exit()?
From the man page
The function _exit() terminates the calling process "immediately".
Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process's parent is sent a SIGCHLD signal.
The value status is returned to the parent process as the process's exit status, and can be collected using one of the wait(2) family of calls.
and you cannot expect atexit() to be called. However, similarly to exit, a status is set and returned from _exit that you might want to test from a calling script, for instance. (e.g. exit(0); and _exit(1);, if the returned value is 1 you know that _exit was used, not exit.)

File descriptor - parent and forked child

I'm writing a cgi program for my small webserver. That program then forks to create a child. As far as I know, parent and its children share the same file descriptor, so I expected to see the child's output, which actually didn't happen.
the cgi program is basically like this:
printf("Content-Type: text/plain;charset=us-ascii\n\n");
printf("parent");
pid=fork();
if(pid==0) printf("child");
wait(null);
What i expected are both "parent" and "child", but in fact it was just "parent". Could anyone help me to explain? Appreciate any help
You should double check that a child process is actually being created. From here you should verify that the returned pid is not -1 and if so, check the errno for more information:
RETURN VALUE
Upon successful completion, fork() shall return 0 to the child process
and shall return the process ID of the
child process to the parent process.
Both processes shall continue to
execute from the fork() function.
Otherwise, -1 shall be returned to the
parent process, no child process shall
be created, and errno shall be set to
indicate the error.
ERRORS
The fork() function shall fail if:
[EAGAIN]
The system lacked the necessary resources to create another
process, or the system-imposed limit
on the total number of processes under
execution system-wide or by a single
user {CHILD_MAX} would be exceeded.
The fork() function may fail if:
[ENOMEM]
Insufficient storage space is available.
If the above does not help, it would probably be useful if you could give some more information on the operating system you're trying to do this on, but I'd imagine this is pretty standard code across most platforms.

Resources