UP | HOME

Process Creation
Processes
COP-3402

Table of Contents

UNIX process creation

celldivision_small.jpeg

  1. Duplicate an existing process with fork()
  2. 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;
  }
}

Author: Paul Gazzillo

Created: 2025-02-10 Mon 11:22

Validate