OS Design and Structure

Apart from the Kernel and the user interface (GUI and/or CLI), a modern operating system also comes with system programs and application programs.

Most users’ view of an operating system is defined by the system programs, not the actual system calls because they are actually hidden from us (through API).

  • For example, when a user’s computer is running the macOS, the user might see the GUI, featuring a mouse-and-windows interface.

System Programs

System programs, also known as system utilities, provide a convenient environment for program development and execution:

  1. They are basic tools used by many users for common low-level activities.
  2. These tools are very generic, thus can be considered as part of the “system” instead of individual user apps that we typically install
  3. Note that sometimes system programs and system calls have the same name, but they are nowhere the same. For example:
    1. write as a command that can be typed on the terminal (type man write to find out what these arguments are.)1
    2. write is also a system call API and an actual system call name

System programs runs on user mode, just like any other user-level applications. When it requires kernel services, they make system calls just like any other user programs.

Categories

Like system calls, they can also be divided into the following categories:

Package Managers: file management and modification

These programs create, delete, copy, rename, print, dump, list, and generally manipulate files and directories. For example: all commands that you can enter in CLI that involves file management in UNIX systems is actually the name of system programs that can be found in the $PATH. These include ls, rm, mkdir, cp, touch among many others.

Modern OS usually comes with default package managers that simplifies installation of softwares (and also managing versions, updates, running background services, etc). For instance, brew for macOS and apt for Debian-based Linux distributions.

Several text editors provided (nano, vi) may be available to create and modify the content of files stored on disk or other storage devices. There may also be special commands to search the contents of files or perform transformations of the text like grep, awk, tr.

Status information

Some programs simply ask the system for various status information: date, time, amount of available memory or disk space, number of users, etc. Others are more complex, providing detailed performance, logging, and debugging information. Example include top, ls, df among many others.

Typically, these programs format and print the output to the terminal or other output devices or files or display it in a window of the GUI. Some systems also support a registry, which is used to store and retrieve system configuration information.

Programming-language support

Compilers, assemblers, debuggers, and interpreters for common programming languages (such as C, C++, Java, and Python) are often provided with the operating system or available as a separate download. Package managers such as npm, pip are also available by default in modern OS to make it easier for users to develop.

Program loading and execution

Once a program is assembled or compiled, it must be loaded into memory to be executed. The system may provide absolute loaders, relocatable loaders, linkage editors, and overlay loaders. Runtime debugging systems for either higher-level languages or machine language are needed as well.

Communications

These programs provide the mechanism for creating virtual connections among processes, users, and computer systems. They allow users to send messages to one another’s screens, to browse Web pages, to send e-mail messages, to log in remotely, or to transfer files from one machine to another. Example include ssh, pipe (|).

Background services

All general-purpose systems have methods for launching certain system-program processes at boot time (upon startup): network-related system programs, some device drivers (although there are drivers that run in kernel mode, these are not system programs), etc

  • Constantly running system-program processes are known as services, subsystems, or daemons.
  • One example is the network daemon:
    • A system needed a service to listen for network connections in order to connect those requests to the correct processes.
  • Other daemon examples include:
    • The init process (specifically calledsystemd in Linux, launchd in macOS)
    • Process schedulers that start processes according to a specified schedule,
    • System error monitoring services,
    • Print servers

Typical systems have dozens of daemons. In addition, operating systems that run important activities in user mode rather than in kernel mode may use daemons to run these activities.

Application (User) Programs

Along with system programs, most operating systems are supplied with programs that are useful for specific users. Such application programs are Web browsers, word processors and text formatters, spreadsheets, database systems, compilers, plotting and statistical-analysis.packages, and games.

System vs Application Programs

It is often hard to distinguish between system and application (user) programs. Some programs like compiler, assembler, debugger, device drivers, and antivirus can be clearly defined as system programs. Programs like media player, photo editing softwares, and video games are clear examples of application programs.

The table below summarises the differences between system programs and application programs (user programs).

System Programs User Programs
Used for operating computer hardware and very common system-usage purposes Used to perform specific user-related tasks
Typically comes with the OS Installed according to user requirements
Commonly runs in the background, require minimal to no user interactions Requires interactions with users

OS Design and Implementation

There’s no known ultimate solution when it comes to OS design. Internal structures of known operating systems can vary widely.

When one design an OS, it might be helpful to consider a few known things.

User and System Goals

Start by defining goals:

  1. User goals: OS should be convenient to use, easy to learn, reliable, safe, fast
  2. System goals: The system should be easy to design, implement, and maintain; and it should be flexible, reliable, error free, and efficient.

Policy and Mechanism Separation

Know the difference between policy and mechanism and separate them:

  1. Policy: determines what will be done
  2. Mechanism: determines how to do something

The separation of policy and mechanism is important for flexibility:

  • Policies are likely to change across places or over time.
  • In the worst case, each change in policy would require a change in the underlying mechanism.

A general mechanism insensitive to changes in policy would be more desirable. A change in policy would then require redefinition of only certain parameters of the system.

Take for example: a mechanism for giving priority to certain types of programs over others. If the mechanism is properly separated from policy, it can be easily tweaked based on user requirements:

  • Support a policy decision that I/O-intensive programs should have priority over CPU-intensive ones
  • Or support the opposite policy whenever appropriate. Either way, no change in the instructions need to be made.

OS Structures

Once an operating system is designed, it must be implemented. Because operating systems are collections of many programs: kernel, system programs, interface, etc, written by many people over a long period of time, it is difficult to make general statements about how they are implemented2.

Below are a few common OS structures.

Monolithic Structure

A monolithic kernel is an operating system architecture where the entire operating system is working in kernel space. It can operate with or without dual mode.

Without Dual Mode

The figure below (screenshot from SGG book) shows the structure of MS-DOS, one of the simplest OS made in the early years:

  • The interfaces and levels of functionality are not well separated (all programs can access the hardware) - i.e: at the time, MS-DOS was written for the Intel 8088 architecture, which has no mode bit and therefore no dual mode.
  • For instance, application programs are able to access the basic I/O routines to write directly to the display and disk drives.
  • Such freedom leaves MS-DOS vulnerable to errant (or malicious) programs, causing entire system crashes when user programs fail.

With Dual Mode

The early UNIX OS was also simple in its form as shown below. In a way, it is layered to a minimal extent with very simple structuring.

The kernel provides file system management, CPU scheduling, memory management, and other operating-system functions through system calls. That is an enormous amount of functionality to be combined into one level.

  • Pros: distinct performance advantage because there is very little overhead in the system call interface or in communication within the kernel.
  • Cons: difficult to implement and maintain.

Other examples of monolithic OS with dual-mode: BSD, Solaris

Layered Approach

The operating system is broken into a many number of layers (levels). The bottom layer (layer 0) is the hardware; the highest (layer N) is the user interface. The figure below shows a layered approach (layer names for illustration purposes). The programs in layer N rely on services ONLY from the layer below it.

Pros:

  • Simple to construct and debug
  • Each layer is implemented only with operations provided by lower-level layers.
  • A layer does not need to know how these operations are implemented; it needs to know only what these operations do.
  • This abstracts and hides the existence of certain data structures, operations, and hardware from higher-level layers.

Cons:

  • Appropriately defining the various layers, and careful planning is necessary.
    • If we are met with bugs in our program, we debug our program and not our compiler
    • We mostly assume that the layers beneath us are already made correct
    • Sometimes, this assumption is not always true and difficult to maintain with the growing size of the OS. Some OS is shipped with bugs on its lower layers that are very difficult for users to debug.
    • Patches and updates are periodically given to fix these bugs.
  • They tend to be less efficient than other types.
    • For instance, when a process running in user mode executes an I/O operation, it executes a system call that is trapped to the I/O layer, which calls the memory-management layer, which in turn calls the CPU-scheduling layer, which is then passed to the hardware.
    • At each layer, the parameters may be modified, data may need to be passed, and so on.
    • Each layer adds overhead to the system call.
    • The net result is a system call that takes longer than does one on a non layered system.

Example: Windows NT (the later version is actually a hybrid OS, combining between layered and monolithic aspects and benefits)3

Microkernel

A microkernel is a very small kernel that provides minimal process and memory management, in addition to a communication facility.

This method structures the operating system by removing all nonessential components from the kernel and implementing them as system and user-level programs. The result is a smaller kernel that does only tasks pertaining to:

  1. Inter-Process Communication,
  2. Memory Management,
  3. Scheduling

For instance, if a user program wishes to access a file, it must interact with the file server.

  • The client program and service never interact directly.
  • Rather, they communicate indirectly by exchanging messages with the microkernel as illustrated below:

Pros: extending the operating system easier. All new services are added to user space and consequently do not require modification of the kernel.

Cons: suffer in performance increased system-function overhead due to frequent requirement in performing context switch.

Example: Mach, Windows NT (first release was a microkernel).

Hybrid Approach

Hybrid kernels attempt to combine between microkernel and monolithic kernel aspects and benefits.

Example: macOS is partly based on microkernel + monolithic approach (image taken from SGG):

  1. Mach provides: IPC, scheduling, memory management
  2. BSD provides: CLI, file system management, networking support, POSIX APIs implementations

Java Operating System (JX)

The JX OS is written almost entirely in Java. Such a system, known as a language-based extensible system, and runs in a single address space (no virtualisation, no MMU), as such it will face difficulties in maintaining memory protection that is usually supported by hardwares in typical OS.

Language-based systems instead rely on type-safety4 features of the language. As a result, language-based systems are desirable on small hardware devices, which may lack hardware features that provide memory protection. Since Java is a type-safe language, JX is able to provide isolation between running Java applications without hardware memory protection.

This is called language based protection, where system calls and IPC in JX does not require an address-space switch. In short, JX runs in a single address space.

The architecture of the JX system is illustrated below (simplified representation5):

  • JX organizes its system according to domains.

  • Each domain represents an independent JVM (Java Virtual Machine): _ JVM is an abstract virtual machine that can run on any OS _ There’s one instance of JVM per Java application _ JVM provides portable execution environment for Java-based apps _ It maintains a heap used for allocating memory during object creation and threads within itself, as well as for garbage collection.

  • Domain zero is a microkernel responsible for low-level details, such as system initialization and saving and restoring the state of the CPU.
    • Domain zero is written in C and assembly language; all other domains are written entirely in Java.
    • Communication between domains occurs through a specific mechanism called portals
  • Protection within and between domains relies on the type safety of the Java language.
    • However, since domain zero is not written in Java, it must be considered trusted (built by trusted sources)

Summary

The figure below shows the summary of various OS structures.

For layered architecture, note that the only difference with hybrid and microkernel structure is that programs at level N relies ONLY on services provided by programs at one level below it.

Appendix

If you’d like to expand your knowledge beyond regular OS, you may have further read about virtualization and containerization.

Virtualisation

We can run any arm or intel-based OS on arm or intel-based hardware, e.g: Dual boot. An extension to that is virtualization, where you can run any OS on any OS (typically the same architecture).

A hypervisor is essentially an emulator computer software, firmware, and hardware that runs virtual machines. Examples of hypervisors: VMWare, VMWorkstation, VirtualBox, Parallel Desktop for Mac, etc

Containerization

Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and ship it all out as one package. Containers are not the same as Virtual Machines, and are generally faster to use. You can read more about the differences between the two here.

Note: “Host OS” in the picture above assumes that it is UNIX-based POSIX compliant OS. If you run Docker on Windows/Mac, it will download a Hypervisor + Guest Linux too before you can run the Docker Engine.

Example of softwares that support containerisation: Docker.

  1. tty itself is a command in Unix and Unix-like operating systems to print the file name of the terminal connected to standard input. If you open multiple terminal windows in your UNIX-based system and type tty on each of them, you will be returned with different ids. You may use write to communicate across terminal windows 

  2. Early operating systems were written in assembly language. Now, although some operating systems are still written in assembly language, most are written in a higher-level language such as C or an even higher-level language such as C++. Actually, an operating system can be written in more than one language: (1) The lowest levels of the kernel might be assembly language, and then (2) higher-level routines might be in C, and finally (3) system programs might be in C or C++, in interpreted scripting languages like PERL or Python, or in shell scripts. In fact, a given Linux distribution probably includes programs written in all of those languages. 

  3. Figure taken from Wikipedia 

  4. The Java language is designed to enforce type safety. This means that programs are prevented from accessing memory in inappropriate ways. Every section of memory is part of some Java object that belongs to some class. For example, a calendar-management applet might use classes like Date, Appointment, Alarm, and GroupCalendar. Each class defines both a set of objects and operations to be performed on the objects of that class (explanation taken from Securing Java (ISBN: 047131952X), section 10) 

  5. Image taken from https://webmobtuts.com/news-events/what-is-the-jvm-introducing-the-java-virtual-machine/