CS 240 Lab 11: Processes

Peter Mawhorter

Processes

How can you close a program that’s stuck in an infinite loop?

.data
msg: .string "Hahaha!\n"

.text
.global main
main:
    sub $8, %rsp
    mov $msg, %rdi
    call printf
    add $8, %rsp
    jmp main

Definitions

  • Operating System: The software that controls the overall operation of a computer, providing services like memory allocation, job scheduling, and input/output control.
  • Kernel: Center of the operating system which manages things. Runs in privileged mode (can see all memory) and interacts directly with hardware. It can run programs, access files, allocate memory, and spawn processes.
  • Shell: A user-interface program for the kernel. Prints a prompt, reads input, and interprets input as a command, which it spawns a process to run.
  • Process: An instance of a program being run. Gives the program the illusion of full control over memory & CPU.

What is a Process?

A process keeps track of the context of a program, including:

  • Program’s code + data stored in memory (including stack + heap)
  • Register contents (including stack pointer and program counter)
  • Environment variables
  • Set of open file descriptors

At the kernel’s discretion, a context switch may happen: saves the current context, then loads a new context and starts running from there.

A process may also receive signals which change its status.

Signals

  • Signals are sent via the kernel, triggered by keyboard shortcuts and/or other processes.

    • In most cases the default behavior is to stop the program (e.g., SIGINT, SIGKILL, and yes, SIGSEGV).
    • Some signals suspend it (SIGTSTP)
  • A process can define a signal handler via the signal function to do something special (but this is tricky).

  • Wikipedia page on signals

Signal Handling

#include <stdio.h>  // printf
#include <time.h>   // sleep
#include <signal.h> // signal

int tried = 0;

void keepGoing(int signal) {
    tried = 1;
}

int main (void) {
    signal(SIGINT, keepGoing);
    while (1) {
        printf("Hahaha!\n");
        if (tried) {
            printf("You can't stop me!\n");
            sleep(0.25);
            tried = 0;
        }
    }
}

Multiprocess Programming

  • Any process can be switched out at any moment (but its context will be restored when it gets switched back in).
  • Kernel is in charge of which processes get to run when.
  • Can create “child” processes if we want to work in parallel:
    • fork creates a new process. Call it once and it returns twice: once to the parent (with the child PID) and once in a new child process (with 0 as the value).
    • exec replaces the running program by loading a new one from a file (gets fresh memory & registers).

Multiprocess Programming

  • Processes can communicate via files, signals, ports, etc.
    • Could also coordinate work up-front before starting a child.
  • Things can happen in any order: you don’t know who the kernel will pick next.
  • Threads offer a mechanism for multiple contexts to share some state; they’re even trickier to get right than processes.
  • Parallel programming is hard.
    • It’s also necessary to create programs that perform calculations while also responding to user input.

Multiprocess Programming

  • Each process has an ID, called a PID.
  • Parent & child processes can communicate:
    • getpid returns the current process’ ID.
    • getppid returns the parent process’ ID.
    • waitpid pauses this process until the target process finishes.
  • In the shell:
    • Use man (“manual”) to look at documentation, e.g.:
      man getpid
    • Use ps to see processes, or top for an interactive display.

Multiprocess Examples

#include <stdio.h>
#include <unistd.h>

int main() {
    int childPID = fork();
    int myPID = getpid();
    printf("P: %d C: %d\n", myPID, childPID);
    exit(0);
}
P: 27012 C: 27013
P: 27013 C: 0
P: 27296 C: 0
P: 27283 C: 27296
P: 35082 C: 35121
P: 35121 C: 0

Multiprocess Examples

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int main() {
    int pid = fork();
    if (pid == 0) {
        sleep(3);
        printf("\n\nSurprise!\n");
    }
    exit(0);
}

Multiprocess Examples

#include <stdio.h>
#include <unistd.h>

int main() {
    int i, myPID, childPID;
    myPID = getpid();
    for (i = 0; i < 2; ++i) {
        childPID = fork();
        if (childPID == 0) {
            printf("Hello child %d iter %d\n", myPID, i);
        } else {
            printf("Hello parent %d iter %d\n", myPID, i);
        }
    }
    exit(0);
}
Hello parent 29195 iter 0
Hello child 29196 iter 0
Hello parent 29196 iter 1
Hello child 29197 iter 1
Hello parent 29195 iter 1
Hello child 29198 iter 1
Hello parent 30035 iter 0
Hello child 30037 iter 1
Hello parent 30035 iter 1
Hello child 30036 iter 0
~/cs240/test > Hello child 30038 iter 1
Hello parent 30036 iter 1

A diagram showing how fork behaves in the ‘forkex1’ program. It shows 7 copies of the code, with one on top, two below that, and four below those two. The fork call is highlighted in each copy, and arrows show how the two middle copies are produced by the first fork call in the loop, while the four bottom copies are produced from the two middle copies by the second fork call in the loop. The bottom four copies have the printf line highlighted since they’re done with the loop and execute that next.