fork()
wait()
exec()
fork()
fork()
- vfork()
vfork()
was intended to create a new process for the purpose of executing a new programexec()
to copy another program into the processes memory space for execution.vfork()
Creates the new process without copying the parent processes address space. The child runs within the same address space of the parent until the exec()
or exit()
call is made.vfork
works this way to improve efficiency by eliminating unnecessary memory operationsfork()
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int globvar = 6; /* external variable in initialized data */
int main(void)s{
int var; /* automatic variable on the stack */
pid_t pid;
var = 88;
printf("before vfork\n"); /* we don't flush stdio */
if ((pid = vfork()) < 0) {
perror("vfork error");
} else if (pid == 0) { /* child */
globvar++; /* modify parent's variables */
var++;
_exit(0); /* child terminates */
}
/* parent continues here */
printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar,
var);
exit(0);
}
fork()
While (fork()>0)
while(fork() == 0);
killall
can work but it usually isn’t fast enough to stop the comment.fork()
fork()
bomb as the owner of the cometfork()
s will start to fail (i.e. killing the comet)stop
signal to stop the bombkill
signal to kill all remaining open processesfork()
exec
family of system calls comes to the rescue here.main()
function (this is the equivalent of calling exit()
)exit()
function. This function is defined in ISO C and ensure that exist handlers are called correctly._exit()
function. This function is defined in ISO C and does not call the exit handlersstart
routine of the last thread in the process.pthread_exit()
from the last thread in the process - more on threads down the trackThere are three forms of abnormal termination:
abort
, which generates a SIGABRT
(this is a special case of the following situation)Regardless of how a process terminates, the same kernel function is called to close all file descriptors and de-allocate memory
.center[]
atexit()
function can be used to register up to 32 different functions that are automatically called when a call to exit()
is made by a process#include <stdlib.h>
int atexit( void (*func)(void));
//Returns 0 of the function is called correctly and nonzero on error
func
is a function pointer that must be declared within your source.#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
static void my_exit1(void);
static void my_exit2(void);
int main(void){
if (atexit(my_exit2) != 0)
perror("can't register my_exit2");
if (atexit(my_exit1) != 0)
perror("can't register my_exit1");
if (atexit(my_exit1) != 0)
perror("can't register my_exit1");
printf("main is done\n");
return(0);
}
static void my_exit1(void){
printf("first exit handler\n");
}
static void my_exit2(void){
printf("second exit handler\n");
}
init
(i.e. the scheduler) do not enter the zombie state as the init
process immediately calls one of the wait()
functions to receive the exit statuswait()
wait()
wait
functions:
#include <sys/wait.h>
pid_t wait(int *staloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
wait
and waitpid
both return the process ID of the child process that has terminatedstatloc
pointer is not null
, then the exist status of the child process is stored in the location pointed to by statloc
wait()
Executing a wait causes:
The wait returns immediately if:
wait()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void){
int i, n = 4, status;
pid_t childpid;
for (i = 1; i < n; ++i)
if((childpid = fork()) < 0){
/* fork error */
perror("error in fork");
exit(EXIT_FAILURE); }
else if(childpid){
/* parent code */
wait(&status);
break;
} else {
/* child code */
}
/* mutual code */
printf("This is process %d with parent %d\n",
getpid(), getppid());
return 0;
}
wait()
wait()
ing for each child to finish before spinning off a new childSIGCHLD
signal.wait()
and waitpid()
use these signals to block the parent.wait()
function waits for the child that finishes first.waitpid
function has a number of options that control which process it actually waits forwait()
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(void){
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork error");
} else if (pid == 0) { /* first child */
if ((pid = fork()) < 0)
perror("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 = %ld\n", (long)getppid());
exit(0);
}
if (waitpid(pid, NULL, 0) != pid) /* wait for first child */
perror("waitpid error");
exit(0);
}
wait()
waitpit()
init
to capture its exit status to avid being a zombiewait()
wait()
and waitpid()
functions#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait3(pid_t pid, int *statloc, int options, struct rusage *rusage);
wait()
wait3()
and wait4()
versions include additional information about resources that the process used after it has terminatedwaitid
function allows the porcess to wait for a specific group or all child process to terminate.exec()
exec
family of functions is used to execute a new program within a process that has been created by a call to fork()
fork()
call) is overwritten by a program loaded from storage and the main function is executed.exec()
family:#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg0, ... /*,
(char *)0, char *const envp[]*/);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);
int execvp(const char *file, char *const argv[]);
int fexecve(int fd, char *const argv[], char *const envp[])
exec()
exec()
exec()
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
pid_t childpid, waitreturn;
int status;
if ((childpid = fork()) == -1) {
perror("The fork failed");
exit(1);
} else if (childpid == 0) {
/* child code */
if (execvp(argv[1], &argv[1]) < 0) {
perror("The exec of command failed");
exit(1);
}
...
exec()
...
} else
/* parent code */
while(childpid != (waitreturn = wait(&status)))
if ((waitreturn == -1) && (errno != EINTR))
break;
exit(0);
}
exec()
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "makeargv.h"
int main(int argc, char *argv[]){
char **myargv, delim[] = " \t";
pid_t childpid, waitreturn;
int status;
if (argc != 2) {
fprintf(stderr, "Usage: %s string\n", argv[0]);
exit(EXIT_FAILURE);
}
if ((childpid = fork()) == -1) {
perror("The fork failed");
exit(EXIT_FAILURE);
} else if (childpid == 0) {
/* child code */
if (makeargv(argv[1], delim, &myargv) < 0) {
fprintf(stderr, "Argument array could not be constructed\n");
exit(EXIT_FAILURE);
} else if (execvp(myargv[0], &myargv[0]) < 0) {
perror("The exec of command failed");
exit(EXIT_FAILURE);
}
...
exec()
...
} else
/* parent code */
while(childpid != (waitreturn = wait(&status)))
if ((waitreturn == -1) && (errno != EINTR))
break;
exit(EXIT_SUCCESS);
}
.center[]
open
fork()
wait()
exec()
class: middle, center, inverse