<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Operating Systems on Software Engineering Learning Paths</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/</link><description>Recent content in Operating Systems on Software Engineering Learning Paths</description><generator>Hugo</generator><language>en</language><atom:link href="https://kyngo.github.io/learning-paths/paths/operating-systems/index.xml" rel="self" type="application/rss+xml"/><item><title>Processes &amp; Threads</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/01-processes-threads/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/01-processes-threads/</guid><description>&lt;h1 id="processes--threads"&gt;Processes &amp;amp; Threads&lt;a class="anchor" href="#processes--threads"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A &lt;strong&gt;process&lt;/strong&gt; is the OS&amp;rsquo;s abstraction for a running program. It encapsulates the program&amp;rsquo;s code, data, and execution state into an isolated unit that the OS can manage, schedule, and protect.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-process-model"&gt;The Process Model&lt;a class="anchor" href="#the-process-model"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A process is more than just executing code. It includes:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Component&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Text segment&lt;/td&gt;
					&lt;td&gt;The compiled program instructions&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Data segment&lt;/td&gt;
					&lt;td&gt;Global and static variables&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Heap&lt;/td&gt;
					&lt;td&gt;Dynamically allocated memory (grows upward)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Stack&lt;/td&gt;
					&lt;td&gt;Function call frames, local variables (grows downward)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Registers&lt;/td&gt;
					&lt;td&gt;CPU register state (PC, SP, general-purpose)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Open files&lt;/td&gt;
					&lt;td&gt;File descriptors the process holds&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Credentials&lt;/td&gt;
					&lt;td&gt;User ID, group ID, permissions&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="process-memory-layout"&gt;Process Memory Layout&lt;a class="anchor" href="#process-memory-layout"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;High addresses
┌──────────────────┐
│ Stack │ ← grows downward
│ ↓ │
├──────────────────┤
│ │
│ (free space) │
│ │
├──────────────────┤
│ ↑ │
│ Heap │ ← grows upward
├──────────────────┤
│ BSS (uninit) │
├──────────────────┤
│ Data (init) │
├──────────────────┤
│ Text │ ← program code
└──────────────────┘
Low addresses&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="process-states"&gt;Process States&lt;a class="anchor" href="#process-states"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every process transitions through a well-defined set of states:&lt;/p&gt;</description></item><item><title>CPU Scheduling</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/02-cpu-scheduling/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/02-cpu-scheduling/</guid><description>&lt;h1 id="cpu-scheduling"&gt;CPU Scheduling&lt;a class="anchor" href="#cpu-scheduling"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The &lt;strong&gt;CPU scheduler&lt;/strong&gt; decides which ready process gets the CPU next. This decision directly impacts system responsiveness, throughput, and fairness. A good scheduler makes a fast machine feel fast; a bad one makes it feel sluggish regardless of hardware.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="scheduling-criteria"&gt;Scheduling Criteria&lt;a class="anchor" href="#scheduling-criteria"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Criterion&lt;/th&gt;
					&lt;th&gt;Definition&lt;/th&gt;
					&lt;th&gt;Optimize&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;CPU utilization&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Percentage of time CPU is busy&lt;/td&gt;
					&lt;td&gt;Maximize&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Throughput&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Processes completed per time unit&lt;/td&gt;
					&lt;td&gt;Maximize&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Turnaround time&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Total time from submission to completion&lt;/td&gt;
					&lt;td&gt;Minimize&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Waiting time&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Time spent in the ready queue&lt;/td&gt;
					&lt;td&gt;Minimize&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Response time&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Time from submission to first response&lt;/td&gt;
					&lt;td&gt;Minimize&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These criteria often conflict. Maximizing throughput may hurt response time; optimizing for interactive responsiveness may reduce batch throughput.&lt;/p&gt;</description></item><item><title>Memory Management</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/03-memory-management/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/03-memory-management/</guid><description>&lt;h1 id="memory-management"&gt;Memory Management&lt;a class="anchor" href="#memory-management"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The OS must multiplex physical memory among many processes while giving each the illusion of a large, private, contiguous address space. Memory management handles allocation, protection, and efficient use of RAM.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="address-spaces"&gt;Address Spaces&lt;a class="anchor" href="#address-spaces"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every process operates in its own &lt;strong&gt;virtual address space&lt;/strong&gt; — a logical view of memory that the hardware translates to physical addresses.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Concept&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Logical (virtual) address&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;What the process sees (generated by CPU)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Physical address&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Actual location in RAM&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Address translation&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Mapping logical → physical (done by MMU)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Protection&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;One process cannot access another&amp;rsquo;s memory&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="paging"&gt;Paging&lt;a class="anchor" href="#paging"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Paging&lt;/strong&gt; divides memory into fixed-size blocks, eliminating external fragmentation:&lt;/p&gt;</description></item><item><title>Virtual Memory</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/04-virtual-memory/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/04-virtual-memory/</guid><description>&lt;h1 id="virtual-memory"&gt;Virtual Memory&lt;a class="anchor" href="#virtual-memory"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Virtual memory extends the basic paging model into a complete system for managing address spaces larger than physical RAM. It encompasses the page table structures, swap management, memory overcommit policies, and hardware-aware optimizations like NUMA and huge pages.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="virtual-vs-physical-addresses"&gt;Virtual vs Physical Addresses&lt;a class="anchor" href="#virtual-vs-physical-addresses"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Aspect&lt;/th&gt;
					&lt;th&gt;Virtual Address&lt;/th&gt;
					&lt;th&gt;Physical Address&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Generated by&lt;/td&gt;
					&lt;td&gt;CPU / program&lt;/td&gt;
					&lt;td&gt;MMU (after translation)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Space size&lt;/td&gt;
					&lt;td&gt;Full architecture width (e.g., 48-bit on x86-64)&lt;/td&gt;
					&lt;td&gt;Limited by installed RAM&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Per-process&lt;/td&gt;
					&lt;td&gt;Yes — each process has its own&lt;/td&gt;
					&lt;td&gt;Shared — single physical space&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Contiguous?&lt;/td&gt;
					&lt;td&gt;Appears contiguous to process&lt;/td&gt;
					&lt;td&gt;Scattered frames&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Bounds&lt;/td&gt;
					&lt;td&gt;0 to 2^48 - 1 (256 TB on x86-64)&lt;/td&gt;
					&lt;td&gt;0 to installed_ram - 1&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Process A sees: Physical RAM: Process B sees:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 0x0000 │────────┐ │ Frame 0 │ ┌─────│ 0x0000 │
│ 0x1000 │──┐ └───▶│ Frame 1 │ │ │ 0x1000 │
│ 0x2000 │ │ │ Frame 2 │◀────┘ │ 0x2000 │
└──────────┘ └─────────▶│ Frame 3 │ └──────────┘
 │ Frame 4 │◀──── Process B page 1
 └──────────┘&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="page-table-structures"&gt;Page Table Structures&lt;a class="anchor" href="#page-table-structures"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A flat page table for a 48-bit address space with 4KB pages would require 2^36 entries × 8 bytes = 512 GB. Clearly impractical. Real systems use hierarchical or inverted page tables.&lt;/p&gt;</description></item><item><title>File Systems</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/05-file-systems/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/05-file-systems/</guid><description>&lt;h1 id="file-systems"&gt;File Systems&lt;a class="anchor" href="#file-systems"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;A &lt;strong&gt;file system&lt;/strong&gt; organizes persistent data on storage devices into a logical structure of files and directories. It translates high-level operations (open, read, write) into low-level block I/O while maintaining data integrity, supporting concurrent access, and managing metadata.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="file-system-concepts"&gt;File System Concepts&lt;a class="anchor" href="#file-system-concepts"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Concept&lt;/th&gt;
					&lt;th&gt;Description&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;File&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Named collection of related data stored on secondary storage&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Directory&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Container that maps file names to file metadata&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Path&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Hierarchical location identifier (&lt;code&gt;/home/user/docs/file.txt&lt;/code&gt;)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Mount point&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Location where a file system attaches to the directory tree&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Superblock&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;File system metadata (size, block count, free space)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Block&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Minimum allocation unit (typically 4 KB)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="file-metadata-stored-separately-from-data"&gt;File Metadata (stored separately from data)&lt;a class="anchor" href="#file-metadata-stored-separately-from-data"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│ File type │ Regular, directory, symlink, device, pipe │
│ Permissions │ rwxr-xr-x (owner/group/other) │
│ Owner/Group │ UID, GID │
│ Size │ Bytes of data │
│ Timestamps │ atime, mtime, ctime │
│ Link count │ Number of hard links │
│ Block pointers │ Locations of data blocks on disk │
└─────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="inodes"&gt;Inodes&lt;a class="anchor" href="#inodes"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;An &lt;strong&gt;inode&lt;/strong&gt; (index node) stores all metadata about a file except its name:&lt;/p&gt;</description></item><item><title>I/O Systems</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/06-io-systems/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/06-io-systems/</guid><description>&lt;h1 id="io-systems"&gt;I/O Systems&lt;a class="anchor" href="#io-systems"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Input/Output systems bridge the gap between the CPU and the external world — disks, networks, keyboards, GPUs. Understanding how the OS manages I/O is critical for writing performant software and diagnosing bottlenecks.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="io-hardware-fundamentals"&gt;I/O Hardware Fundamentals&lt;a class="anchor" href="#io-hardware-fundamentals"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Every I/O device connects to the system through a &lt;strong&gt;controller&lt;/strong&gt; that exposes registers to the CPU:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Register&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Indicates device state (busy, ready, error)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Command&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;CPU writes operations (read, write, seek)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Data-in&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;CPU reads data from device&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Data-out&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;CPU writes data to device&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="port-mapped-vs-memory-mapped-io"&gt;Port-Mapped vs Memory-Mapped I/O&lt;a class="anchor" href="#port-mapped-vs-memory-mapped-io"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Approach&lt;/th&gt;
					&lt;th&gt;Mechanism&lt;/th&gt;
					&lt;th&gt;Example&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Port-mapped&lt;/td&gt;
					&lt;td&gt;Special CPU instructions (&lt;code&gt;in&lt;/code&gt;/&lt;code&gt;out&lt;/code&gt;) access device registers&lt;/td&gt;
					&lt;td&gt;x86 legacy devices&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Memory-mapped&lt;/td&gt;
					&lt;td&gt;Device registers mapped to memory addresses&lt;/td&gt;
					&lt;td&gt;Modern GPUs, NVMe&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Memory-mapped I/O is dominant today — it allows the same load/store instructions to access both RAM and devices.&lt;/p&gt;</description></item><item><title>Concurrency Primitives</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/07-concurrency-primitives/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/07-concurrency-primitives/</guid><description>&lt;h1 id="concurrency-primitives"&gt;Concurrency Primitives&lt;a class="anchor" href="#concurrency-primitives"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Concurrency is the art of managing multiple threads of execution that share resources. Without proper synchronization, programs exhibit &lt;strong&gt;race conditions&lt;/strong&gt; — subtle, non-deterministic bugs that are notoriously difficult to reproduce and fix.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="race-conditions-and-critical-sections"&gt;Race Conditions and Critical Sections&lt;a class="anchor" href="#race-conditions-and-critical-sections"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;race condition&lt;/strong&gt; occurs when the outcome depends on the timing of thread execution:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# NOT atomic — three operations:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 1. Read counter into register&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 2. Add 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 3. Write back to counter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Two threads running increment() 1000 times each&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Expected: 2000 | Actual: unpredictable (e.g., 1847)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A &lt;strong&gt;critical section&lt;/strong&gt; is a code region accessing shared resources that must not execute concurrently.&lt;/p&gt;</description></item><item><title>Containers from the OS Perspective</title><link>https://kyngo.github.io/learning-paths/paths/operating-systems/08-containers-from-os/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://kyngo.github.io/learning-paths/paths/operating-systems/08-containers-from-os/</guid><description>&lt;h1 id="containers-from-the-os-perspective"&gt;Containers from the OS Perspective&lt;a class="anchor" href="#containers-from-the-os-perspective"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Containers are not a single technology — they are an orchestration of several Linux kernel features that together provide process isolation. Understanding these primitives demystifies Docker and reveals what containers actually are: &lt;strong&gt;isolated groups of processes sharing the host kernel&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="linux-namespaces"&gt;Linux Namespaces&lt;a class="anchor" href="#linux-namespaces"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Namespaces partition kernel resources so that one set of processes sees one set of resources, and another set sees a different set.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Namespace&lt;/th&gt;
					&lt;th&gt;Isolates&lt;/th&gt;
					&lt;th&gt;Flag&lt;/th&gt;
					&lt;th&gt;Effect&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;PID&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Process IDs&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWPID&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Process sees itself as PID 1&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;NET&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Network stack&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWNET&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Own interfaces, IPs, routing tables&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;MNT&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Mount points&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWNS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Own filesystem tree&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;UTS&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Hostname/domain&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWUTS&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Own hostname&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;IPC&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;IPC resources&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWIPC&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Own message queues, semaphores&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;USER&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;UID/GID mappings&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWUSER&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Root inside, unprivileged outside&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;CGROUP&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Cgroup hierarchy&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWCGROUP&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Own view of cgroup tree&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;TIME&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;System clocks&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;CLONE_NEWTIME&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Own boot/monotonic time (Linux 5.6+)&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="creating-namespaces"&gt;Creating Namespaces&lt;a class="anchor" href="#creating-namespaces"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a new PID + MNT + NET namespace and run bash inside&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo unshare --pid --mount --net --fork bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Inside: PID 1, no network interfaces, isolated mounts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ps aux &lt;span class="c1"&gt;# only see processes in this namespace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ip link &lt;span class="c1"&gt;# only loopback&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;hostname &lt;span class="c1"&gt;# still host&amp;#39;s (need --uts to isolate)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pid-namespace-in-action"&gt;PID Namespace in Action&lt;a class="anchor" href="#pid-namespace-in-action"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Host view: Container view:
PID 1 (systemd) PID 1 (nginx) ← mapped to PID 4521 on host
PID 4521 (nginx) PID 2 (worker)
PID 4522 (worker)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="user-namespaces--rootless-containers"&gt;User Namespaces — Rootless Containers&lt;a class="anchor" href="#user-namespaces--rootless-containers"&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Map container root (UID 0) to host UID 100000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;unshare --user --map-root-user bash
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;id &lt;span class="c1"&gt;# uid=0(root) — but only inside the namespace&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This enables rootless containers: full &amp;ldquo;root&amp;rdquo; power inside, zero privilege on the host.&lt;/p&gt;</description></item></channel></rss>