CS 4
CS 4
• The function vfork has the same calling sequence and same return values as fork.
• The vfork function is intended to create a new process when the purpose of the
new process is to exec a new program.
• The vfork function creates the new process, just like fork, without copying the
address space of the parent into the child, as the child won't reference that
address space; the child simply calls exec (or exit) right after the vfork.
• Instead, while the child is running and until it calls either exec or exit, the child
runs in the address space of the parent.
• Another difference between the two functions is that vfork guarantees that the
child runs first, until the child calls exec or exit. When the child calls either of
these functions, the parent resumes.
#include <unistd.h>
pid_t vfork(void);
#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
Both return: process ID if OK.
The wait function can block the caller until any one of its child
process terminates first, whereas waitpid has an option that
prevents it from blocking.
The waitpid function doesn't wait for the child that terminates
first; it has a number of options that control which process it waits
for.
The options constants for waitpid
• WIFCONTINUED (status) : True if status was returned for a child that has
been continued after a job control stop.
Program to Demonstrate various exit statuses :
Int main(void)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) /* child */
exit(7);
if (wait(&status) != pid) /* wait for child */
err_sys("wait error");
pr_exit(status); /* and print its status */
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) /* child */
abort(); /* generates SIGABRT */
if (wait(&status) != pid) /* wait for child */
err_sys("wait error");
pr_exit(status); /* and print its status */
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) /* child */
status /= 0; /* divide by 0 generates SIGFPE */
if (wait(&status) != pid) /* wait for child */
err_sys("wait error");
pr_exit(status); /* and print its status */
exit(0); }
Void pr_exit(int status)
if (WIFEXITED(status))
else if (WIFSIGNALED(status))
else if (WIFSTOPPED(status))
}
The waitpid function provides three features that aren't provided
by the wait function.
The waitpid function provides support for job control with the
WUNTRACED and WCONTINUED options.
Program to Avoid zombie processes by calling fork twice :
Int main(void)
{
pid_t pid;
if ((pid = fork()) < 0)
{
err_sys("fork error");
}
else if (pid == 0)
{
/* first child */
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid > 0)
exit(0);
/* parent from second fork == first child */
/* * We're the second child; our parent becomes init as soon * as our real parent calls exit() in the statement
above. * Here's where we'd continue executing, knowing that when * we're done, init will reap our status. */
sleep(2);
printf("second child, parent pid = %d\n", getppid());
exit(0);
}
if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
err_sys("waitpid error");
/* * We're the parent (the original process); we continue executing, * knowing that we're not the parent of the
second child. */
exit(0);
}
Output: $ ./a.out
second child, parent pid = 1
wait3 AND wait4 FUNCTIONS
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
Both return: process ID if OK,-1 on error
• The resource information includes such statistics as the amount of user
CPU time, the amount of system CPU time, number of page faults, number
of signals received etc.
• The resource information is available only for terminated child process not
for the process that were stopped due to job control.
Avoiding Race Condition Using Signals
static void charatatime(char *);
int main(void)
{ Static void charatatime(char *str)
pid_t pid; {
TELL_WAIT(); char *ptr; int c;
if ((pid = fork()) < 0) setbuf(stdout, NULL); /* set unbuffered */
{ for (ptr = str; (c = *ptr++) != 0; )
err_sys("fork error"); putc(c, stdout);
} }
else if (pid == 0)
{
WAIT_PARENT(); /* parent goes first */
charatatime("output from child\n");
}
else
{
charatatime("output from parent\n");
TELL_CHILD(pid);
}
exit(0);
}
Program Execution
• When a process calls one of the exec
functions, that process is completely replaced
by the new program, and the new program
starts executing at its main function.
• The process ID does not change across an
exec, because a new process is not created;
exec merely replaces the current process - its
text, data, heap, and stack segments - with a
brand new program from disk.
6 exec functions:
#include <unistd.h>
int execl(const char *pathname, const char *arg0,... ,(char *)0);
int execv(const char *pathname, char *const argv []);
int execle(const char *pathname, const char *arg0,... ,(char *)0, char *const envp[]);
int execve(const char *pathname, char *const argv[], char *const envp[]);
int execlp(const char *filename, const char *arg0, ... ,(char *)0 );
int execvp(const char *filename, char *const argv []);
#include <stdlib.h>
void exit(int status);
• The atexit() function adds func to a list of functions that are called when the process
terminates.
• The function func should be defined to take no arguments and return no value, thus having
the following general form:
void
func(void)
{
/* Perform some actions */
}
• It is possible to register multiple exit handlers (and even the same exit handler multiple times).
Limitations of atexit()
• The first is that when called, an exit handler
doesn’t know what status was passed to exit().
Occasionally, knowing the status could be useful
for example, we may like to perform different
actions depending on whether the process is exiting
successfully or unsuccessfully.
• The second limitation is that we can’t specify an
argument to the exit handler when it is called.
On_exit()
• To address the limitations of atexit(), there is an alternative method of registering
exit handlers: using on_exit().
#include <stdlib.h>
int on_exit(void (*func)(int, void *), void *arg);
Returns 0 on success, or nonzero on error