Process Creation
Processes
COP-3402
Table of Contents
UNIX process creation
- Duplicate an existing process with
fork()
- Replace new process's program code
exec()
If all processes are created by fork, where does the first one come from?
Process creation workflow
LPI Figure 24-1
Fork duplicates the process
- Same program running
- Same open files (including stdio)
- "Copy" of memory
LPI Figure 24-2 (open file tables)
LPI Figure 24-3 (copy-on-write)
If fork duplicates a process, how do we avoid both processes just doing the exact same thing?
fork()
Return Value
man fork
- PID of child to parent process
- 0 to the child process
- -1 on failure
Using fork()
simplefork.c
#include <stdio.h> #include <unistd.h> // fork() #include <stdlib.h> // exit() #include <inttypes.h> // intmax_t // ctrl-z and ps // man 2 fork int main(int argc, char **argv) { pid_t pid; sleep(10); if (-1 == fork()) { perror("fork"); exit(EXIT_FAILURE); } sleep(10); printf("hello, world!\n"); sleep(10); }
fork.c
#include <stdio.h> #include <unistd.h> // fork() #include <stdlib.h> // exit() #include <inttypes.h> // intmax_t // ctrl-z and ps // man 2 fork int main(int argc, char **argv) { pid_t pid; switch (pid = fork()) { case -1: perror("fork"); exit(EXIT_FAILURE); break; case 0: // child puts("inside child process\n"); sleep(10); _exit(EXIT_SUCCESS); break; default: // parent printf("child pid: %jd\n", (intmax_t) pid); sleep(10); exit(EXIT_SUCCESS); break; } }
Note that this is the same program, but after fork, there are two processes running the same program.
We can ensure these copies do different things by checking fork's return value.
Using exec
simpleexec.c
#include <stdio.h> #include <unistd.h> // fork(), execve() #include <stdlib.h> // exit() #include <inttypes.h> // intmax_t // // man 2 execve int main(int argc, char **argv) { char *prog = "hello"; // what if the program doesn't exist? char *newargv[] = { NULL }; char *newenv[] = { NULL }; execve(prog, newargv, newenv); perror("execve"); _exit(EXIT_FAILURE); }
exec.c
#include <stdio.h> #include <unistd.h> // fork(), execve() #include <stdlib.h> // exit() #include <inttypes.h> // intmax_t // // man 2 execve int main(int argc, char **argv) { char *prog = "/usr/bin/ls"; char *newargv[] = { NULL }; char *newenv[] = { NULL }; execve(prog, newargv, newenv); perror("execve"); _exit(EXIT_FAILURE); }
Fork and exec
fork_exec.c
#include <stdio.h> #include <unistd.h> // fork() #include <stdlib.h> // exit() #include <inttypes.h> // intmax_t // // man 2 execve int main(int argc, char **argv) { pid_t pid; switch (pid = fork()) { case -1: perror("fork"); exit(EXIT_FAILURE); break; case 0: // child puts("inside child process\n"); char *prog = "/usr/bin/ls"; char *newargv[] = { NULL, "./", NULL }; char *newenv[] = { NULL }; execve(prog, newargv, newenv); perror("execve"); _exit(EXIT_FAILURE); break; default: // parent printf("child pid: %jd\n", (intmax_t) pid); exit(EXIT_SUCCESS); break; } }
fork_exec_sleep.c
#include <stdio.h> #include <unistd.h> // fork() #include <stdlib.h> // exit() #include <inttypes.h> // intmax_t // // man 2 execve int main(int argc, char **argv) { pid_t pid; switch (pid = fork()) { case -1: perror("fork"); exit(EXIT_FAILURE); break; case 0: // child puts("inside child process\n"); char *prog = "/usr/bin/sleep"; char *newargv[] = { "/usr/bin/sleep", "10", NULL }; char *newenv[] = { NULL }; execve(prog, newargv, newenv); perror("execve"); _exit(EXIT_FAILURE); break; default: // parent printf("child pid: %jd\n", (intmax_t) pid); sleep(10); exit(EXIT_SUCCESS); break; } }