Skip to main content
Operating Systems

Operating Systems: Services, Interfaces, and Structures

Published: 2026-08-15
Level: postgraduate
Audience: Postgraduate students in Operating Systems

Prerequisite Knowledge

This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.

Previously Covered in This Subject

  • What an operating system is - covered in Lecture 1
  • System calls and the device status table - covered in Lecture 1
  • Dual-mode operation: user mode and kernel mode - covered in Lecture 1
  • The bootstrap program and the kernel - covered in Lecture 1
  • Protection and security - covered in Lecture 1

2.1 What Is an Operating System

2.1.1 What an Operating System Does

Every course on operating systems starts with the same three questions. What is an operating system — the master program that controls the whole computer? What are the components of the system? And what are the various responsibilities of the operating system?

Hook: A computer without an operating system is like a building with no manager — rooms exist, lights work, but nobody decides who gets which room, when, and for how long. The operating system is that manager, and this section explains exactly what it manages.

The main answer is that the operating system is a resource allocator — the thing that decides who gets what. A computer system has many resources that may be needed to solve a problem: CPU time, memory space, file-storage space, I/O devices, and so on. Facing many and possibly conflicting requests for these resources, the operating system must decide how to allocate them to specific programs and users so that the computer runs efficiently and fairly.

Apart from allocation, the operating system manages the memory, it manages processes, it handles free space management, and it takes care of many more things:

  • Memory management — deciding which part of memory each running program occupies, and keeping programs from trampling over one another.
  • Process management — creating, scheduling, and ending the programs in execution.
  • Free space management — tracking which areas of the disk are free and which are occupied, so new files can be placed somewhere sensible.
  • Device management — coordinating the use of every device attached to the machine.

Think about the hardware for a moment. All the devices connected to a system need the support of the operating system for smooth coordination with the rest of the machine. That includes the disk, the keyboard, the display, everything. In that sense, the system is the hardware, and the operating system acts as its manager. Every device that is attached to the system has to go through the operating system, which decides when and how the device is used.

Formalize: The operating system sits between the bare hardware and the application programs. Two classic views capture its role:

  • Resource allocator view: the operating system is a manager that receives many, possibly conflicting, requests (for CPU time, memory, file storage, I/O devices) and hands each one out so the system operates efficiently and fairly.
  • Control program view: the operating system is a control program that manages the execution of user programs to prevent errors and improper use of the computer, and it is especially concerned with the operation and control of I/O devices.

In both views the operating system is the one program that runs at all times on the computer — the kernel — surrounded by system programs (associated with the operating system but not part of the kernel) and application programs (everything else).

Assumption & Scope: The resource-allocator picture assumes a multiprogrammed environment — several programs or users present at the same time, all competing for the same hardware. On a single-tasking device with one program and one user, allocation is trivial and the operating system is instead designed mostly for ease of use, with little attention paid to resource utilization. Where the system is a shared mainframe, allocation dominates every design decision.

Visual intuition: Picture a vertical stack. At the bottom is the hardware — the CPU, memory, disk, keyboard, display. In the middle is the operating system, drawn as a full-width band because every device and every program must cross it. At the top sit the application programs and users. Requests travel downward through the operating system to the hardware; results travel back up. The landmark of this picture is the middle band: nothing passes between top and bottom without its permission — that is the whole point of the manager.

Pitfalls:

  • Confusing "the system" with the operating system. In this lecture, "the system" usually means the hardware plus the operating system working together; the OS is the software manager inside it.
  • Thinking the OS only allocates CPU. Memory, disk space, devices, and even file permissions are all resources that must be allocated or mediated.
  • Assuming the OS is part of the hardware because it "comes with" the machine. It is software — a very privileged program, but a program.

Recap + Bridge: The operating system is the master program that manages the computer's resources and coordinates every device, deciding who gets what, when, and how. The natural next question is: what services does this manager actually provide? That is exactly the road this session follows next.

2.1.2 The Roadmap of This Session

This session walks a single path through the subject. First come the services the operating system provides, both to users and to the system itself. Then we look at the interface between the user and the operating system, and at system calls — the low-level functions through which programs ask the operating system for work. After that come the types of system calls, and then the system programs that ship with an operating system. Next we consider how an operating system is designed and implemented. That leads to the overall structures of operating systems — the different ways the pieces can be organized — and the session concludes with debugging and failure analysis.

The path in brief:

  1. Services — what the OS does for users (2.2) and for the smooth running of the system itself (2.3).
  2. The overall view — how a user's request flows from interface to kernel to hardware and back (2.4).
  3. Interfaces in practice — command line, GUI, touch, and voice (2.5).
  4. System calls and the API — how programs ask the OS for work, with a fully worked file-copying example (2.6).
  5. System programs — the utilities shipped with the OS (2.7).
  6. Design and implementation — goals, policy versus mechanism, and implementation languages (2.8).
  7. Structures — simple, layered, microkernel, modular, hybrid, and mobile arrangements (2.9).
  8. Debugging and failure analysis — finding and fixing errors when things go wrong (2.10), and portability and booting (2.11).

The first few sessions stay mostly theoretical. Once processes get involved — from about the fourth or fifth session onward — many real problems appear, and things get more interesting. So the foundation being built now matters later.

Why the order matters: the session builds one idea on the next. Services tell you what the OS offers; interfaces and system calls tell you how you reach that offer; design and structure tell you how the offer is organized inside; debugging tells you what to do when the offer fails. If the services feel abstract now, the later sessions on processes, scheduling, and memory will keep returning to them — the basic picture built here will be built upon, not replaced.

Real-world & domain connection: Every system you touch runs one of these designs. A Windows laptop, an Ubuntu workstation on WSL, an iPhone, and an Android phone all provide the same class of services — program execution, I/O, file management, communication, error detection — through different structures. When you later debug a slow server or a crashing app, you are using the very debugging and failure-analysis tools (2.10) this roadmap ends with. The roadmap is not a tour of trivia; it is the map of every operating systems course, and it frames how professionals reason about real systems when things go wrong.

2.2 Operating System Services: The User-Facing Set

The operating system provides an environment where programs can execute, and where one program can get the services of another program. The services it offers to users fall into six groups.

Hook: Think of everything you did on a computer today: opened an app, typed into a file, saved your work, printed something, got an error dialog. Every one of those actions is one of six user-facing services the operating system performs for you — this section names all six and explains what each one actually does behind the scenes.

The six user-facing services are: user interface, program execution, I/O operations, file system implementation, communication, and error detection.

2.2.1 User Interface

Almost every operating system you have seen has a user interface — the part of the system you actually interact with. Windows is the very obvious example; Unix systems such as Ubuntu also have one, with a desktop. You can click on things to get information, or you can go to the terminal, type something, and get the information back.

The interface differs in form:

  • A command-line interface (CLI), where you type commands and get the output. The program that accepts those typed commands is a command interpreter (the shell), discussed in depth in section 2.5.
  • A GUI — a graphical user interface — where you click and get the output. The GUI is a window-and-menu system driven by a mouse or other pointing device, built on a desktop metaphor.
  • Batch processing, where more than one process runs either in the background or in the foreground without you interacting with each one individually. Commands and their control directives are written into files, and the files are executed in sequence by the system.

Some systems provide two or even all three of these variations at once — Windows has a GUI plus a command prompt, and Ubuntu offers a desktop plus a terminal.

2.2.2 Program Execution

The operating system must let you load a program into memory and run it. When the program runs normally, everything proceeds on its own. When something goes wrong — abnormal termination, an error inside the program — the error has to be indicated in some way. Usually it is indicated by interrupting the services the operating system is providing. At that point you either kill the application that is running or suspend that particular process. The exact mechanisms for doing all of this are studied later.

Formalize: Program execution is the service that loads a program into memory, starts it, and lets it run to completion. The system must also handle both ways a program can end:

  • Normal end — the program finishes its work and exits on its own.
  • Abnormal end — the program hits an error (a divide by zero, an illegal memory access, an uncaught exception) and must be stopped; the error is reported to the user or to the invoking program.

Behind the scenes, the loading work is done by the loader (see 2.7), which places the program into memory at a suitable location and hands control to its first instruction. When the program ends, the operating system reclaims the memory and other resources the program held so the next program can use them.

2.2.3 I/O Operations

Every program that runs requires I/O — input/output. The input or output can come in the form of a file: the program needs to open the file, read information from it, and write information back to it. Or the I/O can involve any external device connected to the system — a keyboard, a mouse, or a printer as an output device. Any one of these devices is required to perform the input/output operation, and providing these I/O services is one of the operating system's responsibilities.

Why can't the program talk to the printer directly? For efficiency and protection, users usually cannot control I/O devices directly — a program that writes directly to the disk could destroy files belonging to other users, and a program that grabs the printer could lock out everyone else. So the operating system provides a controlled means to do I/O: the program requests the operation through a system call, and the operating system performs it on the device.

Worked example — the same I/O shape, three devices: Consider three different I/O operations and see the common pattern underneath:

  1. File: a text editor opens notes.txt, reads the first 512 bytes into memory so you can see them, and writes your edits back.
  2. Keyboard: the same editor waits for your keystrokes; each keypress is delivered to the program as input.
  3. Printer: when you press Ctrl+P, the editor sends the document to the printer as output.

In all three cases the pattern is identical — open → read/write → close — and in all three cases the operating system, not the program, is the one that actually touches the device. That is why you never address a printer's hardware ports from a normal program: the OS does it for you.

2.2.4 File System Implementation

The file system is how files are stored and organized, in the form of directories. With it, many files can be created, deleted, or searched for; you can list what files are available, and you can manage the various permissions on them. Some files cannot be accessed by everyone — only the administrator can access them. That permission management is performed by each and every operating system.

The file system service so covers four things:

  1. Create and delete files and directories by name.
  2. Read and write the contents of files.
  3. Search and list — find a given file, or list the files and their information in a directory.
  4. Permission management — allow or deny access to files and directories based on ownership, so that, for example, only the administrator can read a system configuration file.

2.2.5 Communication

The operating system supports process-to-process communication. Any number of processes can exchange information on the same system, or between systems if they are connected in a network. If they are on a network, the information may have to be broadcast. Three general mechanisms exist: we can send a signal, we can use shared memory, or we can use message passing.

  • Signal — a small, one-way notification sent to a process (for example, telling it that an event happened or to stop).
  • Shared memory — a region of memory that two or more processes agree to share; each process reads and writes that region directly. Shared memory can be accessed by any number of processes, though there are restrictions that are dealt with later. Because the data is read and written at memory speeds, this is the fastest mechanism, but the processes themselves are responsible for not writing to the same location at the same time.
  • Message passing — the message, in the form of a packet, is sent from one system to another system, with the operating system moving the packet between the two processes. This is safer and easier to implement across a network, but slower for large amounts of data, because every exchange passes through the operating system.

Broadcasting information can also be done by way of a signal or message passing. All of this is studied in detail later, in the sessions on processes and inter-process communication.

Mechanism Speed Ease across a network Coordination needed by processes
Signal Very fast (tiny notification) Yes, but limited payload None — one-way notification
Shared memory Fastest (memory speed) Hard (different machines have no common memory) High — processes must avoid writing the same spot
Message passing Slower (goes through the OS) Easy — packets travel over the network Low — the OS mediates every exchange

When to pick which: use signals for tiny one-way events, shared memory for high-volume data exchange between processes on the same machine, and message passing whenever the processes live on different machines or when the data volumes are small.

2.2.6 Error Detection

Error detection means the operating system constantly keeps track of the errors that may possibly occur. The error can occur in the CPU, or in the hardware — in the memory of the hardware — or in an I/O device. Whatever error occurs, the operating system has to take appropriate action for the smooth functioning of the system. This error detection facility should act as a debugging facility, because it enhances both the user's ability and the programmer's ability to use the system efficiently. Since the operating system provides all these services, this facility should be present in each and every operating system.

Errors come from three places:

  • CPU and memory hardware — for example, a memory error, an illegal memory address access, or a power failure.
  • I/O devices — for example, a printer running out of paper, a network connection failing, or a disk error.
  • User programs — for example, an arithmetic overflow, a divide by zero, or a program using too much CPU time.

For each type of error, the operating system takes appropriate action so the computation stays correct and consistent. That action may be to report the error to the user, to end the offending program, to retry the operation, or to record the event in a log for later analysis — the topic of debugging and failure analysis in section 2.10.

Pitfalls:

  • Believing that error detection means the OS catches errors before they happen. It does not — it constantly watches for errors that may occur, and reacts with appropriate action when they do.
  • Thinking the user interface is the same thing as the operating system. The GUI and the shell are just entry points to the services; the services themselves (execution, I/O, files, communication, error detection) exist underneath no matter which interface you use.
  • Assuming every OS offers the same six services in the same form. The classes of services are common, but the specifics differ from system to system — Windows, Unix, and mobile systems implement each service differently.

Recap + Bridge: The operating system provides six user-facing services — user interface, program execution, I/O operations, file system implementation, communication, and error detection — each performed on behalf of the user or their programs. But there is a second set of functions that exists not for the user directly but for the smooth operation of the system itself: resource allocation, accounting, and protection and security. That set is the next topic.

Real-world & domain connection: These six services are what make ordinary computing possible. When a browser downloads a file, it is using program execution, I/O, the file system, and communication all at once — and if the network drops mid-download, error detection is what triggers the "download failed" message. The same six services appear in every operating system you will ever touch, from Windows desktops to Android phones to the embedded systems in cars and routers, which is why every operating-systems course teaches this list first.

2.3 Operating System Services: Running the System

A second set of functions exists for the smooth operation of the system itself: resource allocation, accounting, and protection and security.

Hook: The user-facing services from section 2.2 make the machine usable. But who makes sure the machine keeps working fairly when many programs run at once? Who stops one program from hogging the CPU, who records which user consumed what, and who keeps outsiders out? Three system-oriented services answer these questions.

These three functions are not for any single user's convenience — they exist to keep the whole system healthy, fair, and safe when multiple users and processes share it.

2.3.1 Resource Allocation

Resource allocation was introduced in the previous session, and is covered in detail in the coming sessions. The problem is easy to state. Suppose there are three processes, P1, P2, and P3. All three are in need of a particular resource. The resource can be a variable, or it can be a record, or it can be a file — anything. All three processes are competing for this one resource. The operating system has to decide how the resource can be efficiently allocated among the three, or among any number of processes. That is what resource allocation means.

Worked example — three processes, one resource: Suppose P1, P2, and P3 all need the same file, data.txt, at roughly the same time.

  1. The request stage: P1 asks to open data.txt for writing; P2 asks to read it; P3 asks to append to it. The operating system now holds three competing requests for one resource.
  2. The decision stage: the operating system cannot give all three the file at once in a conflicting way, so it must choose an order and a mode. A reasonable allocation: P1 gets the file first in write mode, P2 gets it next in read mode, and P3 gets it last in append mode.
  3. The grant stage: P1 finishes writing, the OS releases the file, and grants it to P2; when P2 finishes reading, the OS passes it to P3.
  4. The sense-check: at every instant, at most one process writes, so the file contents are never corrupted by simultaneous conflicting access. That is exactly the outcome the allocator is designed to produce.

This single-resource picture scales up: CPU cycles, main memory, and file storage each get their own special allocation code, while devices such as printers and USB drives are allocated through more general request-and-release code.

2.3.2 Accounting

Accounting means the operating system keeps track of how many users there are and what kind of resources they are using. If one user is consuming far more CPU time or memory than the others, the accounting records show it. These records are useful both for billing and for spotting problems.

Formalize: Accounting answers three questions: who is using the system, which resources they use, and how much of each. The records it keeps serve two purposes:

  • Billing — on shared or commercial systems, users are charged for the resources they consumed, the same way a phone bill charges for minutes used.
  • Usage statistics — administrators and researchers read the records to find heavy users, detect misbehavior, and decide how to reconfigure the system so the service improves. If the accounting shows one user consuming most of the CPU, the administrator knows whom to talk to or what to throttle.

2.3.3 Protection and Security

Protection and security form one of the services, and both are needed because we work in a multi-user, multitasking environment where people may be on a network. The other processes should be protected, and other processes should not interfere with each other. When any number of processes run at the same time — concurrent processes — each should not interfere with the resources the others are accessing. They should be able to access a particular resource without any conflict; that is the protection part. The security part says that outsiders cannot access the system as such. Proper authentication should be there, so that the system is defended from external I/O devices and from that kind of invalid access.

Intuition + Analogy: Think of a shared office. Protection is the rule that your desk and files stay yours — a colleague cannot reach into your drawer and take your documents, and the office has locks on individual cabinets so simultaneous work does not collide. Security is the building's outer gate: strangers from outside cannot walk in at all. In computing terms, protection controls what insiders (processes already running on the system) may touch; security controls whether outsiders (people, devices, or machines on the network) can get in. Authentication — usually a password — is the gatekeeper that checks identities before access is granted.

Scope: Protection and security are system-wide concerns: a chain is only as strong as its weakest link. If one process can bypass the protection checks, or one network port is left open, the whole system is at risk. The mechanisms themselves — how permissions are enforced, how authentication works, how access attempts are recorded — are studied in depth in the sessions on protection and security. This session only establishes why the service exists.

Real-world: in this respect, UNIX is more secure when compared to Windows. That judgment comes from hands-on experience with those two systems. You can think through these services for any other operating system in the same way.

Pitfalls:

  • Treating protection and security as the same thing. Protection is internal — keeping concurrent processes from interfering with one another's resources; security is external — keeping outsiders from gaining access. They are one service with two halves.
  • Thinking authentication is the whole of security. Authentication checks who you are; protection then decides what you are allowed to do with the resources. Both are needed.
  • Believing resource allocation is only about CPU time. Any resource — a variable, a record, a file, a printer — can be contended for and must be allocated, as the P1/P2/P3 example shows.

Recap + Bridge: Beyond the six user-facing services, the operating system runs the machine itself through three services: resource allocation (who gets the contested resource), accounting (who used what), and protection and security (insiders cannot interfere; outsiders cannot get in). With both service sets in hand, the next question is how the whole interaction actually works — how a user's request travels from an interface down to the hardware and back.

Exam note: Resource allocation is foundational and is covered in detail in the coming sessions — the basic picture built here (competing processes, one resource, an allocator that decides) will be the foundation for scheduling and deadlock topics later, so make sure it is clear now rather than memorized.

Real-world & domain connection: These three services run silently on every shared machine you have used. A university lab server allocates CPU among hundreds of student processes, its accounting records decide who to charge or throttle, and its authentication system (login + password) is the security gate. Cloud providers such as AWS and Azure operate on exactly this trio at industrial scale: allocation decides how many virtual CPUs a customer's instance receives, accounting produces the usage bill, and protection and security isolate one customer's processes from another's.

2.4 The Overall View: User, System Calls, and Hardware

2.4.1 The Flow from User to Hardware

Here is the overall view of how the whole interaction takes place between the hardware and the user. It happens in terms of three things: the user interface, system calls, and services.

Hook: You click an icon or type a command, and a fraction of a second later a file opens, a program runs, or a page prints. Something must have carried your request from the screen down into the machine and brought the result back. That journey — user interface → system call → kernel mode → hardware → back — is one single loop, and this section traces it end to end.

When a user runs a particular program — it can be any system program or application program — everything has to go through one of these interfaces. Going through the interface causes a system call to be made. The system call can be I/O-related, it can be file-related, or it can be a resource-oriented system call. One of the system calls is then activated.

When a system call is made, a call is made to the operating system. Automatically the system goes to kernel mode — the privileged mode of the CPU where the operating system itself runs. It starts executing that particular file or program, and in turn it interacts with the hardware, sends the request, and gets the response back to the user. That is the complete loop.

Formalize: The complete loop has five stages:

  1. User action — the user starts a system program or application program through some interface (GUI click, typed command, or batch job).
  2. Interface dispatch — the interface translates the action into a system call: an I/O-related call (read from a device), a file-related call (open, read, write a file), or a resource-oriented call (ask for memory, for a device, for time).
  3. Mode switch — the system call hands control to the operating system, and the CPU switches from user mode (where ordinary programs run) to kernel mode (the privileged mode where the operating system itself runs). Kernel mode is the only mode in which the OS may execute privileged instructions — those that access the hardware directly.
  4. Kernel work — the operating system executes the requested operation: it interacts with the hardware, sends the request to the device or memory, and collects the response.
  5. Return — the result travels back out of kernel mode to the user, who sees the output of the action.

The reason for the mode switch is protection: if ordinary programs could execute privileged instructions directly, a single buggy program could corrupt the whole machine. By forcing every request through the kernel, the operating system keeps control of the hardware.

Visual intuition: Picture a vertical pipeline with four lanes, drawn top to bottom: user interfacesystem callkernelhardware. The request is a marble dropped at the top. It rolls through the interface lane, enters the system-call lane where the mode switches from user to kernel (mark this point on the drawing — it is the only place where the marble changes lanes from user world to kernel world), then rolls through the kernel lane where the OS executes it against the hardware, and the result returns up the same path. The one-sentence takeaway: every user action is a round trip through the kernel.

2.4.2 Interfaces and System Call Types

So the user interface — whether GUI, batch, or command line — always funnels into system calls. The services are what the operating system provides through those calls, and every one of the services seen earlier is delivered this way. The details of the system calls themselves are the next topic.

Recap + Bridge: The user reaches the hardware through exactly one funnel: interface → system call → kernel mode → hardware → back. Every service from sections 2.2 and 2.3 is delivered through this funnel. The funnel's narrowest point — the system call — is so central that the next two topics examine it in detail: first how the command-line and graphical interfaces look in practice (2.5), then the anatomy of system calls themselves, with a fully worked file-copying example (2.6).

Real-world & domain connection: When you press Ctrl+S to save a document, the editor's interface issues a file-related system call (write), the CPU switches to kernel mode, the kernel writes your file to disk, and control returns — all within milliseconds. When a security tool on your machine monitors which programs access the network, it is watching this exact funnel: every network action by any program must pass through the kernel in kernel mode, which is why the OS is the natural chokepoint for enforcing permissions. Understanding this single loop is the key to later topics such as process scheduling, virtual memory, and security, which all live inside the kernel lane of the diagram.

2.5 User Interfaces in Practice

2.5.1 The Command-Line Interface

A live demonstration shows the command-line interface in action. The demo system is WSL — the Windows Subsystem for Linux. Windows provides it so that you can install and run Ubuntu inside Windows without occupying much of the space, and without using a full virtual machine like VMware. With WSL you can directly run Linux commands and any type of Linux program.

In this interface you type commands in a terminal. The place where you type the information or the command is called the shell, and the shell is a command interpreter. The prompt is the symbol that signals the shell is ready, and after the prompt you type the command. The shell understands the command and sends the request to the kernel — the heart of the operating system. The kernel sends the information to the hardware, gets the response back from the hardware, and passes it back to the shell, where you see the output. This is how the whole chain works: command, shell, kernel, hardware, and back.

Formalize: The command-line interface is built from four components that pass work down the chain and results back up:

  1. Terminal — the window or device where you type.
  2. Prompt — the symbol (for example a dollar sign or a percent sign) that tells you the shell is ready for the next command.
  3. Shell — the command interpreter: it reads your typed command, understands it, and either executes it itself or finds the program that implements it and asks the kernel to run that program. On Windows XP and UNIX the shell is a separate program, not part of the kernel; many different shells exist on UNIX systems (Bourne, C, Korn, Bash), and a user chooses among them by preference.
  4. Kernel — the heart of the operating system. It receives the request from the shell, interacts with the hardware (reading from disk, writing to the display, and so on), gets the response, and passes it back up through the shell to your terminal.

So the full round trip is: command → shell → kernel → hardware → kernel → shell → output.

There are two ways a command interpreter can execute a command. In one approach the interpreter itself contains the code for each command. In the other — the approach UNIX uses — the interpreter merely identifies the file that implements the command (for example, the command to delete a file finds a program called rm) and loads that file into memory and runs it. This second approach keeps the shell small, and lets programmers add new commands simply by adding new files with the proper names.

Real-world example: On WSL, typing ls at the prompt shows the files in the current directory; typing date shows the current date and time. Each command name identifies a small program that the shell loads and the kernel runs — you can watch the whole command → shell → kernel → hardware chain happen live, with output returning to your terminal.

2.5.2 The Shell and Its History

The shell shown in the first demo is the default shell found on Ubuntu. That shell is the Bourne shell — more precisely Bash, the Bourne Again Shell, so named because Bourne is the author who created the original Bourne shell. The second example prompt in the demo was captured on a Mac, which you can recognize from the prompt itself; the same kinds of commands work there.

Intuition + Analogy: The shell is like a restaurant waiter. You (the diner) tell the waiter what you want; the waiter does not cook anything themselves, they take the order to the kitchen (the kernel), and the kitchen's output is brought back to your table. Naming details: the original Bourne shell was written by Stephen Bourne; Bash — the Bourne Again Shell — is its modern reimplementation, the default shell on Ubuntu and most Linux distributions. Because the shell is a program and not part of the kernel, users can replace it: C shell, Korn shell, and many third-party shells all speak to the same kernel.

2.5.3 The Graphical User Interface

Most of you already know the GUI. It is a very user-friendly desktop metaphor interface: you have a mouse, a keyboard, and a monitor, and you have icons. The icons represent either a program, or a file, or any type of action that can be performed; you just click an icon. The GUI was originally invented at Xerox, and now many versions exist: Microsoft Windows, and Apple's Mac OS with its Aqua interface. UNIX and Linux have both a command-line interface and a GUI. Windows is the most widely used operating system — roughly 64% of the usage — then come the Unix-family systems, then Mac.

Formalize: The graphical user interface (GUI) replaces typed commands with a desktop metaphor: the screen is a desktop, icons represent programs, files, and directories (folders), and a mouse (or other pointing device) moves a pointer over the icons. Clicking an icon invokes the program it represents; menus pull down lists of commands. Because both the GUI and the shell ultimately issue the same kind of requests to the kernel, the user interface is substantially removed from the actual system structure — the GUI is a convenience layer on top of the operating system, not a part of it.

History in one line: the GUI's ideas came from research at Xerox PARC in the early 1970s (the Xerox Alto, 1973); Apple's Macintosh spread them in the 1980s; Microsoft's first Windows added a GUI over MS-DOS; Mac OS X adopted the Aqua interface; UNIX and Linux offer desktop environments such as KDE and GNOME alongside the command line.

Interface Interaction Best suited to Examples
Command line (CLI) Type text commands Scripting, remote servers, automation, power users Ubuntu terminal, Windows Command Prompt, PowerShell
GUI Click icons and menus with a pointer Everyday interactive use on desktops and laptops Windows, Mac OS X (Aqua), GNOME, KDE
Batch Commands written into files, executed without interaction Scheduled or repetitive jobs Batch files, cron jobs, JCL batch systems

2.5.4 Touch and Voice Interfaces

A touch screen interface exists on some devices, and some laptops also have that facility: you directly touch the screen and click instead of using a mouse, or you click directly on the icon to open the file or app. Voice-based commands are also possible — nowadays even some display-based devices have assistants like Alexa, where you talk and get the information. These interfaces matter in specific situations: when there is no possibility of a mouse, or when the mouse is not required. That happens when the selection or the action has to be done based on a gesture, when there is only a virtual keyboard for entering text, or when you have a voice-based commanding system. Otherwise they are not required.

Scope: Touch and voice interfaces are situational — they exist for the cases where a mouse is impossible or unnecessary: gesture-based selection, a virtual (on-screen) keyboard instead of a physical one, and voice-controlled commanding (smart speakers such as Alexa, or assistants on phones). When a mouse and keyboard are present and comfortable, these interfaces add nothing. They are interfaces to the same operating system, not different operating systems.

Pitfalls:

  • Calling the shell "the command line" and nothing else. The command line is the interaction style; the shell is the specific program (interpreter) that reads your commands — the two are different layers of the same chain.
  • Believing the GUI is the operating system. The GUI is a program running on top of the OS; the same machine can expose a GUI, a CLI, or both, all funneling into the same system calls.
  • Thinking every OS has all interface types. Historically Mac OS provided only a GUI and required users to go through it; Mac OS X later added a command line. Interface availability is a design choice, not a law.
  • Assuming WSL is a full virtual machine. WSL runs Linux inside Windows without a separate virtual machine — it occupies little space and boots commands directly.

Real-world: the practical message is that one operating system can host all of these — click, type, touch, or speak. The choice of interface depends on the device.

Recap + Bridge: The command line works through the chain command → shell → kernel → hardware → back, with the shell (Bash on Ubuntu) acting as command interpreter and the kernel as the heart of the system; the GUI, touch, and voice interfaces are alternative front ends funneling into the same kernel. Whichever interface you use, the underlying request mechanism is the same: system calls. The next section opens that mechanism up — what a system call is, how the API hides it, and how parameters are passed.

Real-world & domain connection: Every interface style above is in daily use in industry. System administrators manage cloud servers almost entirely over SSH command lines (because servers have no screen); desktop users interact through GUIs; warehouses and hospitals use touch screens where gloves or space make mice impractical; and voice assistants such as Alexa sit in millions of homes. All of them — from an AWS server console to a smart speaker — end at the same place: the kernel of the operating system underneath.

2.6 System Calls and the API

2.6.1 The API

A system call is the service provided by the operating system to running programs. The API — the application programming interface — is the programming interface through which programs reach it. The API is written in a higher-level language; it can be any higher-level language, such as C or C++. If you have an application, you can embed system calls using the API rather than calling the system calls directly. Very common examples of APIs are the Win32 API for Windows and the POSIX API for POSIX-based systems. POSIX is present in all Unix, Linux, and Mac OS X systems. The Java API for the JVM is another example. Through these APIs you can use the system.

Hook: You have probably used printf, open, or read in C without ever thinking about where those functions end up. The answer: they end up inside the operating system. The API is the menu, the system call is the kitchen, and this section shows how the two connect.

Formalize: A system call is the service provided by the operating system to running programs — the way a program requests work from the OS. The application programming interface (API) is the higher-level programming interface through which programs reach the system calls. The API is written in a high-level language such as C or C++, and specifies, for each function, the parameters to pass and the return values to expect.

Why program to an API instead of calling system calls directly?

  • Portability: a program written against an API can compile and run on any system that supports the same API — a POSIX program compiles on Unix, Linux, and Mac OS X alike.
  • Simplicity: system calls can be detailed and awkward to work with; the API wraps them into convenient functions.
  • Hiding: the API hides implementation details — the caller need not know how the call is implemented, only what the OS will do as a result.

Behind the scenes, the API's functions invoke the actual system calls on the programmer's behalf. For example, the Win32 function ReadFile() (used to read from a file) actually calls the NtReadFile() system call in the Windows kernel, and the C library's printf() ends up calling the write() system call. The run-time support library (a set of functions included with the compiler) intercepts API calls and invokes the corresponding system calls. A number is associated with each system call, and the system-call interface keeps a table indexed by these numbers; the caller never needs to know the number or the implementation.

The three most common APIs are:

API Where it works Example function
Win32 API Windows systems ReadFile()NtReadFile()
POSIX API Unix, Linux, Mac OS X read() → the read system call
Java API Any system with a JVM Java's FileInputStream → native calls

2.6.2 What a System Call Is

Whenever you have to get some information, or perform some action, you have to make a system call. The system call takes the form of a function, just like a normal function. By seeing the name of the function, you know what type of action it is going to perform. The classic example shows a sequence of system calls that copies the contents of one file into another.

Formalize: A system call looks like an ordinary function call in C or C++: it has a name, parameters, and a return value. The name tells you the action — read() reads, write() writes, open() opens a file. The difference from a normal function call is what happens underneath: when the system call executes, execution passes to the operating system in kernel mode, which performs the requested action on the hardware and returns the result. The caller never sees the machine-level details — only the return value, which reports success or failure.

2.6.3 Worked Example: Copying a File with System Calls

The sequence of system calls for copying a file works like this:

  1. First, try to get the information from the input file — find out that the source file exists and is readable.
  2. Once the input is accepted, try to get the information about the destination file.
  3. Once both pieces of information are available, open the source file. If the file does not exist, come out — the program stops there.
  4. If the file exists, read the input file and write the contents into the destination file.
  5. This read-and-write loop continues until the end of the file is reached, or until the read phase completes.
  6. Close the output file and also the input file.
  7. Whatever has been written can be printed, if you want.
  8. The program ends.

Worked example — copying a file, call by call: Suppose you want to copy the file report.txt into backup.txt. The sequence of system calls is:

  1. get file information (source) — confirm report.txt exists and is readable.
  2. get file information (destination) — check backup.txt's status (it may already exist; the program may abort, ask the user, or delete and recreate it).
  3. open sourceopen("report.txt", READ). If the file does not exist, the call returns an error and the program stops.
  4. create/open destinationcreate("backup.txt") or open("backup.txt", WRITE).
  5. read-write loop — repeatedly read(source, buffer, n) then write(destination, buffer, n), each call returning status information (bytes transferred, or end-of-file, or a hardware error such as a disk failure).
  6. close bothclose(source) and close(destination).
  7. print a message — optional, e.g. "copy complete".
  8. exit — the final system call ends the program normally.

Sense-check: every step in the sequence maps to one of the file-management calls (open, read, write, close) plus the status/error checks around them — and the whole sequence is just an ordinary program's view of the service "copy a file." Even simple programs make heavy use of the OS; systems commonly execute thousands of system calls per second.

This is how the copying of information from one file to another happens in terms of system calls. And this is not the only thing a system call can do. The system call is a general tool, capable of performing whatever we do with the help of the command-line interface or with respect to the GUI. You can create a directory, you can change the permission of a file, and many more things besides opening, reading, and writing files. Most of the things you can do with the system can be done through system calls.

2.6.4 The read() System Call in Detail

Look at the read system call as a concrete example. In C programming, you have to include the general file unistd.h. read is the function name. What does it return? It returns some amount of bytes as the return value. You have to pass three parameters. First, the file descriptor of the file — a number the operating system uses to identify the open file. Second, the name of the buffer, where the data is to be placed. Third, the amount of data that you are going to copy.

Suppose the read system call succeeds and you are reading 30 bytes of data. Then 30 is the return value of this function. If there is any error, it returns −1. Each system call has its own function and its own return type; the return type varies from one system call to another. A number is associated with each and every system call, but you need not know that number, and you need not know how the call is implemented. The only thing you need to know is the work this particular system call performs; the rest of the implementation is hidden from the user. The calls are also supported by runtime libraries — hidden support libraries included by the compiler in order to implement the system calls.

Worked example — read() with real numbers: The signature of the read system call (POSIX) is:

The three parameters are:

  1. fd — the file descriptor, an integer the operating system assigns to the open file. Example: fd = 3 if the file was the third one opened by this program.
  2. buf — the buffer: a memory location where the read data will be placed.
  3. count — the amount of data requested, in bytes.

Case 1 — success: the file has at least 30 bytes remaining; read(3, buf, 30) copies 30 bytes into buf and returns 30. The return value equals the number of bytes actually read.

Case 2 — end of file: no more data; read returns 0, which tells the copy loop in 2.6.3 to stop.

Case 3 — error: the file descriptor is invalid or the device fails; read returns -1, and a global error code (errno) tells the program what went wrong.

Sense-check: the return value carries three distinct meanings — positive (bytes read), zero (end of file), negative (error) — which is exactly why the read-and-write loop in the copy example checks the return value after every call.

2.6.5 How a System Call Executes

The visual for this shows the relationship between the system call and the operating system. A user application, in user mode, tries to use a system call such as open(). As soon as this system call is given, the system call interface changes the environment from user mode to kernel mode. The system goes and finds where the implementation is, does its work, and returns. As soon as it returns, the environment goes back to user mode, and you get the output. That is the interface between the system call and the operating system.

Visual intuition: Draw a horizontal line across the middle of the page: user mode above, kernel mode below. The application runs above the line. When it calls open(), an arrow crosses the line downward — this crossing is the system-call interface, which switches the CPU from user mode to kernel mode. Below the line the OS locates the implementation of the call, performs the work, and the arrow returns upward, switching back to user mode. The one-sentence takeaway: every system call is a round trip across the user/kernel boundary, and the system-call interface is the gatekeeper on that boundary.

2.6.6 Parameter Passing

Some system calls need parameters passed to them, as we saw with read() and with creating a directory. Sometimes the parameters are simple enough to be placed in registers — the small, fast storage areas inside the CPU. If there are more parameters, or the parameter size is larger — in terms of a block, or a table, or an address to the block — then the parameters have to be pushed onto the stack, and later popped from the stack by the system. There is no limit on the length of the parameter list in terms of blocks or stack. Only in some cases will the registers be used, because the registers are limited: if the parameters are very simple in terms of size, we can use the registers. Parameter passing may also be done via a table. Whichever way it is passed, the operating system goes and gets the parameter — from the register, or from the table — and loads and executes it. The user does not execute it; the operating system does. The user only needs to give the right system call with the right parameters.

Formalize: Three general methods exist for passing parameters to the operating system:

  1. Registers — the simplest method: parameters are placed directly in CPU registers. Works when the parameter count and sizes are small, because the register file is limited.
  2. Block or table in memory — when there are more parameters than registers, the parameters are stored in a block (table) in memory, and the address of the block is passed in a register. This is the approach taken by Linux and Solaris. There is no limit on the number or length of parameters this way.
  3. Stack — the program pushes the parameters onto the stack, and the operating system pops them off. Like the block method, this does not limit the number or length of parameters.

In every method, the user's program only supplies the parameters; the operating system fetches them (from register, block, or stack), loads, and executes the call.

2.6.7 Categories of System Calls

The different types of system calls depend on what we are doing:

  • Process control. Create a process, terminate it, end, abort, load, execute, get the attributes of the process, set the attributes of the process, wait for a process, wait for a signal or an event, allocate or free memory. A debugger will also try to do single-step execution of the code.
  • File management. Create a file, delete a file, open, close, read, write, reposition (that is, seeking within the file), get file attributes, and set file attributes.
  • Device management. Request a device, release the device, read from the device, write to the device. All of this can be done with the help of system calls.
  • Information maintenance. Get the time or set the time and date, get the system data or set the system data, get or set the process, file, and device attributes.
  • Communication. Communication between processes happens by sending and receiving messages — there is a send system call and a receive system call. If you have studied network programming, you know that a socket has to be created between the two systems: the socket is the endpoint of the communication. An endpoint is created on one system, and another endpoint on the other system. The request is sent from one system to the other, and the response comes back. That is client-server communication; peer-to-peer communication also exists. All of this is used in client-server programming. If a shared memory has to be created, the system call attaches the memory and detaches it, and the operating system keeps track of the processes accessing the shared memory.
  • Protection. Controlling access to the resources — giving the permissions, setting the permissions, denying the user access, or allowing the access.

Formalize: System calls fall into six major categories. Each category answers one kind of request:

Category Sample calls What it lets a program do
Process control create, terminate, abort, load, execute, get/set attributes, wait, allocate/free memory Manage the program's own execution and other programs' executions
File management create, delete, open, close, read, write, reposition, get/set attributes Work with files and directories
Device management request, release, read, write Use I/O devices
Information maintenance get/set time and date, get/set system data, get/set attributes Exchange information between program and OS
Communication send, receive, create socket, attach/detach shared memory Exchange data between processes, on one machine or across a network
Protection set permission, get permission, allow user, deny user Control access to resources

Two communication models appear in the Communication category: the message-passing model (processes exchange messages; a connection is opened, messages are exchanged with read/write message calls, and the connection is closed — client-server and peer-to-peer both fit here) and the shared-memory model (processes create and attach a shared region of memory and read/write it directly). Message passing is easier across machines and avoids conflicts; shared memory is faster within one machine but requires the processes themselves to avoid writing the same location at the same time.

Exam note: the categories of system calls and their functions are core material, and they are studied in greater detail in later sessions.

Pitfalls:

  • Expecting a single "do everything" system call. Work is done through many small, specific calls (open, read, write, close, create, delete, seek), and every real task such as copying a file is a sequence of them.
  • Confusing the API function with the system call. The API function (like printf or CreateProcess) is what the programmer calls; the system call (like write or NTCreateProcess) is what runs in the kernel underneath.
  • Ignoring return values. The copy example works only because every read and write returns status — bytes read, end of file, or an error; a program that skips these checks cannot handle failures.
  • Remembering the read() return value wrongly: positive = bytes read, 0 = end of file, −1 = error. A common mistake is treating 0 as an error.

Recap + Bridge: A system call is the OS service offered to running programs, reached through an API (Win32, POSIX, Java), taking the form of a function with parameters (passed by registers, block, or stack) and a return value; calls group into six categories: process control, file management, device management, information maintenance, communication, and protection. System calls are the narrow funnel from section 2.4 made concrete. The next step up the ladder is the layer that wraps them for everyday use: the system programs that ship with the operating system.

Real-world & domain connection: These categories are what programmers use every day: fork/exec (process control) run every program you start; open/read/write (file management) power editors and databases; socket/send/recv (communication) carry every web request; chmod (protection) sets file permissions; time (information maintenance) stamps logs. If you want elaborate information about system calls, there is a book called Advanced Programming in the UNIX Environment, which covers them in depth — it is the standard reference that professional Unix and Linux developers keep on their desks.

2.7 System Programs

2.7.1 The Categories of System Programs

System programs are the programs that are already there in your system. They provide an environment for development and execution, and they divide into a few groups:

  • File manipulation. Text editors and word processors — a notepad, or in Microsoft terms a spreadsheet, a presentation, or a Word document.
  • Status information. The date and time, the amount of memory, the disk space, or any other information about the system, including logging and debugging information. Some systems implement a registry — a place used to store and retrieve configuration information — and these details are available through system programs.
  • Language support. Example: compiling. This is a system program. To run a program written in a particular programming language, you need a compatible compiler — one compatible with the architecture or the processor of your system. Only with a compatible compiler can you run the program. Not all operating systems will allow you to store or run the system program in terms of a compiler or assembler.
  • Program loading and execution. The loader, the relocatable loader, and linking loaders take care of getting a program into memory and running it.
  • Communication. Networking-related programs that provide virtual communication among processes, users, and systems.
  • Background services. After the desktop appears, you can see, on the bottom-right, the date being displayed — which means that particular service is running. Some things are automatically started at startup, because what has to be done after startup has already been programmed by a system program that starts running them.
  • Application programs. Applications such as a browser are installed in the system and started by the user; they are not a part of the operating system.

Hook: When you open a text editor, check the date, or compile a program, you are not calling the operating system directly — you are using system programs: the utilities that ship with the OS and create a usable environment for development and execution. This section sorts them into their categories and draws the line between a system program and an application program.

Formalize: System programs (also called system utilities) are the programs that come with the operating system and provide a convenient environment for program development and execution. Some are simple user interfaces to system calls; others are considerably more complex. The standard division into categories:

Category What it provides Examples
File manipulation Create, delete, copy, rename, print, list files and directories Text editors, word processors
Status information Date, time, memory amount, disk space, logging, debugging data, configuration registry date, registry viewers, top-style monitors
Language support Compilers, assemblers, interpreters, debuggers C compiler, assembler
Program loading and execution Load a compiled program into memory and start it Loader, relocatable loader, linking loader
Communication Virtual connections among processes, users, and systems Remote login, file transfer, email, web browsing tools
Background services Services started automatically at boot or at startup Startup services, the taskbar date display
Application programs Programs the user installs and starts; not part of the OS Browsers, office suites

Two clarifications matter. First, a compiler must be compatible with the architecture or processor of the system — a compiler built for one processor cannot produce runnable code for another, and not all operating systems allow a compiler or assembler to be stored and run as a system program. Second, background services are started automatically at startup, because what has to happen after boot has already been programmed into a system program that starts them — the date you see in the corner of the desktop is a running background service.

System programs are programs, not the actual system calls, and they range from very convenient small programs to very complex ones. A compiler for a programming language is one of the complex ones.

Pitfalls:

  • Confusing system programs with system calls. System calls are the low-level requests made to the OS; system programs are the utilities that wrap those calls for humans — a compiler, an editor, a loader.
  • Counting an installed application (a browser) as a system program. Applications are installed by the user and are not part of the operating system; system programs ship with the OS and provide the development and execution environment.
  • Forgetting the architecture constraint on compilers: a compiler must match the processor architecture of the system it runs on.

2.7.2 The Boot Process

When you switch on the system, the first process that runs is the boot process. Booting is one of the system programs; we can also call it the init process — the initial process. Wherever it is located, first it has to be brought into the memory, and then it has to be executed. Only after the boot process executes do the necessary programs that are needed for the execution of other programs or applications start executing. That is the very first thing that happens when a system starts.

Formalize: Booting is the very first thing that happens when a system starts. The boot process (also called the init process — the initial process) is the first process to run. Its job: get itself into memory, execute, and then start the necessary programs needed for the execution of other programs and applications. Only after the boot process has run can anything else start. (The full hardware-level story — how the bootstrap loader finds and loads the operating system — appears in section 2.11.)

Recap + Bridge: System programs — file manipulation, status, language support, loading and execution, communication, background services — ship with the OS and create the environment in which development and execution happen; the boot (init) process is the very first of them to run. The next question moves from what is shipped to how the whole system is designed: what goals and specifications guide an operating system's design, and how are policy, mechanism, and implementation language chosen?

Real-world & domain connection: Every professional toolchain rests on these system programs: developers compile with the language support utilities, debug with the status/debugging utilities, and deploy through loaders and background services. On a Linux server, init (or its modern successors such as systemd) is the first process — PID 1 — and every other process on the machine descends from it; when a server's init service crashes, the whole system goes down. Understanding which utilities are system programs and which are applications explains why a server image ships with a fixed toolchain and why adding an application to it is a separate step.

2.8 Operating System Design and Implementation

2.8.1 Goals and Specifications

The goal here is not to design an operating system or to implement one, but to understand what we have to keep in mind when designing one. The first thing to do, before going for the design of an operating system, is to define some goals and specifications. When we define the goals, we must keep in mind what hardware the operating system will be used on, and what type of system will be affected by the operating system we are going to design.

Two sets of goals are fixed. The user goals say that, as a user, the operating system should be convenient for us to use, easy to learn, reliable, safe, and fast. The system goals say the operating system should be easy to design, easy to implement, and easy to maintain; it should be error free and it should be efficient. An operating system that you are going to use should be reliable: it should not produce errors often, it should be error free, it should be efficient, and it should be very flexible when you try to use it. Those are the system goals; the convenience, reliability, safety, and speed are the user goals.

Hook: You would not build a house without deciding who lives in it, how many rooms it needs, and where it stands. An operating system is a far larger program than any house, yet many of its problems come from skipping exactly that step. Design starts with goals and specifications — and the surprising part is that the two audiences want different things.

Formalize: Design begins with defining goals and specifications. Two factors shape the goals before anything else: the hardware the operating system will run on, and the type of system it will serve (batch, time-shared, single user, multi-user, distributed, real-time, or general purpose). Then two sets of goals are fixed:

  • User goals — what the user wants from the system: convenient to use, easy to learn, reliable, safe, and fast.
  • System goals — what the designers, implementers, and maintainers want: easy to design, easy to implement, easy to maintain, flexible, error free, and efficient.

These goals are not precise engineering targets; they are directions. "Fast" and "reliable" mean different things on a real-time embedded system than on a large mainframe. Because the requirements are vague, there is no unique solution to designing an operating system — the wide range of systems in existence (from small embedded real-time systems to huge multi-user mainframes) shows that different goals produce very different designs.

Visual intuition: Picture two overlapping lists on a whiteboard. On the left, a stick figure labeled "user" with four words beneath it: convenient, easy to learn, safe, fast. On the right, a gear labeled "system" with: easy to design, easy to implement, easy to maintain, error free, efficient. The lists overlap only in the middle (reliability appears on both sides). The one-sentence takeaway: a good operating system design begins by writing both lists down before a single line of code — and the tension between the two lists is where most design trade-offs live.

Pitfalls:

  • Designing without fixing goals first. The course's core warning: define goals and specifications before design; an OS designed with no stated goals satisfies nobody.
  • Treating user goals and system goals as the same list. User goals (convenience, ease of learning, safety, speed) are about using the system; system goals (easy to design, implement, maintain, error free, efficient) are about building and operating it.
  • Expecting goals to be measurable specifications. They are intentionally broad requirements; turning them into concrete parameters is itself part of the design task.

2.8.2 Policy versus Mechanism

Two more things matter when we go for implementation: policy and mechanism. Policy is what you are going to do — what will be done. Mechanism determines how to do something. There should be a separation of policy from mechanism. Not all operating systems do this.

Think of how it works in an organization. Before starting an application or a project, the organization first fixes the policy. It decides what things are going to be accomplished, within what span of time, and how many resources we need and how many are available. Those things are designed first. Then comes the implementation — that is the mechanism — which takes care of how to build it. After the policy is defined, the mechanism decides how long it will take and how to implement it.

Specifying and designing this type of system is the main, creative task of the software.

Professor's analogy — the organization: Before starting a project, an organization first fixes the policy: what will be accomplished, within what time span, and with how many resources — available and needed. Only after the policy is fixed does the implementation (the mechanism) decide how to build it and how long it will take. An operating system works the same way: the policy states what will be done; the mechanism determines how to do it.

Formalize: Two distinct questions arise when implementing any operating system:

  • Policy — what will be done. Example: "I/O-intensive programs should have priority over CPU-intensive ones."
  • Mechanism — how to do it. Example: a timer construct that interrupts the CPU after a set interval, used to enforce any priority rule.

The important principle is the separation of policy from mechanism. Why does it matter?

  • Flexibility: policies change across places and over time. If policy and mechanism are entangled, every change in policy requires rewriting the mechanism. If the mechanism is general and policy-insensitive, a policy change only redefines a few parameters.
  • Example: a general mechanism for giving priority to certain programs can support either "I/O-intensive first" or "CPU-intensive first" — the same mechanism, two opposite policies, no rewrite.
  • Extremes: microkernel-based operating systems push the separation to an extreme by implementing a basic set of almost policy-free building blocks, and letting user-created modules add policy. Solaris scheduling is controlled by loadable tables: with one load-new-table command the system can become time shared, batch, real time, or fair share. At the other extreme, Windows encodes both mechanism and policy to enforce a global look and feel.

The rule of thumb: whenever the question is whether to allocate a resource, it is a policy decision; whenever the question is how, it is a mechanism.

Pitfalls:

  • Using "policy" and "mechanism" interchangeably. Policy answers what will be done; mechanism answers how to do it. A policy can be changed without touching the mechanism only when the two are kept separate.
  • Assuming every operating system separates them. The course is explicit: not all operating systems do this — Windows encodes both together to enforce a consistent look and feel, while Solaris loads policy tables on top of a general mechanism.

Recap + Bridge: Design starts with goals and specifications (user goals: convenient, easy, safe, fast; system goals: easy to design, implement, maintain, error free, efficient), and implementation separates policy (what will be done) from mechanism (how), using the organization analogy. With the design philosophy in hand, the next question is the material itself: what language should the operating system be written in, and what does emulation have to do with running systems on non-native hardware?

2.8.3 Implementation Languages

Earlier operating systems were written in assembly-level language. Assembly language is a mnemonic type of code, which is not very easy to understand compared to a higher-level language. Later, UNIX broke this traditional way of writing operating systems in assembly: UNIX was written in C, by Ken Thompson and Dennis Ritchie. Operating systems today may be written in C++, though which operating system uses what is not public knowledge in this course. What you can do, if you try to create an operating system, is to have a mix: some parts in assembly-level language, some parts in a higher-level language, embedded together.

Why do some people prefer the higher-level language? Because it is easier to port — to move from one system to another, based on the architecture. The only problem with the higher-level language is the storage consumption: the space the code occupies in the memory is more when compared to assembly. At times, because of that storage space, the execution also slows down. So the trade-off is: assembly is fast and compact but hard to understand and hard to port; a higher-level language is easy to understand and portable but occupies more memory and can be slower.

Formalize: The implementation language is a classic trade-off:

Property Assembly language Higher-level language (C, C++)
Speed of generated code Fastest Slightly slower (modern compilers close most of the gap)
Memory footprint Compact Larger
Understandability Hard (mnemonic code) Easy
Portability to other hardware Hard Easy
Debuggability Hard Easy

History: early operating systems were written in assembly. UNIX broke the tradition — it was written in C by Ken Thompson and Dennis Ritchie. Today most operating systems are written in a higher-level language (mostly C, with small assembly sections for device drivers and register save/restore), and a practical approach is a mix: some parts in assembly, some parts in a higher-level language, embedded together. The two real disadvantages of higher-level languages — reduced speed and increased storage — matter much less today, because compilers optimize well and only a small part of the OS (the memory manager and CPU scheduler) is performance-critical.

Worked example — the portability difference: MS-DOS was written in Intel 8088 assembly, so it runs natively only on the Intel x86 family of CPUs. Linux is written mostly in C and runs natively on many CPUs — Intel x86, Sun SPARC, IBM PowerPC. To move MS-DOS to a different processor you would have to rewrite the assembly for every routine; to move Linux you mostly recompile the C source for the new architecture. That single difference — portability — is the reason modern operating systems are written in higher-level languages despite the larger memory footprint.

2.8.4 Emulation

There is also something called emulation: you can allow an operating system to run on non-native hardware. Some systems are designed for a particular hardware. If you try to run an operating system that is not designed for that particular hardware, the hardware is non-native for it, and running the OS there is emulation.

Formalize: Emulation means running software on hardware it was not designed for — non-native hardware. An emulator is a program that duplicates the functionality of one system on another system. Because MS-DOS runs natively only on Intel x86, running it on any other CPU requires an emulator that translates each x86 instruction into the other CPU's instruction set — slower and with more resource use, but it works. Emulation is the price paid when portability was never built in; the higher-level-language choice from 2.8.3 exists largely to avoid needing it.

Scope: Emulation is a fallback, not a design goal. If the operating system was written for specific hardware, emulation lets it run elsewhere, but with slower execution and heavier resource use. Where native support exists (Linux on many CPUs), no emulation is needed and performance is full speed. A related idea — running whole operating systems in virtual machines (such as VMware) — is discussed in the next sections, but virtualization is different from emulation: a virtual machine presents the guest with hardware that matches what it expects, while an emulator translates between different architectures.

Recap + Bridge: Design sets goals first (user and system goals), separates policy from mechanism, chooses an implementation language (higher-level for portability, assembly where speed and size rule), and uses emulation only to run systems on non-native hardware. The design decisions now made, the next topic is how the finished operating system is physically arranged inside: the structures from simple MS-DOS to layered, microkernel, modular, hybrid, and mobile designs.

Real-world & domain connection: Design trade-offs seen here decide real products: Linux is portable C and so runs on everything from Raspberry Pi to mainframes; Mac OS X and Windows encode policy and mechanism together for a consistent user experience; game console operating systems and embedded devices still use tight assembly where every byte counts; and emulation runs classic games and legacy software (DOSBox runs MS-DOS games on modern PCs) exactly as described here. When a company announces "now available on ARM," that is portability; when it instead runs x86 software translated instruction-by-instruction on ARM chips, that is emulation — the two are different engineering paths with different performance.

2.9 Operating System Structures

2.9.1 The Simple Structure: MS-DOS

Any general-purpose operating system is a very large program. How it is structured matters, and the structures differ from MS-DOS to Mac. MS-DOS has a very simple structure: everything can be accessed. As an application program, you can go all the way up to the ROM BIOS, and you can access it through system programs and device drivers. The functionality has not been separated, and the modules have not been separated from one another — the application programs are not separated from the rest. Because of this, if some program tries to change something, it will destroy the whole thing, and there will not be any proper functioning of MS-DOS. That was the problem with this operating system.

Hook: Operating systems are the largest programs most of us will ever study — so how do you organize millions of lines of code so one bug cannot take everything down? The history of operating system structures is a history of answers to that question, from MS-DOS's "everything in one pot" to the layered, microkernel, and modular designs used today.

Formalize: The simple structure is the earliest approach: the operating system is not divided into well-separated modules. In MS-DOS, the interfaces and levels of functionality are not well separated — an application program can access the basic I/O routines directly and reach all the way to the ROM BIOS (the firmware that provides the most basic hardware services). Application programs, system programs, device drivers, and the OS itself are not separated from one another.

Why this is dangerous: because nothing is protected, any program can change any part of the system. If one program modifies something it should not, it can destroy the whole system and the machine stops functioning properly. Part of the reason is historical: the Intel 8088 MS-DOS ran on provides no dual mode and no hardware protection, so the designers had no choice but to leave the base hardware accessible. The lesson generalizes: a structure with no separation of modules has no way to contain damage.

2.9.2 Traditional UNIX

UNIX was not so simple, and the functionality of the hardware support is very well separated. Each and every part is separable here: one part is the system program and another part is the kernel. In the traditional UNIX structure, the user cannot directly interact with any of the device drivers, terminal controllers, or memory controllers. The user has to go either through the shell, or through the system library, or through the compilers and interpreters, to access the information present in the hardware.

The kernel — the heart of the operating system, present in each and every operating system — takes care of interfacing with the hardware. That includes signal handling, file system handling, scheduling, page replacement, virtual memory management, and disk or tape drivers. Everything is handled with the help of the controllers that are present. Through the controllers, the information is sent to the hardware, and the information is retrieved from the hardware. That is the traditional structure.

Formalize: Traditional UNIX separates the system into two main parts:

  1. System programs — the utilities and user-facing tools.
  2. The kernel — everything below the system-call interface and above the physical hardware: signal handling, file system handling, scheduling, page replacement, virtual memory management, and disk or tape drivers.

The user cannot reach the hardware directly. Access to device drivers, terminal controllers, and memory controllers goes through the shell, the system library, or compilers and interpreters; the kernel mediates all interaction with the hardware through controllers. The kernel sends information to the hardware through the controllers and retrieves information from it the same way.

The price of this design: everything sits in one large monolithic kernel. It works far better than MS-DOS, but that enormous single level is difficult to implement and maintain, which motivates the designs that follow.

Visual intuition: Picture UNIX as two stacked boxes: a slim top box labeled "system programs (shell, libraries, compilers)" and a huge bottom box labeled "kernel" containing scheduling, file system, virtual memory, and drivers as labeled compartments. The user interacts only with the top box; every request descends through the system-call interface into the kernel's compartments, which talk to the hardware through controllers. The landmark: one big kernel compartment — the reason UNIX's successor structures all try to shrink or divide that compartment.

2.9.3 The Layered Approach

Nowadays there is a layered type of approach, where each and every layer corresponds to a particular functionality. Starting from the top — the Nth layer — is the user interface, where the user enters the input. The input has to cross these many layers. Each layer provides the services to the layer above it, and uses the services of the lower level. If layer 1 exists, it uses the services of layer 0; if layer 2 exists, it uses the services of layer 1. Each and every layer is independent of the others, and each is built on top of the other. The highest layer is the user layer, and the lowest is the hardware. No layer is affected because of the other layers: they can use the services, but they cannot modify each other; each is independent of the other. This is the UNIX architecture expressed in the layered approach.

Formalize: The layered approach divides the operating system into layers (levels): the bottom layer (layer 0) is the hardware; the highest layer (layer N) is the user interface. Each layer is an implementation of an abstract object made of data and operations on that data, and it has three rules:

  1. Uses only lower layers — a layer may invoke only the services of layers below it. If layer M exists, it uses the services of layer M−1.
  2. Provides services upward — each layer provides services to the layer above it.
  3. Hides its internals — each layer hides certain data structures, operations, and hardware from the layers above; higher layers need to know only what a lower layer's operations do, never how they are implemented.

Advantages: simplicity of construction and debugging. Layer 0 can be debugged using only the hardware (assumed correct); once layer 0 is correct, layer 1 can be debugged on top of it, and so on. If a bug appears while debugging layer M, the bug must be in layer M — the layers below are already verified. Information hiding also leaves implementers free to change internals as long as the external interface stays the same.

Disadvantages:

  • Defining the layers is hard. A layer may use only lower layers, so careful planning is required. Example: the device driver for the backing store (disk used by virtual memory) must sit below memory management, because memory management uses the backing store — but the CPU scheduler may need to swap process information to the backing store, which would place the driver above the scheduler. Layer ordering is a genuine puzzle.
  • Efficiency loss. A user I/O request crosses from the I/O layer to memory management to CPU scheduling to hardware, and every layer may modify parameters and pass data — each layer adds overhead, so a system call takes longer than on a non-layered system.

2.9.4 Microkernel-Based Systems

In a microkernel-based system, the kernel is a small program. Mach is a very good example of a microkernel, and Mac OS X is based on Mach; the kernel in Mac OS X is called the Darwin kernel. In a microkernel system, the communication between the user-mode programs takes place in terms of message passing. It is easier to extend the microkernel, and it is very easy to port it to another operating system, and it is very secure and reliable as well.

The main problem is the performance overhead. When the communication has to take place between the user and the kernel, there is a performance overhead that has to be taken care of. Look at the layout: the application program is there, and it has to interact with the file system or with the device drivers — and all these things are in the user mode. The IPC, memory management, and CPU scheduling are in the kernel mode. Together these form the microkernel. If a program has to access the file system, it has to go through message passing, so every time this performance overhead is there. If a device has to communicate with the file system, the device drivers again pass the message. The overhead also loads every time we switch from user mode to kernel mode and from kernel mode back to user mode.

Intuition + Analogy: If the traditional kernel is a huge, walled compound with everything inside, the microkernel is a small town hall: it keeps only the essential services (IPC, memory management, CPU scheduling) and moves everything else — file system, device drivers — out into user mode as separate programs. When two user-mode programs must talk, they do not call each other directly; they exchange messages through the town hall. The cost: every message is a trip through the town hall, and each trip has overhead.

Formalize: A microkernel is a minimal kernel that removes all nonessential components from the kernel and implements them as system and user-level programs. Typically the microkernel provides only minimal process and memory management plus a communication facility; its main function is providing message-passing communication between the client program and the services running in user space.

  • Example: Mach, developed at Carnegie Mellon in the mid-1980s; Mac OS X's kernel, the Darwin kernel, is based on the Mach microkernel.
  • Benefits: easier to extend (new services go into user space without modifying the kernel), easier to port to another hardware design, and more secure and reliable — most services run as user processes, so if one service fails, the rest of the operating system remains untouched.
  • Drawback: performance overhead. Every operation that crosses the user-kernel boundary — a program accessing the file system, a device driver passing a message to the file system, or any user/kernel mode switch — pays a message-passing overhead. This is why Windows NT's first layered-microkernel release was slower than Windows 95, and why NT 4.0 moved layers back toward the kernel.

2.9.5 Loadable Kernel Modules

Some operating systems use loadable kernel modules. Loadable means: if you have to perform a task, then that particular module is going to be loaded as a part of the kernel, in terms of a table. It is going to load a new table; whenever a command is executed, a new table is loaded, and from there the information is retrieved. Solaris is a good example — Solaris is a modular-based approach. The kernel is the core; if it has to run any one of the modules, it loads that particular table, and with the help of the table that particular module is executed. Each module is responsible for a certain function. Some systems use a combination of approaches: it may use an object-oriented approach or a component-based approach, or it can talk through a known interface, or the module is loaded whenever it is needed. That is the approach taken by Linux and Solaris.

Formalize: The loadable kernel module (modular) approach keeps a core kernel and loads more services dynamically, at boot time or run time, as modules. Each module is responsible for a certain function. The core kernel has defined, protected interfaces, and any module can call any other module. Solaris organizes its core kernel with seven types of loadable modules: scheduling classes, file systems, loadable system calls, executable formats, STREAMS modules, miscellaneous services, and device and bus drivers.

Why modules are attractive:

  • Like the layered approach, each kernel section has defined, protected interfaces — but it is more flexible because any module can call any other (no strict layer ordering).
  • Like the microkernel, the primary module holds only core functions — but it is more efficient, because modules communicate through function calls rather than message passing.
  • Device and bus drivers for specific hardware, and support for different file systems, can be added without rebuilding the kernel.

Linux and Solaris both use this approach.

2.9.6 Hybrid Systems: Mac OS X

A hybrid type of system is a combination of multiple approaches, because we have to address performance, security, and usability, everything. Hybrid systems mostly go for a monolithic type of approach — monolithic acts with only one thing at a time, not multiple things. Sometimes they go for microkernel-type approaches. Mac OS X is a hybrid type of system. Its user interface is called Aqua. On top of that there is Cocoa — a programming interface. Cocoa helps you to run the various frameworks present in the system; that is its main use. The loadable modules in Mac OS X are called kernel extensions. In the Mac OS structure, you have the GUI, Aqua, through which you call any one of the applications or the services. Cocoa acts as the API to run the frameworks in order to provide the service to the kernel environment, and then you get the information back.

Formalize: A hybrid system combines multiple structural approaches to balance performance, security, and usability. Mac OS X is the classic hybrid:

  • Layered structure on top: the user interface Aqua sits at the top; below it, Cocoa is the programming interface (API) through which applications run the various frameworks of the system.
  • Microkernel heritage below: the kernel environment contains the Mach microkernel (memory management, RPC and IPC facilities, thread scheduling) plus the BSD component (command-line interface, networking, file systems, POSIX APIs).
  • Modular pieces: loadable modules in Mac OS X are called kernel extensions (kexts) — device drivers and other dynamic additions developed with the I/O kit.

The user works through Aqua, applications call Cocoa as the API to run frameworks, and those frameworks provide services to the kernel environment, which returns the information back. Hybrid designs exist because no single structure meets all goals: monolithic code is fast but fragile; microkernels are clean but slow; hybrids take pieces of each.

2.9.7 Mobile Platforms: iOS and Android

iOS is mainly for mobile devices like the iPhone and the iPad. Apart from the functionality provided by Mac OS X, iOS provides something called Cocoa Touch. Cocoa Touch is different from Cocoa: it is an API specifically designed for mobile devices, in order to use the touch screen of devices like the iPhone or the iPad. This particular API — Objective-C — was designed by Apple. Apart from that, iOS has media services, core services, and the core operating system, which is mainly based on Mac OS X. Media services provide audio, video, and multimedia services. Core services provide database-based or cloud-based services.

Android is the operating system on many handsets. It was developed by the Open Handset Alliance, and it is open source. Its structure is more or less similar to iOS. Android has libraries that help you run databases — SQLite is there — plus OpenGL for graphics, the surface manager, the media framework, libc, and WebKit for developing or running web applications. There is also a runtime environment where Dalvik is used: Dalvik acts as a virtual machine. Whatever code is given is converted into an executable code, which then runs with the help of the Dalvik machine. So in the Android architecture, the application runs by taking the support of the libraries. With the help of the runtime environment, the kernel loads the modules and runs the application.

Formalize: Mobile operating systems adapt the desktop structures to small, touch-driven devices.

iOS layers on top of Mac OS X's functionality:

  • Cocoa Touch — an API specifically designed for mobile devices, for using the touch screen of the iPhone or iPad; its programming language, Objective-C, was designed by Apple.
  • Media services — audio, video, and multimedia services.
  • Core services — database-based or cloud-based services.
  • Core operating system — mainly based on Mac OS X (which itself is built on the Mach microkernel and BSD).

Android, developed by the Open Handset Alliance and open source, has a structure similar to iOS:

  • Libraries — SQLite for databases, OpenGL for graphics, the surface manager, the media framework, libc (the C library), and WebKit for web applications.
  • Runtime environmentDalvik, a virtual machine: code is converted into executable bytecode, which then runs with the help of the Dalvik machine.
  • Kernel — with the runtime environment's help, the kernel loads the modules and runs the application, which takes the support of the libraries.

Pitfalls:

  • Thinking "monolithic" means one thread runs at a time. In the course's phrasing, monolithic means the system acts as one large unit — functionality is not separated into independent modules. It is a statement about structure, not about parallelism.
  • Confusing Cocoa and Cocoa Touch. Cocoa is Mac OS X's desktop programming interface; Cocoa Touch is the touch-screen API for iOS. Different devices, different APIs.
  • Believing a microkernel is slow in the abstract: the overhead is real, but it is a deliberate trade — security and reliability in exchange for speed. Windows NT's history (microkernel → more monolithic in NT 4.0) shows designers trading back when performance suffered.
  • Treating the structures as mutually exclusive. Real systems combine them: Mac OS X is layered + microkernel + modules; Linux is mostly monolithic in spirit but modular in loading drivers.

Recap + Bridge: Operating system structures form a design spectrum: simple (MS-DOS — no separation, one bug destroys everything), traditional UNIX (system programs + one big kernel), layered (strict levels using only lower layers), microkernel (small kernel, message-passing between user-mode services, overhead cost), loadable modules (core kernel plus dynamically loaded modules), hybrids (Mac OS X: Aqua + Cocoa + Mach/BSD + kernel extensions), and mobile platforms (iOS with Cocoa Touch, Android with Dalvik). The common thread: every structure is a different answer to how much to separate, and how much overhead that separation is worth. With structures covered, the session turns to what happens when systems fail: debugging and failure analysis.

Real-world & domain connection: These structures decide what you can do with real devices: Android's Dalvik/ART runtime runs apps in a sandboxed virtual machine on billions of handsets; iOS's Cocoa Touch determines how every iPhone app handles touch input; Linux's loadable kernel modules are why you can plug in a new USB Wi-Fi adapter and have the driver load automatically without rebooting; and the Mach microkernel heritage in Darwin is why Mac OS X survived the transition from PowerPC to Intel and then to Apple Silicon. Choosing a structure is one of the first architectural decisions a real operating system project makes, and it constrains everything that follows.

2.10 Debugging and Failure Analysis

2.10.1 Kernighan's Rule

This topic is flagged as very, very important. According to Kernighan, debugging is twice as hard as writing the code. If you have written the code properly — or cleverly — then when something happens you may not have the capability to debug that particular code. So always keep this in mind: if you write code as cleverly as possible, you may not be clever enough to debug it. Writing simple, debuggable code beats writing clever, undebuggable code.

Hook: How many programmers have been defeated by their own "brilliant" one-liner? The most famous rule in all of debugging comes from Brian Kernighan: debugging is twice as hard as writing the code. The course flags this as very, very important material — and it is the only topic in this session with that emphasis.

Formalize: Kernighan's rule (often called Kernighan's Law): debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

The logic is a trap, not a joke:

  1. Writing code takes some intelligence.
  2. Debugging that code is twice as hard — it requires double the intelligence.
  3. If you used all your cleverness on writing, you have none left for debugging.

The practical rule that follows: write simple, debuggable code. Simple code can be understood, traced, and fixed when it fails; clever code may be admired once and then defeated forever. Debugging is the activity of finding and fixing errors — bugs — in both hardware and software, and performance problems count as bugs too, so performance tuning is part of debugging.

Exam note: Debugging and failure analysis are flagged as very, very important material — treat that emphasis as a strong signal for revision.

Recap + Bridge: Debugging is twice as hard as writing, so write debuggable code from the start. With that attitude set, the practical question is how debugging actually happens: where do errors get recorded, and what tools turn those records into fixes? That is log files and dumps next.

2.10.2 Log Files and Dumps

The main use of debugging is to find and fix the errors — the bugs. To do that, we have some log files that are generated in case there is any error information. Suppose there is an error in the application: we can capture that error in the code dump. "Core" actually means memory, so a core dump file is created, which captures the information with respect to the failure of an application. At times the system can also crash, and that creates a crash dump file, which has the kernel memory.

Formalize: When a process fails, the operating system records the failure in two places:

  • Log file — a file where the operating system writes error information to alert system operators or users that a problem occurred. Logs are also written for less severe events, and tracing systems log all interesting events with their time and important parameters for later analysis.
  • Core dump — a capture of the memory of the failed process ("core" was the early term for memory). This core image is stored in a file and can later be examined by a debugger — a tool that lets a programmer explore the code and memory of a process — to find the cause of the failure.

Kernel failures are handled similarly but with more care: a kernel failure is called a crash. When a kernel crashes, the error information is saved to a log file, and the kernel's memory state is saved to a crash dump. Because a crash in file-system code makes it risky to write to the file system, the kernel writes its memory state to a section of disk set aside for this purpose that contains no file system; after reboot, a process gathers the data and writes it into a crash dump file within the file system for analysis.

2.10.3 Profiling and Performance Tuning

Sometimes we need to keep track of the activities and record them for performance optimization — that is profiling. Profiling means periodically sampling the instructions and the statistical trends that are going through the system, and maintaining them accordingly. For performance tuning, we have to remove the bottlenecks present in the system.

Formalize: Profiling periodically samples the instruction pointer — the code location being executed — to determine which code is running, and records the statistical trends of the system's activities. Unlike a full trace, profiling does not capture every event; it samples, so it shows statistical trends rather than individual activities. Its purpose is performance tuning: finding and removing bottlenecks — the points in the processing that slow everything else down. The operating system can also produce trace listings: all interesting events are logged with their time and important parameters and written to a file; an analysis program later processes the log to find bottlenecks and inefficiencies. Traces can even be fed to a simulation of an improved system to test proposed changes.

2.10.4 Monitoring Tools in Practice

In Windows, there is the Task Manager. It has a performance tab where you can see the CPU usage, the page file usage history, the total number of threads, how many threads are in use, how many processors there are, the total memory, and the kernel memory. By seeing this you can understand whether the CPU is utilized properly — CPU utilization is very important.

In Solaris and Mac OS there is a tool called DTrace. DTrace has probes: whenever a code is executed, a probe fires, captures the data, and sends it. Events specified by the user are in the user space; the execution happens in the kernel. Whenever this particular event is triggered or fired, automatically the control moves from the user library to the kernel, and again it comes back to the user library.

The monitoring also records, for each process with a particular user ID, the amount of time it is running — in terms of nanoseconds. That per-process CPU time is reported precisely.

Worked example — the Windows Task Manager performance tab: Open the Task Manager (Ctrl+Shift+Esc) and switch to the performance tab. The readings you can take:

  1. CPU usage — the percentage of processor capacity in use right now; high sustained usage (near 100%) means the CPU is a bottleneck.
  2. Page file usage history — how the swap space on disk has been used over time, which shows whether memory is overflowing into disk.
  3. Total number of threads and threads in use — how many execution streams exist and how many are active.
  4. Number of processors — how many CPU cores the machine exposes to the OS.
  5. Total memory and kernel memory — how much RAM the machine has, and how much the kernel itself occupies.

Sense-check: together these numbers answer one question — is any resource saturated? If CPU is at 10% but memory is full and the page file is growing, the bottleneck is memory, not CPU. That is the whole point of performance monitoring: find the saturated resource, then tune it.

Worked example — DTrace probes: DTrace is the dynamic tracing facility of Solaris (and later Mac OS X and FreeBSD). It dynamically adds probes to a running system, in both user processes and the kernel, without stopping the system:

  1. Define the event — the user specifies an event of interest (for example, every read system call made by processes with a given user ID).
  2. Probe fires — whenever that code is executed, the probe fires, captures the data (the control moves from the user library into the kernel, where the probe executes), and sends it.
  3. Return — control returns to the user library, and the recorded data is collected.

The tool records, for each process with a particular user ID, the amount of CPU time it ran — reported in nanoseconds — plus a great deal more (system call sequences, kernel function calls, I/O events). DTrace is safe for production systems: when not in use it has no effect, and when probing is finished the system is restored to its pre-debugging state.

Pitfalls:

  • Writing clever code and hoping it will not need debugging — it will, and Kernighan's rule says you will be twice as unready. Write simple, debuggable code from the start.
  • Confusing core dumps with crash dumps. A core dump captures the memory of one failed process; a crash dump captures the kernel's memory when the whole system crashes. Different events, different files, different tools.
  • Thinking profiling captures everything. Profiling samples — it gives statistical trends, not every individual activity; if you need every event with its time, you need tracing.
  • Reading the Task Manager as a single number. The performance tab is a set of related readings; the skill is comparing them to find which resource is the bottleneck.

Recap + Bridge: Debugging is twice as hard as writing (Kernighan's rule — flagged very, very important), failures are recorded in log files plus core dumps (process) or crash dumps (kernel), profiling samples the system to find bottlenecks, and practical tools — Windows Task Manager, DTrace probes with per-process CPU time in nanoseconds — turn these ideas into visible numbers. The session closes with the machine itself: how operating systems boot, and what portability and platform-specific software mean.

Real-world & domain connection: Debugging and performance work dominate real system administration and engineering. A server team investigating a slowdown starts exactly as this section describes: check Task Manager equivalents (top on Linux), sample profiles (perf, DTrace), find the saturated resource, and tune it. When an app crashes, the core dump is what the vendor's engineers analyze; when a machine blue-screens, the crash dump is what Microsoft asks for. Kernighan's rule is quoted in every code review discussion about clever code, and the per-process CPU time in nanoseconds is what cloud billing and autoscaling systems are built on.

2.11 Portability, Booting, and Platform-Specific Software

2.11.1 Portability and Compatibility

When we try to design an operating system, it should be able to run on any kind of machine, or it can be designed to run on a specific system. Some systems have been designed to run only on specific hardware — the system can be tied to the architecture of the processor. Especially in the Mac world, the machines have their own processor, their own architecture, and their own instructions, which they handle themselves. They do not allow other operating systems to be used on them. For the rest, the portability or compatibility should be there — the ability to access information and run across systems.

Hook: Why does your Windows installer ask whether you have a 32-bit or 64-bit system, and why does Mac software so rarely run on other machines? The answer is a design decision made long before the software existed: whether the operating system is portable (designed to run on many machines) or tied to one architecture. This section closes the session by explaining that decision, then the boot process, and the platform-specific software industry that results.

Formalize: Portability is the ability of an operating system or program to access information and run across different systems; compatibility is its ability to work with the hardware it is placed on. At design time there is a fork:

  • Portable systems — designed to run on any kind of machine (subject to the implementation-language choices of 2.8.3; a higher-level language like C is easier to port).
  • Architecture-tied systems — designed to run only on specific hardware, tied to the processor's architecture and its instruction set.

The Mac world sits at the architecture-tied end: Apple machines have their own processors, their own architecture, and their own instructions, which they handle themselves, and they do not allow other operating systems to run on them. Most other systems aim for portability and compatibility — the ability to access information and run across systems.

2.11.2 How a System Boots

Whenever you switch on a system, the first thing has to be brought up and placed in the memory for execution, and then the rest of the system starts. A small piece of code — the bootstrap loader — is what loads that particular program into the memory. Sometimes there is a block called the boot block, which holds the code. The process works in two steps: first, we go and find where the boot block is and get the information; second, we load it into the memory and start executing. Alternatively, we can have a boot menu — something like GRUB — which allows the selection among multiple disks. Multiple boot options are shown, and from that we can load a kernel and start fresh. These are the various ways the system can be booted.

Formalize: Booting is the procedure of starting a computer by loading the kernel. When the CPU receives a reset event (power-up or reboot), it starts executing at a predefined memory location, where the initial bootstrap program lives. Because RAM is in an unknown state at startup, the bootstrap program is stored in read-only memory (ROM) — which needs no initialization and cannot easily be infected by a virus.

The standard sequence for large operating systems (Windows, Mac OS X, UNIX):

  1. Bootstrap loader (in firmware) runs diagnostics and reads a single fixed block — the boot block at a fixed disk location — into memory and executes it.
  2. The code in the boot block is often simple; it may be sophisticated enough to load the entire operating system, or it may know only where the rest of the bootstrap program is on disk and its length, and load that.
  3. The full bootstrap program traverses the file system, finds the operating system kernel, loads it into memory, and starts its execution. Only at this point is the system running.

The two-step alternative: a boot menu such as GRUB (an open-source bootstrap program for Linux systems) presents multiple boot options — selection among multiple disks and kernels — and from that menu we load a kernel and start fresh. This is how a dual-boot machine (Windows and Linux on one disk) lets you choose at startup.

Scope: Booting has a built-in chicken-and-egg problem: the kernel cannot start without being loaded, and nothing is running to load it. The answer is the fixed sequence above — firmware that needs no setup, a tiny boot block the firmware can always find, and a bootstrap loader that grows progressively smarter. The same reason explains why small systems (phones, PDAs, game consoles) can store the entire operating system in ROM: it is simple, rugged, and always available — at the cost of firmware that is hard to change.

2.11.3 Platform-Specific Software

There is a specific reason why most newly built software is Windows-first. Mac OS offers stronger protection when compared to Windows. Those using the Windows operating system know: Windows can run almost any system. We are not bothered about threads or whatever — we install whatever software we can run and start running it. It even asks whether you want to run the application, and we go on. Mac, and whatever carefully guarded software in the system, will not allow you to run all software. The authenticity, the protection, and the security provided for the system are more in those cases, because the new software should not affect the operating system. Windows does not take care of all those things, so any new build works on Windows.

That is why vendors ship separate versions for each platform: sometimes three things — Windows, Mac, and Unix — and sometimes only two — Windows and Mac. Each build has different functionality because the structure of each operating system differs. Within Windows you have to be very particular: the software will be specific to 32-bit or 64-bit, and to Windows 10 or Windows 11, so there will be two different specifications to choose from. And for Mac: people working in organizations use Macs because they have their own processor, their own architecture, and their own instructions, and they do not allow other operating systems to be used with them. Mac users generally stay with Mac OS. People who use a MacBook feel very comfortable with it, and booting feels easy. On processor-based Windows machines, booting can happen within fractions of a second.

Formalize: Platform-specific software is software distributed in separate versions because each platform differs in structure, security model, and architecture:

  • Why Windows-first? Windows is the most permissive platform — it lets users install and run almost any software (asking only whether you want to run the application), because it does not enforce the strict authenticity and protection checks of other systems. That permissiveness means a new build will run on Windows, so vendors ship there first.
  • Why separate versions? Mac OS is more protective than Windows and restricts which software can run, so the authenticity, protection, and security of the system stay intact and new software cannot disturb the operating system. Each version has different functionality because the structure of each operating system differs.
  • Vendor practice: installers come in separate versions — sometimes three (Windows, Mac, Unix), sometimes two (Windows, Mac). Within Windows, software is specific to 32-bit versus 64-bit and to the OS generation (Windows 10 versus Windows 11), so two different specifications must be offered.
  • The Mac side: Apple machines have their own processor, architecture, and instructions, and do not allow other operating systems; Mac users generally stay with Mac OS, and organizations that use Macs run no other OS on them.

2.11.4 Student Questions and Answers

Q: Can we install or run Mac OS on a Windows machine?

A: I am not sure a direct install is possible. On Windows there are many authentications — even to install a particular app and then use it, you have to go through one or two authentication steps. But what we can do is install a virtual machine, such as VMware. Using VMware, we can run guest operating systems, and two or more guest operating systems can be installed side by side. The only problem: a virtual machine occupies some space and slows down your system. The steps: during startup itself, enable virtualization (check whether it is enabled or not — once enabled, you need not enable it every time), then start the virtual machine, upon which the guest operating system is loaded or booted. The Ubuntu-on-VMware installation was itself a cumbersome process, and executing it might slow down the system — so whether you really need a virtual machine is something to think about.

Q: Is there a specific reason why most of the newly built software is not available for Mac OS?

A: Yes. Mac OS is more secure than Windows, and it will not allow you to run every piece of software, so the protection and security of the system stay intact, and new software cannot disturb the operating system. Windows does not restrict software this way, which is why new builds work on Windows first. That is why installers come in separate versions — sometimes three (Windows, Mac, Unix), sometimes two (Windows, Mac). For Windows you must pick the right build for 32-bit or 64-bit and for Windows 10 or 11. Mac builds follow Apple's own processor and architecture, and organizations that use Macs do not run other operating systems on them.

Pitfalls:

  • Thinking a virtual machine is free. VMware and similar tools run guest operating systems side by side, but each guest occupies disk space and slows the system — the professor's own Ubuntu-on-VMware installation was cumbersome, and that cost must be weighed before choosing virtualization.
  • Expecting one installer to fit every machine. Platforms differ in security model and architecture, so vendors ship separate builds: Windows (32-bit versus 64-bit, Windows 10 versus Windows 11), Mac, and Unix.
  • Believing booting is a single step. It is a chain — firmware bootstrap, boot block, bootstrap loader, kernel — and a boot menu such as GRUB only adds a choice stage in the middle of that chain.

Recap + Bridge: The session closes where every machine starts: portability is a design choice (portable versus architecture-tied, as in the Mac world), booting is a fixed chain from firmware bootstrap through the boot block and bootstrap loader to the kernel (with boot menus such as GRUB for multiple disks), and platform-specific software is the industry's answer to differing security models and architectures. This completes the loop opened in section 2.1: services, interfaces, system calls, system programs, design, structures, and debugging all traced back to the machine that boots them.

Real-world & domain connection: Every one of these topics shows up in daily practice. Booting is why you can dual-boot Windows and Linux with GRUB, why a Mac's startup key combination picks a boot disk, and why firmware updates matter for security. Portability is why Linux runs on servers, phones, and Raspberry Pis while macOS stays on Apple hardware. Platform-specific distribution is why your Windows installer asks for 32-bit or 64-bit, why Mac software installs with a drag to Applications, and why organizations standardize on one platform. The virtual machine answer in the Q&A is exactly how developers today run Windows, Linux, and macOS guests on one laptop — the same VMware mechanism, with the same space and speed costs.

Exam Guidance Summary

  • Debugging and failure analysis are flagged as very, very important; treat that emphasis as a strong signal for revision.
  • The categories of system calls — process control, file management, device management, information maintenance, communication, and protection — and what each category can do are core material, studied in greater detail in later sessions.
  • Resource allocation, communication, shared memory, and message passing are foundational: the coming sessions revisit them in detail, so the basic picture from this session will be built on, not replaced.
  • The first few sessions are mostly theoretical; once processes are introduced, the material gets harder and the problems become more interesting, so expectations should be set accordingly.

Exam note: Where this session is strong, the exam is likely to follow: know the six user-facing services and the three system-oriented services by name; trace the user → interface → system call → kernel mode → hardware loop; list the six categories of system calls with an example call each; explain the difference between policy and mechanism; and compare the operating system structures (simple, layered, microkernel, modular, hybrid, mobile). Debugging and failure analysis carry the strongest weighting signal in this session.

Key Industry Applications

  • WSL (Windows Subsystem for Linux): running Ubuntu and Linux commands inside Windows without a full virtual machine.
  • VMware virtual machines: running guest operating systems (two or more) side by side, at the cost of disk space and speed.
  • GUIs: Windows as the most widely used system (about 64% of usage), Mac OS X with the Aqua interface, and the GUI's origin at Xerox.
  • Voice and touch interfaces: assistants like Alexa, and touch screens on laptops and mobile devices.
  • Win32 API for Windows, POSIX API for Unix, Linux, and Mac OS X, and the Java API for the JVM — the standard ways applications reach system calls.
  • The Unix design lineage: UNIX written in C by Ken Thompson and Dennis Ritchie, the layered architecture, and the Darwin kernel in Mac OS X built on the Mach microkernel.
  • Solaris and Linux loadable kernel modules, and hybrid designs such as Mac OS X with its Cocoa framework API and kernel extensions.
  • Mobile structures: iOS with Cocoa Touch and Objective-C, and Android from the Open Handset Alliance with SQLite, OpenGL, WebKit, and the Dalvik virtual machine.
  • Debugging and performance tooling: the Windows Task Manager performance tab, DTrace probes in Solaris and Mac OS, and per-process CPU time measured in nanoseconds.
  • Boot-time infrastructure: the bootstrap loader, the boot block, and boot menus such as GRUB for choosing among multiple disks and kernels.
  • Platform-specific software distribution: separate installer builds for Windows (32-bit versus 64-bit, Windows 10 versus 11), Mac, and Unix, driven by each platform's security model and architecture.

Where these live in practice: every application you install touches one or more of these industry realities — a Windows installer is platform-specific software; a phone app runs on iOS's Cocoa Touch or Android's Dalvik runtime; a cloud server boots through a bootstrap loader and is monitored with Task Manager-style tools and DTrace-class tracing; and the code you write reaches the hardware through Win32, POSIX, or the Java API. When later sessions discuss processes, scheduling, and memory, these applications are what those topics will be operating on.

OS Lecture 2 notes · Operating Systems: Services, Interfaces, and Structures

Operating Systems· postgraduate· 2026-08-15

Sections Breakdown

1What Is an Operating System

The operating system as a resource allocator and control program: memory, process, free-space, and device management, plus the roadmap of the session.

2Operating System Services: The User-Facing Set

The six user-facing services: user interface, program execution, I/O operations, file system implementation, communication, and error detection.

3Operating System Services: Running the System

The three services that keep the system itself running: resource allocation, accounting, and protection and security.

4The Overall View: User, System Calls, and Hardware

The overall view: how a user's request flows through the interface and system calls into kernel mode, to the hardware, and back.

5User Interfaces in Practice

User interfaces in practice: the command line and the shell, the GUI, and touch and voice interfaces.

6System Calls and the API

System calls and the API: what they are, the worked file-copy and read() examples, parameter passing, and the six categories of system calls.

7System Programs

System programs: the categories of utilities that ship with the OS, and the boot process.

8Operating System Design and Implementation

OS design and implementation: goals and specifications, policy versus mechanism, implementation languages, and emulation.

9Operating System Structures

Operating system structures: simple, traditional UNIX, layered, microkernel, loadable modules, hybrid, and mobile platforms.

10Debugging and Failure Analysis

Debugging and failure analysis: Kernighan's rule, log files and dumps, profiling and performance tuning, and monitoring tools.

11Portability, Booting, and Platform-Specific Software

Portability, booting, and platform-specific software, closing with the session's student questions and answers.

12Exam Guidance Summary

The exam-relevant signals from the session: which topics carry the strongest weight and how the foundations connect to later sessions.

13Key Industry Applications

How each concept maps onto real industry tools and platforms, from WSL and VMware to GRUB and DTrace.

Postgraduate students in Operating Systems

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

What Is an Operating System

Must-know: The operating system is a resource allocator that decides who gets what (CPU time, memory, file storage, I/O devices) and acts as a control program managing user programs and I/O; every device attached to the system goes through the operating system.

⚠️ Top pitfall: Confusing 'the system' (hardware plus OS) with the operating system itself, or thinking the OS only allocates CPU when it also manages memory, processes, free space, and devices.

Self-check: Name three resources that the operating system allocates and why allocation matters in a multiprogrammed environment.

Connects to: Operating System Services: The User-Facing Set, Operating System Services: Running the System, The Overall View: User, System Calls, and Hardware

Operating System Services: The User-Facing Set

Must-know: Name the six user-facing OS services: user interface, program execution, I/O operations, file system implementation, communication, and error detection, and give one concrete task performed by each.

⚠️ Top pitfall: Confusing the user interface with the operating system itself, or thinking the OS catches errors before they happen rather than detecting and reacting to them.

Self-check: What are the three mechanisms of process-to-process communication, and which is fastest on a single machine?

Connects to: What Is an Operating System, Operating System Services: Running the System, User Interfaces in Practice

Operating System Services: Running the System

Must-know: The three system-oriented services are resource allocation (who gets the contended resource), accounting (who used what, for billing and statistics), and protection and security (internal non-interference plus external access control with authentication).

⚠️ Top pitfall: Treating protection and security as the same: protection is internal (processes must not interfere with each other's resources), security is external (outsiders must not access the system).

Self-check: P1, P2, and P3 all need data.txt at the same time. What does the operating system decide, and why is the order of grants important?

Connects to: Operating System Services: The User-Facing Set, The Overall View: User, System Calls, and Hardware, Operating System Design and Implementation

The Overall View: User, System Calls, and Hardware

Must-know: The complete loop: user action → interface → system call (I/O, file, or resource related) → switch to kernel mode → operating system interacts with hardware → response returns to user.

⚠️ Top pitfall: Thinking the user program performs the hardware operation directly; in fact, in kernel mode the operating system executes the request on the user's behalf.

Self-check: Why must the CPU switch from user mode to kernel mode when a system call is made?

Connects to: Operating System Services: The User-Facing Set, System Calls and the API, Operating System Structures

User Interfaces in Practice

Must-know: The command-line chain is command → shell (command interpreter) → kernel → hardware → back; the prompt signals the shell is ready; the kernel is the heart of the OS. Bash is the Bourne Again Shell, the default shell on Ubuntu.

⚠️ Top pitfall: Confusing the command line (interaction style) with the shell (the interpreter program), or believing the GUI is the operating system rather than a program on top of it.

Self-check: Trace the path of a command typed at the Ubuntu prompt from your fingers to the hardware and back.

Connects to: The Overall View: User, System Calls, and Hardware, System Calls and the API, System Programs

System Calls and the API

Must-know: The six categories of system calls — process control, file management, device management, information maintenance, communication, and protection — and a sample call for each; read() returns the number of bytes read, 0 at end of file, and -1 on error.

⚠️ Top pitfall: Confusing the API function (printf, CreateProcess) with the underlying system call (write, NTCreateProcess), or misreading read()'s return: positive = bytes read, 0 = end of file, -1 = error.

Self-check: List the system calls executed to copy one file into another, and say what read() returns in each of its three outcomes.

Connects to: The Overall View: User, System Calls, and Hardware, User Interfaces in Practice, System Programs

System Programs

Must-know: The categories of system programs and one example each; the boot/init process is the first process to run when the system starts; a compiler must be compatible with the processor architecture; applications installed by the user are not part of the OS.

⚠️ Top pitfall: Confusing system programs (utilities like editors, compilers, loaders) with system calls (the low-level requests they wrap), or counting user-installed applications as system programs.

Self-check: Name three categories of system programs and the first process that runs when a system starts.

Connects to: System Calls and the API, Operating System Design and Implementation, Portability, Booting, and Platform-Specific Software

Operating System Design and Implementation

Must-know: Design starts with goals and specifications; user goals (convenient, easy to learn, reliable, safe, fast) differ from system goals (easy to design, implement, maintain, error free, efficient); policy is what will be done, mechanism is how; UNIX was written in C by Ken Thompson and Dennis Ritchie; assembly is fast and compact but hard to port, higher-level languages are portable but larger.

⚠️ Top pitfall: Using policy and mechanism interchangeably, or assuming every operating system separates them (not all do — Windows encodes both together).

Self-check: State the user goals and the system goals, and give an example of a policy and a matching mechanism.

Connects to: System Programs, Operating System Structures, Portability, Booting, and Platform-Specific Software

Operating System Structures

Must-know: Compare the structures: MS-DOS simple (no separation; damage spreads), traditional UNIX (system programs + one large kernel), layered (strict level ordering, easy debugging, slow calls), microkernel (small kernel, message passing, overhead; Mach/Darwin), loadable modules (core + dynamic modules; Solaris, Linux), hybrid (Mac OS X: Aqua, Cocoa, kexts), mobile (iOS Cocoa Touch; Android Dalvik VM).

⚠️ Top pitfall: Confusing Cocoa (Mac OS X desktop API) with Cocoa Touch (iOS touch API), or believing microkernels are slow in the abstract — the overhead is a deliberate trade for security and reliability.

Self-check: Why does the layered approach simplify debugging, and what overhead does it add to a system call?

Connects to: The Overall View: User, System Calls, and Hardware, Operating System Design and Implementation, Debugging and Failure Analysis

Debugging and Failure Analysis

Must-know: Kernighan's rule: debugging is twice as hard as writing the code, so writing clever code you cannot debug is a trap. Log files and core dumps record process failures; crash dumps record kernel failures. Profiling samples instructions to find statistical trends; performance tuning removes bottlenecks.

⚠️ Top pitfall: Confusing core dumps (memory of a failed process) with crash dumps (kernel memory after a system crash), or believing profiling captures every event when it only samples trends.

Self-check: State Kernighan's rule and give two ways a system records a failure, one for a process and one for the whole kernel.

Connects to: Operating System Services: The User-Facing Set, Operating System Structures, Portability, Booting, and Platform-Specific Software

Portability, Booting, and Platform-Specific Software

Must-know: Booting is a chain: firmware bootstrap program (ROM) → boot block → bootstrap loader → kernel; GRUB is a boot menu for multiple disks/kernels. Portability is the ability to run across systems; Mac is architecture-tied. Mac OS is more secure than Windows and restricts software, so vendors ship separate builds per platform.

⚠️ Top pitfall: Thinking a virtual machine is free — each guest occupies disk space and slows the system; or expecting one installer to fit every platform when builds are specific to 32/64-bit and OS generation.

Self-check: List the steps from switching on the machine to the kernel starting, and explain why firmware (ROM) is used for the first bootstrap step.

Connects to: System Programs, Operating System Design and Implementation, Operating System Structures

Exam Guidance Summary

Must-know: Debugging and failure analysis are the strongest-weighted topic in this session; the six categories of system calls are core material studied in greater detail later; resource allocation, communication, shared memory, and message passing are foundational and will be built on.

⚠️ Top pitfall: Under-weighting the theoretical first sessions — the basic picture built here (services, system calls, structures) is the foundation the harder process-related sessions build on.

Self-check: Which topics carry the strongest exam signals in this session, and why should the foundational services and system-call picture be kept clear?

Connects to: What Is an Operating System, Operating System Services: Running the System, System Calls and the API, Debugging and Failure Analysis

Key Industry Applications

Must-know: Each structure and service from this session has a named industry counterpart: Win32/POSIX/Java APIs, Mach/Darwin microkernel lineage, Solaris/Linux loadable modules, iOS Cocoa Touch, Android Dalvik, Task Manager and DTrace for performance, GRUB for boot selection.

⚠️ Top pitfall: Treating the named systems as trivia — they are the concrete anchors that make the abstract concepts (system calls, structures, debugging, booting) examinable.

Self-check: Give one named industry application for each of: APIs, microkernels, loadable modules, mobile structures, debugging tools, and boot-time infrastructure.

Connects to: User Interfaces in Practice, System Calls and the API, Operating System Structures, Debugging and Failure Analysis, Portability, Booting, and Platform-Specific Software

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.