<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vadher Nikunj</title>
    <description>The latest articles on DEV Community by Vadher Nikunj (@vadher_nikunj_47e8c86d866).</description>
    <link>https://dev.to/vadher_nikunj_47e8c86d866</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4200579%2F57b1a3ea-6f11-4d40-be59-ddbdac0d0a9b.jpg</url>
      <title>DEV Community: Vadher Nikunj</title>
      <link>https://dev.to/vadher_nikunj_47e8c86d866</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vadher_nikunj_47e8c86d866"/>
    <language>en</language>
    <item>
      <title>Queues Explained with Real Examples from the Linux Kernel</title>
      <dc:creator>Vadher Nikunj</dc:creator>
      <pubDate>Mon, 02 Nov 2026 05:42:39 +0000</pubDate>
      <link>https://dev.to/vadher_nikunj_47e8c86d866/queues-explained-with-real-examples-from-the-linux-kernel-2750</link>
      <guid>https://dev.to/vadher_nikunj_47e8c86d866/queues-explained-with-real-examples-from-the-linux-kernel-2750</guid>
      <description>&lt;p&gt;In the last post we looked at the stack, where the last thing in is the first thing out. This time we look at its opposite, the queue. It is just as simple, and the Linux kernel leans on it all the time.&lt;/p&gt;

&lt;p&gt;Let's start with the idea, write a small one in C, and then see where the kernel uses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a queue?
&lt;/h2&gt;

&lt;p&gt;Think of the line at a ticket counter. A new person joins at the back. The person at the front gets served and leaves. Nobody jumps ahead. The first person who came is the first person who gets a ticket.&lt;/p&gt;

&lt;p&gt;That rule is called first in, first out, or FIFO. A queue has two main actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enqueue&lt;/strong&gt; adds a new item at the back&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dequeue&lt;/strong&gt; takes the item at the front&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most queues also let you check if they are empty or full.&lt;/p&gt;

&lt;p&gt;The big difference from a stack is fairness. A queue always serves the item that has waited the longest.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tiny queue in C
&lt;/h2&gt;

&lt;p&gt;The easy way to build a queue is with an array and two positions. One position, &lt;code&gt;head&lt;/code&gt;, marks the front. The other, &lt;code&gt;tail&lt;/code&gt;, marks where the next item goes. But there is a catch. If you only ever move forward, you soon reach the end of the array, even though the front part is now empty.&lt;/p&gt;

&lt;p&gt;The fix is to wrap around. When &lt;code&gt;tail&lt;/code&gt; or &lt;code&gt;head&lt;/code&gt; reaches the end, it goes back to 0. This is called a circular buffer, or ring buffer. Picture the array bent into a circle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MAX 8
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="cm"&gt;/* where the next item is taken from */&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="cm"&gt;/* where the next item goes in */&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="cm"&gt;/* how many items are waiting */&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="cm"&gt;/* full, so we stop */&lt;/span&gt;
    &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="cm"&gt;/* wrap around to the start */&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;dequeue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="cm"&gt;/* empty, nothing to give */&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;% MAX&lt;/code&gt; part does the wrap. If &lt;code&gt;tail&lt;/code&gt; is 7 and &lt;code&gt;MAX&lt;/code&gt; is 8, then &lt;code&gt;(7 + 1) % 8&lt;/code&gt; is 0, so the next item goes back at the start. The &lt;code&gt;count&lt;/code&gt; tells us if the queue is full or empty, because &lt;code&gt;head == tail&lt;/code&gt; can mean either one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0m0d2vur5ujn3op1q2zz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0m0d2vur5ujn3op1q2zz.png" alt="Diagram of a circular queue with 8 slots, head at slot 2 and tail at slot 5" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like the stack, both actions take the same short time no matter how many items are waiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Linux kernel uses queues
&lt;/h2&gt;

&lt;p&gt;The examples below are from the Linux 2.6 kernel. Newer kernels have changed some details, but the ideas are still there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wait queues for sleeping processes
&lt;/h3&gt;

&lt;p&gt;A process often has to wait for something. It may be waiting for a disk read to finish, or for a resource to be free. There is no point keeping the CPU busy while it waits. So the kernel puts it to sleep on a &lt;strong&gt;wait queue&lt;/strong&gt; and runs something else.&lt;/p&gt;

&lt;p&gt;Each wait queue belongs to one kind of event. When the event happens, the kernel wakes the processes sleeping on it. Inside, a wait queue is a doubly linked list. Each item points to a sleeping process. The head of the list also has a lock, because interrupt handlers and normal kernel code can both change it.&lt;/p&gt;

&lt;p&gt;There is a nice detail here. Sometimes many processes wait for a resource that only one of them can use. Waking all of them would be a waste, since only one would win and the rest would go back to sleep. This is called the "thundering herd" problem. To avoid it, such processes are marked as exclusive and added at the back of the list, and the kernel wakes only one of them at a time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read/write semaphores in strict FIFO order
&lt;/h3&gt;

&lt;p&gt;A semaphore is a kind of lock. When a process can't get it, the process sleeps on the semaphore's wait queue. For read/write semaphores, the kernel handles the waiting processes in strict FIFO order. Each new waiter joins at the back. When the lock is released, the kernel looks at the process at the front first. That is a ticket counter line, written in kernel code.&lt;/p&gt;

&lt;h3&gt;
  
  
  The runqueue
&lt;/h3&gt;

&lt;p&gt;Processes that are ready to run sit on the &lt;strong&gt;runqueue&lt;/strong&gt;. Older versions kept one big list and had to scan all of it to pick the best process. Linux 2.6 split it into 140 lists, one for each priority level, and each CPU got its own set.&lt;/p&gt;

&lt;p&gt;When a process becomes ready, the function &lt;code&gt;enqueue_task()&lt;/code&gt; adds it to the tail of the list for its priority. The kernel also has &lt;code&gt;dequeue_task()&lt;/code&gt; to take it out. So within one priority level, processes line up and take turns. For round robin real-time processes, the one that gets the CPU is moved to the end of its list, so others of the same priority get a fair share.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pipes as a circular buffer
&lt;/h3&gt;

&lt;p&gt;When you type &lt;code&gt;ls | grep txt&lt;/code&gt;, the two programs talk through a pipe. From Linux 2.6.11, each pipe uses 16 buffers, and the kernel treats them as one circular buffer. Writers keep adding data. Readers keep taking it out from the front. To find the first empty buffer, the kernel adds the current buffer index and the number of full buffers, modulo 16. That is the same &lt;code&gt;% MAX&lt;/code&gt; trick from our code above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queue or stack?
&lt;/h2&gt;

&lt;p&gt;How do you pick? Ask one question: who should be served next?&lt;/p&gt;

&lt;p&gt;If the newest item should go first, use a stack. Function calls and undo work that way.&lt;/p&gt;

&lt;p&gt;If the oldest item should go first, use a queue. This is what you want when things arrive over time and each one should get its turn, like print jobs or network packets. It is also the base of breadth first search in graphs, where you visit nodes level by level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Add a &lt;code&gt;peek()&lt;/code&gt; function to the code above that returns the front item without removing it.&lt;/li&gt;
&lt;li&gt;Change the queue to use a linked list instead of an array, so it has no fixed size.&lt;/li&gt;
&lt;li&gt;Build a queue using two stacks. It is a common interview question.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;Next in the series is the linked list, which we have already met twice here, inside wait queues and the runqueue. If you want to write these structures yourself and see them run, our C and data structures course at &lt;a href="https://www.jupiuslearning.com/courses/c-ds-a/" rel="noopener noreferrer"&gt;/courses/c-ds-a/&lt;/a&gt; walks through them step by step.&lt;/p&gt;




&lt;p&gt;I first published this on the &lt;a href="https://www.jupiuslearning.com/blog/queues-explained-with-real-examples-from-the-linux-kernel/" rel="noopener noreferrer"&gt;Jupius Learning blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>c</category>
      <category>linux</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Stacks Explained with Real Examples from the Linux Kernel</title>
      <dc:creator>Vadher Nikunj</dc:creator>
      <pubDate>Mon, 02 Nov 2026 05:31:02 +0000</pubDate>
      <link>https://dev.to/vadher_nikunj_47e8c86d866/stacks-explained-with-real-examples-from-the-linux-kernel-o2n</link>
      <guid>https://dev.to/vadher_nikunj_47e8c86d866/stacks-explained-with-real-examples-from-the-linux-kernel-o2n</guid>
      <description>&lt;p&gt;A stack is one of the simplest data structures there is. You can learn the idea in one minute. But it is also one of the most useful, and it sits inside every program you have ever run, including the Linux kernel.&lt;/p&gt;

&lt;p&gt;Let's start with the idea, then look at where the kernel uses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a stack?
&lt;/h2&gt;

&lt;p&gt;Think of a pile of plates. You put a new plate on top. When you need one, you take the top plate. You never pull one from the middle. The last plate you put on is the first one you take off.&lt;/p&gt;

&lt;p&gt;That rule has a name: last in, first out, or LIFO. A stack has only two main actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Push&lt;/strong&gt; puts a new item on top&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pop&lt;/strong&gt; takes the top item off&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most stacks also let you peek at the top item without removing it, and check if the stack is empty.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tiny stack in C
&lt;/h2&gt;

&lt;p&gt;Here is a stack of integers using a plain array. It is small, but it shows the whole idea.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define MAX 100
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="cm"&gt;/* -1 means the stack is empty */&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;MAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="cm"&gt;/* full, so we stop */&lt;/span&gt;
    &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="cm"&gt;/* empty, nothing to give */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both actions are quick. They do not depend on how many items are in the stack. That is why stacks are used in places where speed matters a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Linux kernel uses stacks
&lt;/h2&gt;

&lt;p&gt;Every process on Linux gets its own stack inside the kernel. It is separate from the stack your program uses in normal mode. In the Linux 2.6 days on x86, this kernel stack lived in a fixed area of 8 KB, which is two memory pages. The small data block that describes the process sat at the start of that area, and the stack started at the far end and grew backwards toward it.&lt;/p&gt;

&lt;p&gt;Notice the detail here. The stack does not grow forward. It starts at the high end and moves down as you push. A register called &lt;code&gt;esp&lt;/code&gt; always points to the current top. When the stack is empty, it points just past the end of the area. This is the same thing as &lt;code&gt;top = -1&lt;/code&gt; in our small example, only done at machine level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj3k9m2rzbdncdba0bztc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj3k9m2rzbdncdba0bztc.png" alt="Diagram of a Linux kernel stack growing downward toward the process info block, with esp at the top" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Function calls
&lt;/h3&gt;

&lt;p&gt;When one function calls another, the CPU pushes the return address and the local variables on the stack. When the function ends, they are popped, and the program goes back to exactly where it left off. If function A calls B, and B calls C, then C must finish first, then B, then A. That is LIFO again. You never have to think about it, because the stack does it for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interrupts
&lt;/h3&gt;

&lt;p&gt;Now the more interesting case. When a device such as a keyboard or a network card needs attention, the CPU stops what it is doing and runs an interrupt handler. The first thing the kernel does is save the CPU registers on the kernel stack. The last thing it does is restore them, so the interrupted work can carry on as if nothing happened.&lt;/p&gt;

&lt;p&gt;Interrupts can also be nested. One handler can be interrupted by another one, and that one by another. How does the kernel remember where to go back to? It just pushes each one on the stack. The newest handler finishes first, then it returns to the one before it, and so on, until the CPU is back to the original work. A stack is the natural fit, because the last thing that started is always the first thing that must finish.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching between processes
&lt;/h3&gt;

&lt;p&gt;When the kernel stops one process and starts another, it has to save the state of the first one so it can be continued later. Part of that state is stored in the process's own kernel stack. Because each process has its own stack, the kernel can switch to another process by changing the stack pointer. In the code, the switch is really a swap from one stack to another.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the stack is small
&lt;/h2&gt;

&lt;p&gt;You may wonder why the kernel keeps this stack so small. It is because kernel code is careful. It does not use deep chains of function calls or big local arrays. A stack that runs out of space is a serious bug, since the data next to it can be overwritten. The kernel also had a setting for even smaller 4 KB stacks, and in that case it used a few extra stacks just for interrupts, so that deeply nested handlers would not run it out of room.&lt;/p&gt;

&lt;p&gt;The lesson for your own code is the same. A stack has a limit, and if you go too deep, for example with a function that calls itself forever, you get the famous stack overflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  More places you already use stacks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The undo button in your editor&lt;/li&gt;
&lt;li&gt;The back button in your browser&lt;/li&gt;
&lt;li&gt;Checking that brackets match in code, like &lt;code&gt;{ ( ) }&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Evaluating expressions like &lt;code&gt;3 + 4 * 2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Depth first search in graphs and trees&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write a function that uses a stack to check if a string like &lt;code&gt;{[()]}&lt;/code&gt; has matching brackets.&lt;/li&gt;
&lt;li&gt;Reverse a string using only push and pop.&lt;/li&gt;
&lt;li&gt;What happens in the code above if you call &lt;code&gt;pop()&lt;/code&gt; on an empty stack? How would you handle it better?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you can do these three, you understand stacks well enough for most interviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;Next in the series is the queue. It is the stack's opposite, first in and first out, and the kernel uses it a lot too. If you want to practise as you read, our C and data structures course covers stacks, queues and the rest hands-on.&lt;/p&gt;




&lt;p&gt;I first published this on the &lt;a href="https://www.jupiuslearning.com/blog/stacks-explained-with-real-examples-from-the-linux-kernel/" rel="noopener noreferrer"&gt;Jupius Learning blog&lt;/a&gt;. If you want to practice, the &lt;a href="https://www.jupiuslearning.com/courses/c-ds-a/" rel="noopener noreferrer"&gt;C, data structures and algorithms course&lt;/a&gt; is a good place to start.&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>c</category>
      <category>linux</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
