commit c0815b9be09d0cab30ac4a1798e78c82f1fa2440
parent 9f871f3eb5571cb33b53732fa0d0245a2eb6620a
Author: Andrew Laack <andrew@laack.co>
Date: Sun, 1 Mar 2026 21:01:11 -0600
Operating systems notes + package manager notes
Diffstat:
10 files changed, 178 insertions(+), 1 deletion(-)
diff --git a/docs/ConditionVariables.md b/docs/ConditionVariables.md
@@ -0,0 +1,28 @@
+# Condition Variables
+
+**Source:** CS 6200
+
+**Chapter:** P2L2
+
+**Definition:** Condition variables are used with [mutexes](Mutex.md), and provide the ability to condition waits.
+
+## Example
+
+An example of this would be waiting for a list to be full to print it. You would first acquire the lock to print and call Wait(m, listFull). The listFull condition variable will be set to true once the insertion logic completes, filling up the list. Note that the Wait function must unlock the mutex and re-aquire the lock once the condition variable is true because insertion and printing are assumed to be using the same mutex for accessing the list.
+
+A real implementation would likely use Signal(listFull) to send the message to the waiting logic that it may proceed.
+
+## API
+
+Common API
+
+- Condition type
+ - list of waiting threads
+ - reference to mutex
+ - ...
+- Wait(mutex, cond)
+ - mutex automatically locked and unlocked while waiting for cond
+- Signal(cond)
+ - notify only one thread waiting on condition
+- Broadcast(cond)
+ - notify all waiting threads
diff --git a/docs/Flatpak.md b/docs/Flatpak.md
@@ -0,0 +1,12 @@
+# Flatpak
+
+**Source:** [https://docs.flatpak.org/en/latest/sandbox-permissions.html?pubDate=20260219](https://docs.flatpak.org/en/latest/sandbox-permissions.html?pubDate=20260219)
+
+**Definition:** Flatpak is a system for building, distributing, and running sandboxed desktop applications.
+
+## Terms
+
+- A Flatpak application is installed with the Flatpak command and serves as an executable programs.
+- A runtime, or platform, is an integrated environment that provides basic utilities for a Flatpak application.
+- A baseapp is a set of additoinal libraries, like electron, for Flatpak applications that require more than a basic runtime.
+- A Flatpak bundle is a single file format containing a Flatpak application or runtime.
diff --git a/docs/FreeSoftware.md b/docs/FreeSoftware.md
@@ -1,5 +1,10 @@
# Free Software
+## Distribution Approaches
+
+- [Flatpak](Flatpak.md)
+- [Homebrew](Homebrew.md)
+
## Note Taking
### Graphical
diff --git a/docs/Homebrew.md b/docs/Homebrew.md
@@ -0,0 +1,7 @@
+# Homebrew
+
+**Source:** [https://docs.brew.sh](https://docs.brew.sh)
+
+**Definition:** Homebrew is a package manager requiring only glibc and gcc.
+
+One benefit of Homebrew is it should support macOS, Linux, and WSL in a unified way. Despite this, the consensus seems to be running Homebrew on Linux is a bad idea because distribution package managers often result in dependency versioning issues.
diff --git a/docs/Mutex.md b/docs/Mutex.md
@@ -0,0 +1,15 @@
+# Mutex
+
+**Source:** CS 6200
+
+**Chapter:** P2L2
+
+**Definition:** A mutex is a mutual exclusion mechanism that only allows one thread to perform an operation on some data at a given time.
+
+## Specifics
+
+Operating Systems and threading libraries support mutexes, which work as a lock.
+
+A common data structure to represent mutexes is locked (boolean), the owner, and blocked threads (not necessarily ordered). When a thread tries to acquire a lock it will be blocked until the lock is released by the owner. Additionally, a thread must unlock the lock after exiting the critical section otherwise all waiting threads will be blocked indefinitely.
+
+The code section protected by the lock is called the **critical section**. This code should correspond to code can only safely be executed by one thread at a time.
diff --git a/docs/OperatingSystems.md b/docs/OperatingSystems.md
@@ -15,7 +15,6 @@
- Abstracts hardware details with syscalls
- Don't want to worry about disk sectors / blocks in software
-
## Links
### CS6200: Graduate Introduction to Operating Systems
@@ -49,3 +48,7 @@
- [I/O Queue](IOQueue.md)
- [Inter Process Communication](InterProcessCommunication.md)
- [Thread](Thread.md)
+- [Mutex](Mutex.md)
+- [ConditionVariables](ConditionVariables.md)
+- [Pthread](Pthread.md)
+- [POSIX](POSIX.md)
diff --git a/docs/POSIX.md b/docs/POSIX.md
@@ -0,0 +1,7 @@
+# POSIX (Portable Operating System Interface)
+
+**Source:** CS 6200
+
+**Chapter:** P2L3
+
+**Definition:** POSIX is a group of standards for maintaining compatibility between operating systems.
diff --git a/docs/ProcessControlBlock.md b/docs/ProcessControlBlock.md
@@ -22,6 +22,14 @@
The PCB is created when a process is started, and during runtime certain fields may be updated.
+### Hard and Soft Process State
+
+When using multiple kernel level threads for a singular process, there is hard process state and light process state in the PCB. The hard process state is state information relevant for all threads, like the virtual address mapping. There is also soft state, like the registers for a given thread, which is only applicable to a specific thread.
+
+By using multiple data structures to represent the PCB, they are easier to share between threads and they are easier to manage from user-level threading libraries, which only have to upade a smaller portion of the state.
+
+Most operating systems today use multiple data structures to represent the PCB.
+
## Runtime
Assume process P1 is running and P2 is idle. The CPU registers are currently populated with data from P1. When the OS decides to interrupt P1's execution it performs the following operations:
diff --git a/docs/Pthread.md b/docs/Pthread.md
@@ -0,0 +1,7 @@
+# PThread ([POSIX](POSIX.md) Thread)
+
+**Source:** CS 6200
+
+**Chapter:** P2L3
+
+**Definition:** PThreads are POSIX threads which have specified syntax and semantics for operations.
diff --git a/docs/Thread.md b/docs/Thread.md
@@ -9,3 +9,88 @@
Threads are part of the same virtual address space as the process that contains them, but each thread has a per-thread execution context, contained within the process control block.
Threads have a non-zero overhead, but they have a lesser overhead than processes because they don't require their own address spaces, only their own execution contexts. Additionally, threads can use shared variables in the same address space for communication between threads which is cheaper than the IPC alternatives.
+
+## Single CPU Benefits
+
+If idle time is greater than the cost of context switching twice it makes sense to context switch to another thread (or process). Since creating the new virtual to actual address space mapping is one of the most costly parts of context switching between processes, using threads can be more efficient than using processes.
+
+## Needed to Support Threads
+
+### Data Structure
+
+A thread type should include a thread identifier, register values (PC, SP, registers), the stack, and additional attributes. These additional attributes can be used by a thread management system to better schedule thread execution.
+
+### Creation / Management
+
+Below is one solution to thread management / creation:
+
+- Fork(proc, args)
+ - This call creates a thread that will execute the procedure proc with the arguments args
+ - This is **not** the Unix syscall Fork.
+ - The new thread data structure is initialized with PC = proc and stack = args
+- Join(thread)
+ - When a parent thread calls join with the child thread ID, the parent will be blocked until the child completes
+ - Join will return the results from the child to the parent thread in a well-defined location in memory
+ - All resources allocated for the child will be freed
+
+### Synchronization
+
+- [Mutexes](Mutex.md) are useful for synchronizing access to memory used by different processes at the same time.
+
+## Kernel and User-Level
+
+### Kernel
+
+Kernel level threads are managed by the kernel and the kernel level scheduler. As such, it is up to the Kernel to do the mapping to physical CPU cores.
+
+### User-Level
+
+User-level threads are implemented by software libraries.
+
+#### One-to-one
+
+In the one-to-one model user-level threads are mapped directly to kernel level threads. This means the OS can see the user-level threads and can do synchronization.
+
+The drawback is that each operation must go through the kernel via a syscall (can be slow). Also, since we rely on the kernel, we are limited by the kernel level policies (e.g. limits on # of threads or scheduling options).
+
+#### Many-to-one
+
+User level threads are all mapped to the same kernel level thread. This is implemented by a threading library.
+
+The benefit is portability because everything is done in the library, without concern for the underlying kernel. We also don't have to do lots of costly syscalls.
+
+A drawback is the OS doesn't know about these threads so blocking calls will block the entire process.
+
+#### Many-to-many
+
+This is a system where some user-level threads are mapped to some kernel level threads. This can take advantage of the benefits from both approaches above.
+
+Despite this, more complex coordination between the user-level thread manager and the kernel must be implemented.
+
+## Patterns
+
+### Boss-worker
+
+The boss is responsible for assigning work to the workers. The workers are then responsible for completing their subset of the work (this work can be generalized or specialized to take advantage of locality). A downside of this is the throughput of the system can be limited by the boss thread.
+
+We often implement this with a queue where the boss adds to the queue and the workers pop from the queue. This requires synchronization, but limits the work required by the boss because it doesn't have to track the state of each worker.
+
+With this pattern, we have a pool of workers (threads) which can be defined statically or dynamically.
+
+### Pipeline
+
+Threads are assigned to a subtask of the system. The entire task is then done by a pipeline of threads.
+
+This takes advantage of locality and allows processing many tasks at the same time, but the throughput is limited by the weakest link in the pipeline. To combat these inequalities, we can use a thread pool to increase the threads for a given step.
+
+### Layered
+
+Each layer has a group of related subtasks. Each full task must pass up and down through all layers as the logical groupings of subtasks needn't be ordered.
+
+## Thread Management
+
+Consider a process with 4 user-level threads which will only be running on 2 kernel-level threads at any given time. When the process starts, the kernel will give the process some number of kernel-level threads. The process can then request another kernel level thread with the `set_concurrency` syscall from the kernel.
+
+If the above process blocked both threads with IO operations, it would be useful for the other user-level threads to step in and execute their functionality instead of blocking both kernel level threads. To do this, the kernel can send a signal to the user-level library, informing it the threads have blocked. The library can then look at it's run queue and request more kernel level threads to continue execution. Once IO completes, the kernel might notice one of the threads has remained idle for some time. As such, the kernel may notify the user-level library that the thread may no longer be used by the process.
+
+**Pinning:** is when a user-level thread requests to be associated with a singular kernel-level thread.