<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Down The Ra-bit Hole]]></title><description><![CDATA[For the curious engineers.]]></description><link>https://downtherabithole.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/698ce732e249cba68b3bbdb5/3feff84f-04c6-45b1-b3a2-b1b5ab89694f.png</url><title>Down The Ra-bit Hole</title><link>https://downtherabithole.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 02 Jul 2026 01:03:29 GMT</lastBuildDate><atom:link href="https://downtherabithole.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How a Process Really Works]]></title><description><![CDATA[As a DevOps/SRE/Platform Engineer you see many varieties of processes in the wild; Microservices writing to a database, a CI pipeline which runs linters and unit tests, the Docker ecosystem itself is ]]></description><link>https://downtherabithole.dev/how-a-process-really-works</link><guid isPermaLink="true">https://downtherabithole.dev/how-a-process-really-works</guid><category><![CDATA[operating system]]></category><category><![CDATA[linux-processes]]></category><category><![CDATA[Platform Engineering ]]></category><category><![CDATA[Devops]]></category><category><![CDATA[SRE]]></category><category><![CDATA[ci-cd]]></category><category><![CDATA[cpu]]></category><category><![CDATA[scheduling]]></category><category><![CDATA[Linux]]></category><category><![CDATA[#parallel computing]]></category><category><![CDATA[fundamentals]]></category><dc:creator><![CDATA[George Sims]]></dc:creator><pubDate>Wed, 01 Jul 2026 10:35:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/698ce732e249cba68b3bbdb5/17dd1a7e-dbb8-4fcc-9bca-a9df12d02edd.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a DevOps/SRE/Platform Engineer you see many varieties of processes in the wild; Microservices writing to a database, a CI pipeline which runs linters and unit tests, the Docker ecosystem itself is a type of abstraction on a process with some OS magic thrown in. Sure that's pretty easy - we all know these things. But do you really understand how that process runs under the hood?</p>
<p>The process is the Operating System's way of executing a program, seemingly at the same time as all of the other programs running on our computer. In its simplest form, the program is an executable living on a disk. It has instructions within it, but the OS has the task of making it run (ideally successfully) alongside everything else already occupying the CPU.</p>
<p>First, it helps to understand how the CPU works. The CPU has the capability to execute one thing at any given time*****. On modern PCs that sounds very limited. Imagine how many programs are currently running at the same time even as you read this: your laptop is probably running your IDE, some Docker containers and fetching all of your Slack messages. Under the hood the OS is doing something incredible: all of these programs are not running at the same time, but instead made to seem like they are. For this to be successful the CPU must be able to execute the programs almost instantaneously, swapping them out when the scheduler sees fit, so the internal state of each program must be known and stored somewhere in working memory, which is where the abstraction of the program - the process - is key.</p>
<p>When talking about a process it can be described by its state. A state includes what the process can read/write to, which parts of memory it has access to and also all of its instructions that are stored in memory ready to execute. It helps to think about a process like a box, everything inside the box is used to run the program, if the CPU has the box then it can successfully run the program which that box defines. This box must be loaded into memory from the disk. The program on disk is normally already 'translated' from the programming language it is written in to a form which is understandable by the CPU, this is usually a compiled executable file (think of the output file of a <code>gcc</code> compiler). Historically Operating Systems would load the whole program/executable into memory, but these days they are loaded 'lazily' meaning only the parts of the executable that are required in that moment are loaded.</p>
<blockquote>
<p>It's like baking a cake!<br />Think of a process like a cake recipe being made in the kitchen. The kitchen manager (OS scheduler) hands the baker (CPU) a set of prepared ingredients and the steps (ingredients + steps = process). The baker would then simply follow those instructions using the ingredients to bake the cake (process execution).</p>
</blockquote>
<p>There are two important data structures used by a process: the stack and the heap. The local variables, function parameters, return addresses etc are stored in the stack during runtime by the process. The nature of the stack is LIFO (last in, first out), the process needs to remember where to return to after calling any function. To do this it will 'push' the return address (register) to the stack, once the function has finished the process can then 'pop' the stack to get that address to return back to. The heap can be seen as something which grows over time during the life of the process. Data structures which grow dynamically such as linked lists and hash tables are stored there. Think about the C function <code>malloc()</code>, it is used to dynamically allocate memory to be used during execution, the heap is the place where that will be stored.</p>
<p>Now we have all of the pieces of the process defined and loaded, the process is now ready to be scheduled on the CPU. This is the job of the scheduler. The scheduler is managed on the OS level and uses scheduling policies which help determine which processes should be run on the CPU and when. Historical information, performance metrics and workload knowledge are all things the scheduler will check to make an informed decision. There is a list of states that a process can be in at any given time, the three main ones are: 'Running', 'Blocked' and 'Ready'. Naturally when running it means that the CPU is executing the process. When a process, say a network call or a DB write happens, they both require I/O (which in the CPUs mind is an eternity), this means that the CPU should run something else while waiting even though the process isn't finished yet. Once those processes have the data they were waiting for, they are considered ready and the scheduler will eventually make them CPU bound again.</p>
<blockquote>
<p>The bread is burning!<br />Go back to our baker analogy. If she was following the recipe and she suddenly smelled smoke, that would take higher priority than her current cake. The kitchen manager would then mark down where she was in the recipe, tell her to attend to the potential fire (a different process), then pick up where she left off. That is how context switching works on the CPU - a different process is required to run (be it due to priority or simply time) so the current process' context is saved so it can be loaded back again afterwards.</p>
</blockquote>
<p>What about program size? To be successful the program must first be loaded into memory before it can be executed by the CPU - but what if that program is larger than what is available on the machine? Back in the day the process would simply fail. Program creators would make sure that the program would take up N addresses, where N was address 0 up to 2^32 on 32-bit machines and 2^64 on 64-bit. Upon loading the whole program could then be stored in the available addresses before execution. Nowadays computers have the capability to use virtual memory, an abstraction on both disk and RAM. The OS allows for the process to only be loaded partially into available memory, and when required load parts of the program from the disk to memory, swapping out the unused parts. This is called paging. This way the program can grow way past the limitation of memory, and instead be limited by physical disk space. This abstraction also allows each process to be totally isolated and not corrupt another's address space - crucial to the architecture of containers, which we will cover in a future post.</p>
<p>After reading this post you should now not only grasp how processes work under the hood, but also start to think about why parallelization is so important to factor into your design choices as early as possible. If your microservice requires a DB call, make it asynchronous so that another process can run while it waits. Write your CI pipelines so that your linting, unit testing and building don't block each other while I/O bound. Finally always understand that you are at the mercy of the CPU scheduler when trying to get everything perfectly synced.</p>
<p><em><strong>*modern CPUs have multiple cores and thus can actually run two or more things at once, but for simplicity's sake let's assume we have one core</strong></em></p>
]]></content:encoded></item></channel></rss>