Architectural style
Every system has an architecture and SerenityOS is no exception. As an operating system running on x86, SerenityOS has a layering architecture consisting of three layers: kernel, system function, and applications. The kernel controls the hardware of the computer and resides at the core of the architecture. System calls act as the interface between the kernel and applications. In the beginning, SerenityOS relied on a few external libraries. However, it has gradually gotten rid of them and developed by itself instead.
The advantages of this type of architectural style include simplicity, extensibility, and transparency.
Containers View
According to the definition of the C4 model, the container model is the zoom-in version of the overall system boundary. A “container” is something like a server-side web application, single-page application, desktop application, mobile app, database schema, file system, etc. Essentially, a container is a separately runnable/deployable unit (e.g. a separate process space) that executes code or stores data.
However, due to the particularity of being an operating system, there are no parts of SerenityOS that run separately. Thus we use containers view to show the high-level shape of the software architecture and how responsibilities are distributed across it. The way in which containers communicate with one another is also shown in it.
Below is the description of elements in the container diagram.
Kernel
As the heart of SerenityOS, the kernel is the central part of the OS which interacts directly with the hardware of the x86 computer. The kernel of SerenityOS supports both x86 (32-bit) and x86_64 (64-bit) and pre-emptive multi-threading.
The hardware of a typical computer contains CPU, ALU, memory, IO devices. Those resources can’t be utilized efficiently and easily without the help of OS. In SerenityOS, the main functions of the kernel are:
- The hardware of the computer like RAM, keyboard, mouse, printers, etc. is controlled by the Kernel.
- The Kernel is responsible for IPv4 stack with ARP, TCP, UDP, and ICMP protocols.
- It schedules and manages different processes and executes the different operations and tasks.
- It manages and maintains the ext2 file system.
- It is also responsible for error handling.
- The kernel performs the different input and output services.
- The kernel also has sub-components like drivers to control hardware peripherals, boot code, header files.
- Purgeable memory management, Filesystem notifications are also performed by the kernel.
- CPU and memory profiling is performed by the kernel.
Service Call
In SerenityOS, the service call is the programmatic way in which a user application requests a service from the kernel of the operating system. A service call is a way for programs to interact with the operating system. When an application makes a request to SerenityOS’s kernel, it makes a service call. Service call provides the services of the operating system to the user application through Application Program Interface(API). As the only entry points into the kernel system, all applications must use system calls to access hardware/software system resources. There are five types of service calls in SerenityOS, which are listed and exemplified as follows:
-
Process control: end, abort, create, terminate, allocate, and free memory.
-
File management: create, open, close, delete, read a file, etc.
-
Device management
-
Information maintenance
-
Communication
Applications
The applications layer is the least privileged in the architectural view of SerenityOS. Applications running on your computer have to invoke service calls to carry out specified tasks. Examples of applications include graphical file managers, games, sysadmin tools, etc. Users generally develop or operate applications in SerenityOS.
Components view
In the above, we will continue to explore the software architecture of SerenityOS based on the container view. Since the analysis process of the C4 model is a step-by-step enlargement and analysis, we choose to enlarge the kernel container in the container here and analyze the relationship between the container and the other two containers, system call and application.
The container: Kernel is divided into six components, namely filesystem, Timer and Interrupt, Memory Management, I/O devices, Thread Management.
The container: Application is divided into many components, namely Web Browser, E-mail client, HackStudio(IDE), Help Systems, Shell, and many other Unix-support apps & games.
The container: System Call is divided into five components, namely System Sevices, process Call, communication Call, Filesystem Call, exception Call.1
The figure mainly shows the relationship between components and container: Application and container: system call. I will analyze the dependencies between components in text form. First of all, the file system is the core existence in the kernel. In this system, any element in the system can be regarded as a member of the file system, so the other five components will interact with the file system, apply for permissions, read and write, or make configuration changes. I/O device management needs the assistance of Thread Management for I/O scheduling to achieve a shorter system response time, and at the same time, it needs to apply to memory management to access caches and buffers. System service is a number of network services for the system, such as HTTP, DNS, Timer provides clock function and works with interrupts. Thread Management is mainly used for multi-threaded scheduling work, improving the thread work efficiency of each component, and improving the efficiency and performance of the kernel together with memory management.
There will be shared components in the three multiple containers, and System Services is both a System call component and an Application component.
Connector View
Between the application and kernel function, the connector that enables the applications to call the kernel function –system call, are the libraries provided in the userland.
As shown in the figure above, all the libraries provided to build applications are written in C++ without third-party code, therefore the data structures are also provided in the AK library.
For instance, if an image viewer application needs to display an image, the system call functions to build a graphic user interface are provided in LibGUI to build an outer box, the data structure in AK library will load the image into some data structure and load it into the RAM.
The applications are not able to directly interact with the kernel function for security consideration. Directly interacting with the kernel function is not protected with some limitation or protection measurement that is coded in the system call function. If an application uses the kernel function directly, for example, write an oversize data into a buffer that only has 256byte capacity, it will overflow and overwrite some data or instruction of next instructions in the stack.
The system call libraries provide that application the ability to use the kernel function with extra security and protection to the hardware and whole operating system.
Development view
The Development Viewpoint describes the architecture that supports the software development process. This is an optional level of detail and is often available on-demand from tooling such as IDEs. The primary elements are Code elements (e.g. classes, interfaces, objects, functions, database tables, etc) within the component in scope. And the Intended audience is Software architects and developers.
In SerenityOS, the Development can be divided into 7 main sections:
-
Kernel: The main kernel(Container: Kernel) of the OS, which is the most relevant
-
Ports: Function ports for System calls and system services
-
Meta: Include Azure, Cmake, Zsh, and many other aip for cloud developments
-
Toolchain: Tools for debugging. bug tracking for C++ programming
-
Documentation: Documentation for Users, Developers and Customers
-
Userland: UI design, theme, fonts, color desgin
-
Base: Base Code for the OS
-
Test: Test cases for debugging
In the C4 model, we scroll in the ‘map’ of the software architecture, and now arrives the layer of Development view. We will take a look inside the component: Browser, which is inside the Container: Application, to find out how this project organizes the code in functional modules and its coding Standardization.
The SerenityOS Browser uses a multi-process architecture to improve stability and security in the face of arbitrary web content. [^ Github]
Every instance of the Browser application can have one or more tabs open. Each tab has a unique WebContent service process spawned on its behalf.
Two important aspects of web browsing are further separated from the WebContent process: network requests and image decoding segregated to the RequestServer and ImageDecoder processes respectively.
All processes are aggressively sandboxed using the pledge()
and unveil()
mechanisms. Furthermore, all processes except Browser run as an unprivileged user, separate from the primary logged-in desktop user.
To get a fresh WebContent process, anyone with the suitable file system permissions can spawn one by connecting to the socket at /tmp/portal/webcontent
. This socket is managed by SystemServer and will spawn a new instance of WebContent for every connection.
The same basic concept applies to RequestServer and ImageDecoder as well, except that those services are spawned by WebContent as needed, not by Browser.
Runtime view
Runtime view will explain the interaction between components of the SerenityOS and the users.
Serenity is an operating system where most of the application scenarios occur in the interaction between the user and the system.
The user enters instructions for the desired operation, and the application shell interprets the instructions into the Kernel and makes system calls. The six components of the kernel interact in the Kernel and work together to achieve tasks such as process and memory management, disk storage, etc.
As a commitment to creating a complete operating system without third-party Runtime dependency, it does not use the standard Libc++/Libstdc++, but relies on custom standard libraries (not STL)2
Quality Attributes
In Essay 1, we have introduced four quality attributes: Functionality, Usability, Aesthetics, and Consistency. This section will describe how the architecture realizes these key quality attributes, and how potential trade-offs between them have been resolved. This section will describe how the architecture realizes these key quality attributes, and how potential trade-offs between them have been resolved.
Functionality: The functionality of an operating system is realized by the ability to respond correctly to the user’s instructions. As a Unix-like System, the Shell with libc and I/O redirection on the Serenrity OS architecture helps to interpret user commands and execute them using the kernel, which has achieved the functionality of the OS.
Usability and Aesthetic: For users of the system, Serenity OS has a comprehensive build guide on GitHub. The developers have also created a Discord channel to help users run and ask questions about the system for all.
Consistency: An internal quality attribute. Designed to keep the implemented system consistent with the intended architecture. To implement this key quality Attribute, developers upload the same style of code in GitHub and have a clear Code submission policy in the description3.
Trade-off: These quality attributes are complementary, with aesthetics being an enhancement to usability and attracting more users interested in retro interfaces.
API Design Principles Applied
-
Unified Coding Language: The code style of submission is required to write in idiomatic SerenityOS C++20.
-
The variable name and library name are named in an intuitive, understandable, and uniform way. For example, the libraries of building Graphic user interface, Digital Signal Processing, and ELF file handling are named with LibGUI, LibDSP, and LibELF.
The function name is like short sentences such as and will be renamed by the project monitors into a more understandable way. Rename ServerConnection() to ConnectToServer() and rename ClientConnection() to ConnectionFromClient().
-
Due to the purpose of being free from third-party code, C++ templates and data structures such as stack, heap, linked list are all implemented in the AK containers and all codes are required to use the AK containers.
-
Use nested hierarchy: From kernel functions, system calls, to the userland application and utilities are coded with different hierarchies and put in different folders.
For example, the kernel function Scheduler is put in the ‘’/Kernel’ folder, the ‘copy’ shell command is put in the ‘/Userland/Utilities’ folder and the browser is put in the ‘/Userland/Applications’ folder.
-
Version and documentation: the version and help document of the applications and utilities can be checked with the command line in the shell. And there is a helper document that can be accessed directly on the desktop. For example, you can check the version and document of the ‘cat’ command in the shell with ‘cat –version’ and ‘cat –help’, the help document can also be found through the helper document on the desktop of the OS.4
References
-
System Call. from https://man.serenityos.org/man2/index.html ↩︎
-
Anastasia Kazakova. Talking to SerenityOS Contributors About a Scratch-built C++ Developer’s Playground in Modern C++ Retrieved March 2, 2022 https://blog.jetbrains.com/clion/2021/11/talking-to-serenityos-contributors/ ↩ ↩︎
-
SerenityOS. Github for SerenityOS. Retrieved February 27, 2022, from https://github.com/SerenityOS/serenity ↩︎
-
Policy. Github Contribute Policy. Retrieved February 27, 2022, from https://github.com/SerenityOS/serenity/blob/master/CONTRIBUTING.md#issue-policy ↩︎