Process + Process API

CS439

The Process

What is a process? How does it get created? And how does your computer manage all of them? A process is a running program. The program itself is lifeless - the os "breathes" life into it. The beauty of the OS is that it gives the illusion of multiple CPUs. It does this through virtualization - essentially making it seem like there are more CPUs than one. The OS basically gives each program a tiny slice of CPU time then switches to the next incredibly fast. Policies: The program deciding which program is running next Machine state: When we are switching between programs, we need to keep state (memory, registers, stack pointers, io info, etc). A process runs with a state. The OS provides a set of interfaces (The Process API) to interact with these processes. Some common actions needed include
  • Create: First the os loads the program's code and any static data into memory. Then, it allocates more memory for anything else running (runtime stack + heap), also standard input/output (like error streams), and transfers control to the programs starting point (called name).
  • But alas it's not this simple, Unix systems have some interesting ways to approach creating processes. There's fork and exec.
  • fork: creates almost an exact copy of the process that calls it (parent/child setup). However, the child doesn't start running from the beginning from main. It starts after the fork call returns (as if it called it itself). It's kinda trippy. Code runs, hits fork - now it thinks there are two processes that both "hit" fork. To tell them apart "fork" returns differently for the parent and the child. The child gives back a return code of 0. Parent gives back the PID of the child. Allows the parent/child to do different things
  • Output isn't deterministic - parent or child could run first post fork based on the cpu scheduler (kinda tricky - what if order matters?)
  • If the order does matter... a parent can make sure its child finishes with the wait system
  • exec: A family of system calls. IT DOES NOT CREATE A NEW PROCESS. It changes the current process running. Essentially overwrites the memory space of the running program, and restarts from the new programs main.
  • A successful call to exec never returns. Why? Because the program that called it doesn't exist anymore, it gets replaced.
  • So fork makes a copy and exec replaces programs -> But why design it this way? It turns out this separation is essential. fork creates a child from a parent THEN calls exec to run a new process. That small window between the fork and exec commands gives us room for incredibly powerful features.
  • Other commands

    How does the OS actually "keep control" -> Limited direct execution

    The OS wants your programs instructions to run directly on the hardware when possible (it's the fastest way). BUT the OS must maintain control and switch between processes.

    Restricted operations

    Relies heavily on hardware. Most modern CPUs have different modes. At a minimum - a user mode and a kernal mode. In user mode, some things are restricted. If a program in user mode attempts a disallowed action, the CPU detects it and throws an exception. The OS could then possibly terminate the process. But programs need ways to read files which involves the hardrive -> they ask the os -> system call (trap instruction) -> restricted instructions Two things happen during a trap: 1) control jumps from the user programs code to a predefined location in the os kernel. 2) Processor switches from user mode to kernel mode. (When doing this it saves previous states/information to return to later). Once in kernel mode, the OS code examines what the user code wants. Then, it performs some checks and performs the priv. operations. When done, it runs a return_from_trap function, which basically reverses the process taken to get to kernel mode (restores state, switches back to user mode, etc) The user program doesn't specify a memory address for a trap. There's a trap table already with all the possible exceptions/traps. When a trap occurs, the hardware looks up the cause of the trap in the error. The user can only request specific services. The OS "baby-proofs" the system.

    Switching processes

    How does the os regain control if a process really never makes a system call (esp if its doing something like infinite looping). A classic problem. The solution fundementally changed how OSs were structured. Originally, the OS trusted processes to eventually call a sys call (typically w a yield call or smthn). But what if it didn't or just never yielded. In this case, the only case to regain contol would be to reboot the machine.
    That's why today most modern OSs follow a "non-cooperative" approach. There's a timer that consistently interrupts processes. The timer raises an interrupt signal (which works like a trap). The current process is halted and control is forced back to the OS. This works even if the process was in an infinite loop! If the OS decides to switch in the moment to switch, it (as mentioned earlier) saves state (often in a data structed called a contol block pcp), loads the prev saved state of the second process, and then execution resumes w process B. This saving and restoring is the core of CPU virtualization (and it works incredibly fast today)

    Revisiting other sys calls

    What about kill/destory? Kill is the primary way to send signals to processes. Think of signals as a sort of software interrupt - a way to notify processes that something happens. Like when you do ^C in your terminal, you send a keyboard interrupt signal to the process running. Processes can install signal handlers - or code that runs automatically when it receives a certain signal (you could do things like save state before pausing w this possible). Sigkill can't be caught or ignored. Generally, you can only sigkill processes running as the same user (the OS enforces this). This is typically true unless you are the superuser (root user) which can stop processes for any user. Operating as root - another great power, great responsibility moment.

    Some cool command line tools to use to check out process info

    Some extra info

    Not everybody thinks fork/exec is the ideal design (check out the paper "a fork in the road"). There are a few issues when working with multi-threaded systems and complex data structures. There are tradeoffs, it's not perfect, but today this is the way almost all OSs are designed. But who knows? This is why we learn - so we can dare to imagine new, better systems.