My Intro
I have been wanting to take this class since I started this program way back in 2022. I’ve also been scared of it, because other than CS1 which was in C++ which I took exactly 10 years ago I’ve only ever written code in Python (okay a little C# in VGAI but that doesn’t count). So to prep for this I’ve been following beej’s guide to c which has been a nice prep for at least thinking about having to care about memory.
Reading through it, doing a bit of code workshops, getting used to compiling (gasp) things, etc has been a good time, though I won’t write too much about that. That being said, I haven’t finished the whole guide, I’m about halfway through, so this is definitely going to be a learning experience for me.
I see the multitude of footguns with which C provides me, and I’ve definitely got a couple holes in my feet just from my little toy scripts to start getting things to run. So wish me luck everyone. I’ll mostly just do lecture notes in here, because I believe it’s prohibited to talk about the projects anywhere that’s not official OMSCS channels.
Part 1 - Introduction to Operating Systems
An operating system is a piece of software that abstracts and arbitrates the underlying hardware of a computer system.
All OSes provide many abstractions and arbitration methods to interact with the underlying hardware.
Visual Metaphor
“An operating system is like a toy shop manager”
It is like this because:
- Directs resources like employees/parts/tools
- Enforces how employees work in policies like safety/fairness
- Navigate complex tasks (this feels like a stretch) by simplifying operations and optimizing performances for all the underlying resources
The operating system:
- Directs operational resources like PCU, memory, peripheral devices
- Enforces working policies like fair resource access and limits to resource usage
- Mitigates difficulty of complex tasks by abstracting hardware details (system calls)
What is an operating system?
It is software that handles interactions with hardware like CPU, GPU, Memory, USB, Networks, and Disks. On the other side of the operating system you have applications that would like to take advantage of that hardware.
So the operating system acts as a common interface between lower level hardware, and higher level applications. It hides hardware complexity. It manages resources, ensuring memory isn’t over-used, disk space is not too low, and bus channels are not flooded.
Additionally it provides isolation and protection so that applications can not cause trouble with each other by doing something silly like one app modifying memory that another app might be using.
Official Definition
An operating system is a layer of systems software that:
- Directly has privileged access to the hardware
- Hides hardware complexity
- Manages hardware on behalf of one or more applications
- Ensures applications are isolated and protected from one another
Operating Systems Examples
Desktop OSes
- Microsoft Windows
- Unix based
- Ubuntu, ARCH, MACOS, CentOS, etc
Embedded OSes
- Android
- iOS
- Symbian
Each operating system makes some unique choices in their design and implementation. This class cares about Linux, Ubuntu specifically.
OS Elements
Abstractions
Directly relate to hardware usually, provides abstracted way to read hardware.
- process
- thread
- file
- socket
- memory
Mechanisms
Mechanisms are tools that the OS uses to handle those abstractions
- create
- schedule
- open
- write
- allocate
Policies
Methods in which the OS uses its mechanisms and abstractions.
- Least recentuly used
- Early deadline first, etc
So policies employ mechanisms which are built on abstractions. An example is memory management which employs least recently used policy, and in doing so allocates, writes, etc using the memory abstraction.
OS Design Principles
Separation of Mechanism & Policies
- Implement flexible mechanisms to support many policies
Optimize for commons case
- Where will OS be used
- What will the user want to be able to execute
- What are the workload requirements
User/Kernel Protection Boundary
The OS must have special privileges to have direct access to the hardware.
Generally this is broken into user-level privileges and kernel-level privileges. Operating systems need kernel-level privileges, where applications generally have user-level privileges (except for some anticheat things in games like valorant or Battlefield 6).
Traversing from app to hardware is via the OS, and the OS can perform checks to make sure illegal things aren’t happening, and provides the system calls to provide tools for the apps to use. Things like:
- open file
- send (Socket)
- allocate memory
Typical System Call process
- User process starts execution
- User process calls system call (non-kernel level)
- System call is executed (kernel leve) and returns result
- Process result of system call, continue processing
To make a system call you must:
- Write arguments
- Savel relevant data in well defined location
- make system call, providing necessary info
Crossing User/Kernel boundary
Crossing the boundary is a requirement, for apps to actually take advantage of the hardware it is running on.
The OS is responsbile for making sure the apps can’t do anything catastrophic to the machine. This includes things like illegal instructions, memory access, and maintaining appropriate privileges. It is also responsible for dealing with traps on illegal instructions, and deciding what and how to handle them.
Doing the user-kernel transition does take some time, anywhere from 50-100 ms on a 2ghz machine.
It also switches the locality, from a fast in-memory cache, to a potentially slower cold memory storage.
It costs a lot to cross the boundary!
OS Services
The OS provides tools for apps via things called services.
The scheduler helps schedule work to be done by the cpu.
The memory manager makes sure that memory is appropriately assigned.
Block device drive helps to interact with devices attached to the system.
The file system is a service that allows apps to maintain persistent files on hard disks.
These services are all available via system calls, in different flavors based on the OS you’re using.
Operating System Organizations
Monolithic OS
All potential services are built into the OS directly. Could have mem management, many different filesystems for different purposes, etc.
Pros:
- Batteries are all included
- Allows for inlining, compile time optimizations, etc
Cons:
- Customization is low
- Portability is low
- Requires more memory
- etc
It’s not great.
Modular OS
This OS has the basic services as a part of it from the core but then many modules and interfaces can be added as needed.
The OS makes this possible by specifying interfaces that are required to interact with the hardware. So given that documentation, we can make a module for ourself that is optimized for a specific task.
Pros:
- Easier to maintain
- Smaller footprint
- Less resource intensive
Cons:
- indirection can impact performance (have to go through the interface a lot)
- Maintenance can still be an issue (even though it’s a pro lol)
Generally modular is preferred and is much more commonly used.
Microkernel OS
Only requires the most basic primitives at OS level. Address spaces, threads, etc could be included but things like file systems, disk drivers, and db stuff runs outside of kernel level but at user level.
You can imagine this requires lots of inter-process communications, as well as lots of user-kernel barrier traversing. Inter Process Communication is therefore included in microkernel OSes.
Pros:
- Size is very small
- Verifiability
Cons:
- Portability is bad because it’s so custom
- Very complex software development
- Cost of crossing user/kernel boundary
Linux Architecture
Linux uses a modular approach with a specific organization.
Mac OS Architecutre
Uses a core microkernel which gives primitive systems, but then has BSD that interacts with rest of apps