Process

It is a dynamic abstraction for executing a program (the info needed to describe a running program, so we can pause, switch and resume programs). Use ps to get process information

  • Memory context: Code, data, stack, heap
  • Hardware context: Registers, PC, SP, FP
  • OS context
    • PID: to uniquely identify processes
    • Process state: New, ready, running etc.

Process Table

  • Contains multiple Process Control Blocks (PCBs)
  • Each PCB stores information on one process (all the contexts above)

Unix Processes

Create new process

  • int fork()
    • Returns: PID of newly created process in parent process; 0 in child process
    • Behaviour: Creates a new child process
      • Child process is a duplicate of parent (memory & hardware context)
      • Memory in child is a copy of the parent
      • Child differs in: PID, parent PID (PPID), fork() return value
    • Implementation (simplified)
      • TRAP to kernel mode
      • Create address space of cchild
      • Allocate new PID of child p'
      • Create kernel process data structures, copy kernel environment of parent here
      • Initialise child process context: PID=p', PPID=parent id, CPU time=0
      • Copy memory from parent (very expensive, can be optimised)
        • Copy on write: only duplicate a memory location when it is written to by either parent or child, otherwise share same memory location
      • Acquire shared resources e.g. open files, current working directory
      • Initialise hardware context: copy registers etc from parent process
      • Child is ready to run, add it to scheduler queue
  • int execl(const char *path, const char *arg0, ... , const char *argN, NULL)
    • Returns: -1 if there was an error. Otherwise, process will be replaced and it won’t return anything
    • Behaviour: Replaces current executing process with a new one (context reset, go to main() of new program)
  • fork + exec allows us to create child processes that do different things
  • All processes have init process as an ancestor (nowadays systemd or other)
    • Created in kernel at boot time
    • Traditionally PID 1
    • Watches for other processes and respawns where needed
    • Uses fork() to create process tree, e.g. initloginbash

Terminate Process

  • void exit(int status);
  • Implicit exit: when main() returns, exit is implicitly called, return value is status
  • status is returned to the parent process, 0 means successful execution, not zero means problematic execution
  • This function does not return
  • Most system resources are released on exit. These are not released:
    • PID & status: to give to the parent
    • Process accounting e.g. cpu time
    • Process table entry may still be needed
    • The process is now a zombie process, info is retained in case parent calls wait()
  • When parent is terminated before child, it becomes an orphan
    • init becomes a “pseudo” parent of the child
    • Child termination sends signal to init, which then uses wait() to clean up child
  • When child terminates before parent, but parent does not call wait()
    • On older unix implementations, this may cause process table to fill up, needing reboot

Waiting for child

  • `int wait(int *status)
    • Returns: PID of terminated child process
    • Behaviour `
      • Blocks the parent process until at least one child terminates
      • Stores the exit status of the child process in *status. Can use NULL if exit status is not needed
      • Cleans up remaining child system resources (those not removed on exit), or removes zombie process
  • waitpid() waits for specific child process
  • waitid() waits for any child process to change status