<?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[DevNation]]></title><description><![CDATA[Blog on  System Programming Languages]]></description><link>https://devnation.joshisfitness.com</link><generator>RSS for Node</generator><lastBuildDate>Sat, 12 Sep 2026 20:05:12 GMT</lastBuildDate><atom:link href="https://devnation.joshisfitness.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Understanding atomic_t vs refcount_t in the Linux Kernel]]></title><description><![CDATA[atomic_t vs refcount_t in the Linux Kernel: Counters, References, and Object Lifetime
Introduction
When developing Linux kernel code, counters and object lifetime management can look deceptively simil]]></description><link>https://devnation.joshisfitness.com/understanding-atomic-t-vs-refcount-t-in-the-linux-kernel</link><guid isPermaLink="true">https://devnation.joshisfitness.com/understanding-atomic-t-vs-refcount-t-in-the-linux-kernel</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[coding]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Sat, 12 Sep 2026 10:37:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/fef51f4a-17e7-424f-9c56-33bf6c47cf60.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1><code>atomic_t</code> vs <code>refcount_t</code> in the Linux Kernel: Counters, References, and Object Lifetime</h1>
<h2>Introduction</h2>
<p>When developing Linux kernel code, counters and object lifetime management can look deceptively similar.</p>
<p>Both may involve operations such as:</p>
<pre><code class="language-c">increment();
decrement();
</code></pre>
<p>But they solve fundamentally different problems.</p>
<p>Two important Linux kernel primitives are:</p>
<ul>
<li><p><code>atomic_t</code></p>
</li>
<li><p><code>refcount_t</code></p>
</li>
</ul>
<p>The distinction is simple:</p>
<blockquote>
<p><code>atomic_t</code> <strong>is primarily for atomic integer operations.</strong></p>
<p><code>refcount_t</code> <strong>is specifically for reference counting and object lifetime management.</strong></p>
</blockquote>
<p>Understanding this distinction becomes increasingly important when writing kernel modules that operate in concurrent environments.</p>
<hr />
<h1>1. The Core Idea</h1>
<p>A kernel object can contain both an atomic counter and a reference counter:</p>
<pre><code class="language-c">struct demo_object {
    atomic_t  counter;
    refcount_t refs;
};
</code></pre>
<p>Although both fields contain numeric values, their <strong>meaning is different</strong>.</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Purpose</th>
<th>Typical Question</th>
</tr>
</thead>
<tbody><tr>
<td><code>atomic_t counter</code></td>
<td>Counts operations or events</td>
<td>"How many operations occurred?"</td>
</tr>
<tr>
<td><code>refcount_t refs</code></td>
<td>Tracks object references</td>
<td>"How many users still reference this object?"</td>
</tr>
</tbody></table>
<p>This semantic difference is the foundation of the entire demonstration.</p>
<hr />
<h1>2. What Is <code>atomic_t</code>?</h1>
<p><code>atomic_t</code> provides atomic operations on an integer value.</p>
<p>Common kernel APIs include:</p>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>atomic_set()</code></td>
<td>Initialize or assign a value</td>
</tr>
<tr>
<td><code>atomic_read()</code></td>
<td>Read the current value</td>
</tr>
<tr>
<td><code>atomic_inc()</code></td>
<td>Increment the value</td>
</tr>
<tr>
<td><code>atomic_dec()</code></td>
<td>Decrement the value</td>
</tr>
<tr>
<td><code>atomic_add()</code></td>
<td>Add a value</td>
</tr>
</tbody></table>
<p>For example:</p>
<pre><code class="language-c">atomic_inc(&amp;obj-&gt;counter);
</code></pre>
<p>This performs an atomic increment of the counter.</p>
<p>The important word is:</p>
<blockquote>
<p><strong>atomic</strong></p>
</blockquote>
<p>The operation is designed for concurrent execution contexts so that the particular atomic update is performed as an atomic operation.</p>
<p>However, this does <strong>not</strong> mean that every operation involving the object automatically becomes thread-safe.</p>
<hr />
<h1>3. Typical Uses of <code>atomic_t</code></h1>
<p><code>atomic_t</code> is useful when the value represents activity or statistics.</p>
<p>Examples include:</p>
<table>
<thead>
<tr>
<th>Example</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td>Request counter</td>
<td>Number of processed requests</td>
</tr>
<tr>
<td>Packet counter</td>
<td>Number of processed packets</td>
</tr>
<tr>
<td>Event counter</td>
<td>Number of generated events</td>
</tr>
<tr>
<td>Operation counter</td>
<td>Number of operations performed</td>
</tr>
<tr>
<td>Statistics</td>
<td>Runtime kernel statistics</td>
</tr>
</tbody></table>
<p>For example:</p>
<pre><code class="language-c">atomic_inc(&amp;obj-&gt;counter);
</code></pre>
<p>could mean:</p>
<blockquote>
<p>"Another request has been processed."</p>
</blockquote>
<p>The counter represents <strong>activity</strong>, not ownership.</p>
<hr />
<h1>4. What Is <code>refcount_t</code>?</h1>
<p><code>refcount_t</code> is intended for <strong>reference counting</strong>.</p>
<p>Instead of asking:</p>
<pre><code class="language-text">How many operations happened?
</code></pre>
<p>it asks:</p>
<pre><code class="language-text">How many references currently keep this object alive?
</code></pre>
<p>Common APIs include:</p>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>refcount_set()</code></td>
<td>Initialize the reference count</td>
</tr>
<tr>
<td><code>refcount_read()</code></td>
<td>Read the reference count</td>
</tr>
<tr>
<td><code>refcount_inc()</code></td>
<td>Acquire a reference</td>
</tr>
<tr>
<td><code>refcount_dec()</code></td>
<td>Release a reference</td>
</tr>
<tr>
<td><code>refcount_dec_and_test()</code></td>
<td>Release a reference and test for zero</td>
</tr>
</tbody></table>
<p>The key concept is <strong>object lifetime</strong>.</p>
<hr />
<h1>5. Reference Counting Lifecycle</h1>
<p>Consider an object that starts with one reference.</p>
<pre><code class="language-text">Object created
      |
      v
refs = 1
      |
      | another user obtains reference
      v
refs = 2
      |
      | one user releases reference
      v
refs = 1
      |
      | final reference released
      v
refs = 0
      |
      v
Object can be freed
</code></pre>
<p>The critical transition is:</p>
<pre><code class="language-text">1 -&gt; 0
</code></pre>
<p>When the final reference is released, the object may become eligible for cleanup.</p>
<hr />
<h1>6. <code>atomic_t</code> vs <code>refcount_t</code></h1>
<p>These primitives should <strong>not</strong> be treated as interchangeable.</p>
<table>
<thead>
<tr>
<th><code>atomic_t</code></th>
<th><code>refcount_t</code></th>
</tr>
</thead>
<tbody><tr>
<td>General-purpose atomic counter</td>
<td>Reference-counting primitive</td>
</tr>
<tr>
<td>Counts operations/events</td>
<td>Tracks object references</td>
</tr>
<tr>
<td>Useful for statistics</td>
<td>Used for object lifetime</td>
</tr>
<tr>
<td><code>atomic_inc()</code></td>
<td><code>refcount_inc()</code></td>
</tr>
<tr>
<td><code>atomic_dec()</code></td>
<td><code>refcount_dec()</code></td>
</tr>
<tr>
<td><code>atomic_add()</code></td>
<td><code>refcount_dec_and_test()</code></td>
</tr>
</tbody></table>
<p>A useful mental model is:</p>
<table>
<thead>
<tr>
<th>Question</th>
<th>Appropriate Type</th>
</tr>
</thead>
<tbody><tr>
<td>How many requests happened?</td>
<td><code>atomic_t</code></td>
</tr>
<tr>
<td>How many packets were processed?</td>
<td><code>atomic_t</code></td>
</tr>
<tr>
<td>How many events occurred?</td>
<td><code>atomic_t</code></td>
</tr>
<tr>
<td>How many active references exist?</td>
<td><code>refcount_t</code></td>
</tr>
<tr>
<td>Can this object be freed yet?</td>
<td><code>refcount_t</code></td>
</tr>
</tbody></table>
<p>The most important distinction is:</p>
<pre><code class="language-text">                 What does the number mean?
                           |
             +-------------+-------------+
             |                           |
             v                           v
       Activity/Event              Object Ownership
             |                           |
             v                           v
         atomic_t                    refcount_t
</code></pre>
<hr />
<h1>7. Demonstration 1: Basic <code>atomic_t</code></h1>
<p>The first demonstration treats <code>atomic_t</code> as a simple operation counter.</p>
<p>The counter starts at zero:</p>
<pre><code class="language-text">0
</code></pre>
<p>Five increments produce:</p>
<pre><code class="language-text">0 -&gt; 1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5
</code></pre>
<p>An additional atomic addition of <code>10</code> produces:</p>
<pre><code class="language-text">5 -&gt; 15
</code></pre>
<p>A decrement then produces:</p>
<pre><code class="language-text">15 -&gt; 14
</code></pre>
<p>The important concept is not the final number.</p>
<p>The important concept is what the number <strong>represents</strong>.</p>
<p>Here it represents:</p>
<pre><code class="language-text">Operations / Activity
</code></pre>
<p>It does not determine whether an underlying object is still alive.</p>
<hr />
<h1>8. Demonstration 2: Basic <code>refcount_t</code></h1>
<p>Now consider a reference counter.</p>
<p>The reference count starts with one reference:</p>
<pre><code class="language-text">refs = 1
</code></pre>
<p>That initial reference represents ownership of the object.</p>
<p>When another user needs the object:</p>
<pre><code class="language-text">1 -&gt; 2
</code></pre>
<p>When that user finishes:</p>
<pre><code class="language-text">2 -&gt; 1
</code></pre>
<p>The object remains alive because one reference still exists.</p>
<p>Eventually, when the final reference is released:</p>
<pre><code class="language-text">1 -&gt; 0
</code></pre>
<p>the object can reach its cleanup state.</p>
<p>The important idea is:</p>
<pre><code class="language-text">refcount_t
    |
    v
Object lifetime
    |
    v
Can the object still be safely used?
</code></pre>
<hr />
<h1>9. Demonstration 3: Using Both Together</h1>
<p>A kernel object can contain both an operation counter and a reference count.</p>
<p>For example:</p>
<pre><code class="language-c">struct demo_object {
    atomic_t   counter;
    refcount_t refs;
};
</code></pre>
<p>Their meanings are independent:</p>
<table>
<thead>
<tr>
<th>Member</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td><code>counter</code></td>
<td>Number of operations</td>
</tr>
<tr>
<td><code>refs</code></td>
<td>Number of active references</td>
</tr>
</tbody></table>
<p>Suppose the object is in this state:</p>
<table>
<thead>
<tr>
<th>State</th>
<th>Value</th>
</tr>
</thead>
<tbody><tr>
<td>Operations performed</td>
<td><code>5</code></td>
</tr>
<tr>
<td>Active references</td>
<td><code>2</code></td>
</tr>
</tbody></table>
<p>There is no requirement for these values to match.</p>
<p>For example:</p>
<pre><code class="language-text">Operations = 5
References = 2
</code></pre>
<p>is perfectly meaningful.</p>
<p>Five operations do not imply five references.</p>
<p>Similarly:</p>
<pre><code class="language-text">References = 2
</code></pre>
<p>does not imply that exactly two operations have occurred.</p>
<p>They represent different aspects of the object's state.</p>
<hr />
<h1>10. Demonstration 4: Requests and Object Lifetime</h1>
<p>Consider a kernel object that processes requests.</p>
<p>Every request can increment an operation counter:</p>
<pre><code class="language-c">atomic_inc(&amp;object-&gt;counter);
</code></pre>
<p>The counter might evolve as follows:</p>
<table>
<thead>
<tr>
<th>Request</th>
<th>Counter</th>
</tr>
</thead>
<tbody><tr>
<td>First request</td>
<td><code>1</code></td>
</tr>
<tr>
<td>Second request</td>
<td><code>2</code></td>
</tr>
<tr>
<td>Third request</td>
<td><code>3</code></td>
</tr>
</tbody></table>
<p>At the same time, another user may acquire a reference to the object.</p>
<p>This produces two independent forms of tracking:</p>
<table>
<thead>
<tr>
<th>Tracking</th>
<th>Primitive</th>
</tr>
</thead>
<tbody><tr>
<td>Request activity</td>
<td><code>atomic_t</code></td>
</tr>
<tr>
<td>Object ownership</td>
<td><code>refcount_t</code></td>
</tr>
</tbody></table>
<p>Conceptually:</p>
<pre><code class="language-text">                  Kernel Object
                       |
             +---------+---------+
             |                   |
             v                   v
      Operation activity     Object lifetime
             |                   |
             v                   v
         atomic_t            refcount_t
             |                   |
             v                   v
       "What happened?"     "Who still needs it?"
</code></pre>
<p>This separation of responsibilities is important in concurrent kernel programming.</p>
<hr />
<h1>11. Demonstration 5: Multiple References</h1>
<p>Suppose an object starts with:</p>
<pre><code class="language-text">refs = 1
</code></pre>
<p>Three additional references are acquired:</p>
<pre><code class="language-text">1 -&gt; 2 -&gt; 3 -&gt; 4
</code></pre>
<p>The reference count is now:</p>
<pre><code class="language-text">refs = 4
</code></pre>
<p>Each additional reference represents another entity that currently needs the object to remain alive.</p>
<p>Those references must eventually be released.</p>
<p>After releasing the three temporary references:</p>
<pre><code class="language-text">4 -&gt; 3 -&gt; 2 -&gt; 1
</code></pre>
<p>The original reference remains.</p>
<p>Finally, when that last reference is released:</p>
<pre><code class="language-text">1 -&gt; 0
</code></pre>
<p>the object can be cleaned up.</p>
<hr />
<h1>12. The Reference Counting Rule</h1>
<p>One of the most important rules when working with reference counting is:</p>
<blockquote>
<p><strong>Every acquired reference must eventually be released.</strong></p>
</blockquote>
<p>Conceptually:</p>
<table>
<thead>
<tr>
<th>Operation</th>
<th>Effect</th>
</tr>
</thead>
<tbody><tr>
<td>Acquire reference</td>
<td><code>refs + 1</code></td>
</tr>
<tr>
<td>Release reference</td>
<td><code>refs - 1</code></td>
</tr>
<tr>
<td>Final release</td>
<td><code>refs == 0</code></td>
</tr>
<tr>
<td>Zero references</td>
<td>Object may be freed</td>
</tr>
</tbody></table>
<p>The basic lifecycle is:</p>
<pre><code class="language-text">Acquire
   |
   v
refs + 1
   |
   v
Use object
   |
   v
Release
   |
   v
refs - 1
   |
   +-------------------+
   |                   |
   | refs &gt; 0          | refs == 0
   |                   |
   v                   v
Object remains       Cleanup
alive
</code></pre>
<p>An unbalanced reference can prevent an object from reaching its cleanup state.</p>
<p>This is one reason reference-counting bugs can be difficult to diagnose.</p>
<hr />
<h1>13. Object Lifetime</h1>
<p>The demonstration dynamically allocates its object.</p>
<p>The lifecycle can be understood as:</p>
<table>
<thead>
<tr>
<th>Stage</th>
<th>Action</th>
</tr>
</thead>
<tbody><tr>
<td>Creation</td>
<td>Allocate object</td>
</tr>
<tr>
<td>Initialization</td>
<td>Initialize counter and references</td>
</tr>
<tr>
<td>Usage</td>
<td>Perform operations</td>
</tr>
<tr>
<td>Reference acquisition</td>
<td>Increment reference count</td>
</tr>
<tr>
<td>Reference release</td>
<td>Decrement reference count</td>
</tr>
<tr>
<td>Final release</td>
<td>Reference count reaches zero</td>
</tr>
<tr>
<td>Cleanup</td>
<td>Free object</td>
</tr>
</tbody></table>
<p>The overall lifecycle looks like this:</p>
<pre><code class="language-text">+----------------------+
| Object allocated     |
+----------+-----------+
           |
           v
+----------------------+
| Initialize counters  |
| and references       |
+----------+-----------+
           |
           v
+----------------------+
| Object is usable     |
+----------+-----------+
           |
           v
+----------------------+
| References exist     |
+----------+-----------+
           |
           v
+----------------------+
| References released  |
+----------+-----------+
           |
           v
+----------------------+
| refcount reaches 0   |
+----------+-----------+
           |
           v
+----------------------+
| Object can be freed  |
+----------------------+
</code></pre>
<p>The critical relationship is:</p>
<pre><code class="language-text">Object allocated
       |
       v
References exist
       |
       v
Object is usable
       |
       v
Final reference released
       |
       v
Reference count reaches zero
       |
       v
Object can be freed
</code></pre>
<hr />
<h1>14. Why Not Use <code>atomic_t</code> for Everything?</h1>
<p>At first glance, it may seem reasonable to use <code>atomic_t</code> for both operation counters and object references.</p>
<p>For example:</p>
<pre><code class="language-c">atomic_t counter;
</code></pre>
<p>But compare it with:</p>
<pre><code class="language-c">refcount_t refs;
</code></pre>
<p>The second declaration communicates much more information.</p>
<pre><code class="language-text">atomic_t counter;
        |
        +--&gt; This is an atomic integer counter.


refcount_t refs;
        |
        +--&gt; This represents references to an object.
</code></pre>
<p>Reference counting has semantic requirements related to ownership and lifetime.</p>
<p>Using the appropriate kernel primitive therefore makes the code:</p>
<ul>
<li><p>easier to understand</p>
</li>
<li><p>clearer to maintain</p>
</li>
<li><p>more explicit about ownership</p>
</li>
<li><p>better aligned with the intended kernel abstraction</p>
</li>
</ul>
<p>The type itself communicates intent.</p>
<hr />
<h1>15. Atomic Does Not Mean the Entire Program Is Thread-Safe</h1>
<p>This is an important concept.</p>
<blockquote>
<p><strong>An atomic operation does not automatically make an entire algorithm thread-safe.</strong></p>
</blockquote>
<p>Suppose a structure contains several fields:</p>
<pre><code class="language-c">struct demo_object {
    atomic_t counter;
    int state;
    void *data;
};
</code></pre>
<p>Making this operation atomic:</p>
<pre><code class="language-c">atomic_inc(&amp;obj-&gt;counter);
</code></pre>
<p>does not automatically protect:</p>
<pre><code class="language-c">obj-&gt;state
obj-&gt;data
</code></pre>
<p>from concurrent access.</p>
<p>Atomicity applies to the particular atomic operation.</p>
<p>A larger algorithm may still require synchronization.</p>
<hr />
<h1>16. Kernel Synchronization Primitives</h1>
<p>Linux provides multiple synchronization mechanisms, each intended for different problems.</p>
<table>
<thead>
<tr>
<th>Mechanism</th>
<th>Typical Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>atomic_t</code></td>
<td>Atomic counter operations</td>
</tr>
<tr>
<td>Spinlock</td>
<td>Short critical sections</td>
</tr>
<tr>
<td>Mutex</td>
<td>Sleepable mutual exclusion</td>
</tr>
<tr>
<td>Semaphore</td>
<td>Resource synchronization</td>
</tr>
<tr>
<td>RCU</td>
<td>Read-heavy concurrent access</td>
</tr>
<tr>
<td>Memory barriers</td>
<td>Ordering and visibility</td>
</tr>
</tbody></table>
<p>Conceptually:</p>
<pre><code class="language-text">                 Concurrency Problem
                         |
          +--------------+--------------+
          |              |              |
          v              v              v
      Counter        Critical       Read-heavy
      update         section        access
          |              |              |
          v              v              v
      atomic_t       Spinlock          RCU
                         |
                         v
                       Mutex
</code></pre>
<p>The correct primitive depends on <strong>what is being protected</strong> and <strong>what the execution context allows</strong>.</p>
<hr />
<h1>17. Kernel Headers</h1>
<p>The demonstration uses several kernel headers.</p>
<table>
<thead>
<tr>
<th>Header</th>
<th>Main APIs / Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>&lt;linux/module.h&gt;</code></td>
<td>Module infrastructure</td>
</tr>
<tr>
<td><code>&lt;linux/kernel.h&gt;</code></td>
<td>Kernel logging and core definitions</td>
</tr>
<tr>
<td><code>&lt;linux/init.h&gt;</code></td>
<td>Initialization and cleanup annotations</td>
</tr>
<tr>
<td><code>&lt;linux/atomic.h&gt;</code></td>
<td><code>atomic_t</code> operations</td>
</tr>
<tr>
<td><code>&lt;linux/refcount.h&gt;</code></td>
<td><code>refcount_t</code> operations</td>
</tr>
<tr>
<td><code>&lt;linux/slab.h&gt;</code></td>
<td><code>kmalloc()</code> and <code>kfree()</code></td>
</tr>
</tbody></table>
<p>For example:</p>
<pre><code class="language-c">#include &lt;linux/module.h&gt;
#include &lt;linux/kernel.h&gt;
#include &lt;linux/init.h&gt;
#include &lt;linux/atomic.h&gt;
#include &lt;linux/refcount.h&gt;
#include &lt;linux/slab.h&gt;
</code></pre>
<p>These headers provide the infrastructure required by the demonstration module.</p>
<hr />
<h1>18. Memory Management</h1>
<p>The example dynamically allocates its demonstration object.</p>
<p>The relevant memory-management APIs are:</p>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>kmalloc()</code></td>
<td>Allocate kernel memory</td>
</tr>
<tr>
<td><code>kfree()</code></td>
<td>Release kernel memory</td>
</tr>
</tbody></table>
<p>It is important to distinguish memory allocation from reference counting.</p>
<table>
<thead>
<tr>
<th>Mechanism</th>
<th>Responsibility</th>
</tr>
</thead>
<tbody><tr>
<td><code>kmalloc()</code></td>
<td>Obtain memory</td>
</tr>
<tr>
<td><code>refcount_t</code></td>
<td>Track references</td>
</tr>
<tr>
<td><code>kfree()</code></td>
<td>Release memory</td>
</tr>
</tbody></table>
<p>Therefore:</p>
<pre><code class="language-text">kmalloc()
   |
   v
Memory exists
   |
   v
refcount_t
   |
   v
Track who still references it
   |
   v
refs == 0
   |
   v
kfree()
</code></pre>
<p>A reference count does not allocate memory.</p>
<p>Likewise, <code>kmalloc()</code> does not track object ownership.</p>
<p>The code must connect these mechanisms correctly.</p>
<hr />
<h1>19. Module Lifecycle</h1>
<p>A Linux kernel module normally has an initialization path and an exit path.</p>
<table>
<thead>
<tr>
<th>Module Event</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td>Module initialization</td>
<td>Allocate and initialize resources</td>
</tr>
<tr>
<td>Module operation</td>
<td>Execute the demonstration</td>
</tr>
<tr>
<td>Module cleanup</td>
<td>Release resources</td>
</tr>
</tbody></table>
<p>The demonstration performs its examples during initialization.</p>
<p>The dynamically allocated object is eventually released during module cleanup after the reference count reaches its final state.</p>
<p>Conceptually:</p>
<pre><code class="language-text">module_init()
     |
     v
Allocate object
     |
     v
Initialize atomic_t
     |
     v
Initialize refcount_t
     |
     v
Run demonstrations
     |
     v
module_exit()
     |
     v
Release object
</code></pre>
<hr />
<h1>20. A Practical Mental Model</h1>
<p>A simple way to remember the difference is to ask what the number means.</p>
<pre><code class="language-text">                    What does the number represent?
                                  |
                    +-------------+-------------+
                    |                           |
                    v                           v
             Activity / Events             Ownership / Lifetime
                    |                           |
                    v                           v
                atomic_t                    refcount_t
                    |                           |
                    v                           v
             "How many?"                 "Who still needs it?"
</code></pre>
<p>Examples:</p>
<pre><code class="language-text">How many packets were processed?
        |
        +--&gt; atomic_t


How many requests occurred?
        |
        +--&gt; atomic_t


How many references exist?
        |
        +--&gt; refcount_t


Can the object be freed?
        |
        +--&gt; refcount_t
</code></pre>
<hr />
<h1>21. Common Conceptual Mistakes</h1>
<h2>Mistake 1: Treating <code>atomic_t</code> as a lifetime mechanism</h2>
<p>An atomic counter can count events, but that does not automatically mean it correctly models object ownership.</p>
<pre><code class="language-c">atomic_t counter;
</code></pre>
<p>does not communicate the same lifetime semantics as:</p>
<pre><code class="language-c">refcount_t refs;
</code></pre>
<hr />
<h2>Mistake 2: Assuming atomic means thread-safe</h2>
<p>This:</p>
<pre><code class="language-c">atomic_inc(&amp;obj-&gt;counter);
</code></pre>
<p>only makes that atomic operation atomic.</p>
<p>It does not automatically protect:</p>
<pre><code class="language-c">obj-&gt;state;
obj-&gt;data;
obj-&gt;other_field;
</code></pre>
<hr />
<h2>Mistake 3: Assuming counters should match</h2>
<p>Consider:</p>
<pre><code class="language-text">Operations = 100
References = 2
</code></pre>
<p>There is nothing inherently wrong with this.</p>
<p>The values represent different concepts.</p>
<pre><code class="language-text">100 operations
      !=
2 references
</code></pre>
<hr />
<h2>Mistake 4: Forgetting to release references</h2>
<p>If a reference is acquired:</p>
<pre><code class="language-text">refs + 1
</code></pre>
<p>it must eventually be released:</p>
<pre><code class="language-text">refs - 1
</code></pre>
<p>Otherwise the object may never reach:</p>
<pre><code class="language-text">refs == 0
</code></pre>
<p>and therefore may never reach its intended cleanup state.</p>
<hr />
<h1>22. <code>atomic_t</code> and <code>refcount_t</code> in One Object</h1>
<p>A useful conceptual example is:</p>
<pre><code class="language-c">struct demo_object {
    atomic_t   operations;
    refcount_t refs;
};
</code></pre>
<p>The object now has two independent dimensions of state:</p>
<pre><code class="language-text">                    demo_object
                         |
              +----------+----------+
              |                     |
              v                     v
        operations                refs
              |                     |
              v                     v
          atomic_t              refcount_t
              |                     |
              v                     v
       Activity tracking      Lifetime tracking
</code></pre>
<p>For example:</p>
<pre><code class="language-text">operations = 500
refs       = 3
</code></pre>
<p>This means:</p>
<pre><code class="language-text">500 operations have been counted
3 references currently exist
</code></pre>
<p>It does <strong>not</strong> mean:</p>
<pre><code class="language-text">500 references
</code></pre>
<p>or:</p>
<pre><code class="language-text">3 operations
</code></pre>
<p>The two counters have independent meanings.</p>
<hr />
<h1>23. Key Lessons</h1>
<p>The most important concepts from this project are:</p>
<table>
<thead>
<tr>
<th>Concept</th>
<th>Lesson</th>
</tr>
</thead>
<tbody><tr>
<td><code>atomic_t</code></td>
<td>Use for atomic counter operations</td>
</tr>
<tr>
<td><code>refcount_t</code></td>
<td>Use for object reference counting</td>
</tr>
<tr>
<td>Reference acquisition</td>
<td>The object must remain alive while referenced</td>
</tr>
<tr>
<td>Reference release</td>
<td>Every acquired reference needs a release</td>
</tr>
<tr>
<td>Zero references</td>
<td>The object can reach its cleanup state</td>
</tr>
<tr>
<td><code>kmalloc()</code></td>
<td>Allocates kernel memory</td>
</tr>
<tr>
<td><code>kfree()</code></td>
<td>Releases kernel memory</td>
</tr>
<tr>
<td>Atomic operation</td>
<td>Does not make an entire algorithm thread-safe</td>
</tr>
<tr>
<td>Synchronization</td>
<td>May still be required around larger operations</td>
</tr>
</tbody></table>
<p>The central distinction is:</p>
<pre><code class="language-text">atomic_t
   |
   +--&gt; Atomic counting
   |
   +--&gt; Operations / events / statistics


refcount_t
   |
   +--&gt; Reference counting
   |
   +--&gt; Object ownership / lifetime
</code></pre>
<hr />
<h1>24. Where to Go Next</h1>
<p>This demonstration is intentionally small.</p>
<p>Once the basic concepts are clear, the next step is to move from isolated API demonstrations toward realistic Linux kernel concurrency and lifetime-management patterns.</p>
<p>A useful progression is:</p>
<table>
<thead>
<tr>
<th>Stage</th>
<th>Topic</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td><code>atomic_t</code></td>
</tr>
<tr>
<td>2</td>
<td><code>refcount_t</code></td>
</tr>
<tr>
<td>3</td>
<td>Object lifetime management</td>
</tr>
<tr>
<td>4</td>
<td>Kernel threads</td>
</tr>
<tr>
<td>5</td>
<td>Spinlocks</td>
</tr>
<tr>
<td>6</td>
<td>Mutexes</td>
</tr>
<tr>
<td>7</td>
<td>Character devices</td>
</tr>
<tr>
<td>8</td>
<td>Concurrent user-space access</td>
</tr>
<tr>
<td>9</td>
<td><code>kref</code></td>
</tr>
<tr>
<td>10</td>
<td>RCU</td>
</tr>
<tr>
<td>11</td>
<td>Memory ordering</td>
</tr>
<tr>
<td>12</td>
<td>Real kernel subsystem patterns</td>
</tr>
</tbody></table>
<p>The progression can be visualized as:</p>
<pre><code class="language-text">atomic_t
   |
   v
refcount_t
   |
   v
Object Lifetime
   |
   v
Kernel Threads
   |
   v
Spinlocks
   |
   v
Mutexes
   |
   v
Character Devices
   |
   v
Concurrent User-Space Access
   |
   v
kref
   |
   v
RCU
   |
   v
Memory Ordering
   |
   v
Real Kernel Subsystem Patterns
</code></pre>
<p>This moves the learning process from simple primitives toward the concurrency and lifetime-management techniques used in larger kernel components.</p>
<hr />
<h1>25. Final Takeaway</h1>
<p>The entire distinction can be summarized with two questions:</p>
<table>
<thead>
<tr>
<th>Primitive</th>
<th>Think About</th>
</tr>
</thead>
<tbody><tr>
<td><code>atomic_t</code></td>
<td><strong>"How many operations or events?"</strong></td>
</tr>
<tr>
<td><code>refcount_t</code></td>
<td><strong>"How many references keep this object alive?"</strong></td>
</tr>
</tbody></table>
<p>Or, even more simply:</p>
<pre><code class="language-text">              atomic_t
                  |
                  v
       "How many operations?"
                  |
                  v
          Atomic counting


              refcount_t
                  |
                  v
       "Who still references it?"
                  |
                  v
          Object lifetime
</code></pre>
<p>A well-designed kernel component should use the primitive that matches the <strong>meaning of the data</strong>.</p>
<pre><code class="language-text">atomic_t
    =
atomic counting


refcount_t
    =
reference counting
    +
object lifetime
</code></pre>
<p>Understanding this distinction provides a strong foundation for more advanced Linux kernel topics such as:</p>
<ul>
<li><p>concurrency</p>
</li>
<li><p>locking</p>
</li>
<li><p>reference ownership</p>
</li>
<li><p>character drivers</p>
</li>
<li><p><code>kref</code></p>
</li>
<li><p>RCU</p>
</li>
<li><p>memory ordering</p>
</li>
<li><p>lifetime management</p>
</li>
</ul>
<p>The key lesson is therefore not simply how to call the APIs.</p>
<p>It is understanding <strong>why the kernel provides different primitives for different meanings</strong>.</p>
<hr />
<h1>GitHub Repository</h1>
<p>The complete source code, build files, and module implementation are available here:</p>
<p><a href="https://github.com/aj333git/linux_kernel_atomic_refcount_2"><strong>linux_kernel_atomic_refcount_2</strong></a></p>
<p>Explore the repository to see the concepts demonstrated in an actual Linux kernel module.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Linux Kernel Threads and Spinlocks]]></title><description><![CDATA[Introduction
Concurrent execution is an important concept in operating systems and kernel development. Modern processors can execute multiple tasks concurrently, often across multiple CPU cores. When ]]></description><link>https://devnation.joshisfitness.com/understanding-linux-kernel-threads-and-spinlocks</link><guid isPermaLink="true">https://devnation.joshisfitness.com/understanding-linux-kernel-threads-and-spinlocks</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Wed, 02 Sep 2026 13:50:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/944ae4d9-818b-469c-8741-a789a4b8a096.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Concurrent execution is an important concept in operating systems and kernel development. Modern processors can execute multiple tasks concurrently, often across multiple CPU cores. When multiple execution contexts access the same shared resource, synchronization becomes necessary to prevent inconsistent or unexpected results.</p>
<p>Linux provides several synchronization mechanisms for kernel development. One of the commonly used mechanisms is the <strong>spinlock</strong>.</p>
<p>This article explains the concept of combining <strong>Linux kernel threads</strong> with a <strong>spinlock-protected shared counter</strong>. The focus is on understanding the design, synchronization mechanism, execution flow, and expected behavior rather than implementation details.</p>
<hr />
<h2>What Is a Linux Kernel Thread?</h2>
<p>A Linux kernel thread is a thread that executes entirely within kernel space.</p>
<p>Kernel threads are useful for performing background work that is managed by the kernel rather than directly by a user-space application.</p>
<p>A kernel thread:</p>
<ul>
<li>Runs in kernel space.</li>
<li>Is scheduled by the Linux scheduler.</li>
<li>Can execute concurrently with other kernel threads.</li>
<li>Can access kernel data structures and resources.</li>
<li>Can be started and stopped by kernel code.</li>
<li>Can execute independently of a normal user-space process.</li>
</ul>
<p>Kernel threads are commonly used for background kernel activities such as:</p>
<ul>
<li>Deferred processing.</li>
<li>Device-related operations.</li>
<li>Background maintenance.</li>
<li>Resource management.</li>
<li>Kernel subsystems that require independent execution contexts.</li>
</ul>
<hr />
<h2>Why Synchronization Is Necessary</h2>
<p>Consider a shared counter accessed by two kernel threads.</p>
<p>Both threads perform repeated increments of the same variable.</p>
<p>At first glance, incrementing a counter appears to be a simple operation. However, an increment is conceptually composed of multiple steps:</p>
<ol>
<li>Read the current value.</li>
<li>Add one to the value.</li>
<li>Write the new value back.</li>
</ol>
<p>When two threads perform these operations concurrently, their actions can overlap.</p>
<p>For example:</p>
<table>
<thead>
<tr>
<th>Thread 1</th>
<th>Thread 2</th>
</tr>
</thead>
<tbody><tr>
<td>Reads the counter</td>
<td></td>
</tr>
<tr>
<td></td>
<td>Reads the same counter</td>
</tr>
<tr>
<td>Adds one</td>
<td></td>
</tr>
<tr>
<td></td>
<td>Adds one</td>
</tr>
<tr>
<td>Writes the result</td>
<td></td>
</tr>
<tr>
<td></td>
<td>Writes the result</td>
</tr>
</tbody></table>
<p>Both threads may calculate their new value from the same original value.</p>
<p>As a result, one increment can effectively overwrite another increment.</p>
<p>This situation is known as a <strong>race condition</strong>.</p>
<hr />
<h2>What Is a Race Condition?</h2>
<p>A race condition occurs when the final result of an operation depends on the timing or ordering of concurrent execution.</p>
<p>Race conditions are particularly dangerous in kernel programming because kernel code often works with shared resources used by multiple execution contexts.</p>
<p>A race condition can result in:</p>
<ul>
<li>Incorrect counter values.</li>
<li>Corrupted data.</li>
<li>Inconsistent state.</li>
<li>Difficult-to-reproduce bugs.</li>
<li>Unexpected system behavior.</li>
</ul>
<p>The problem is not necessarily that either thread is incorrect individually. The problem is that both threads are accessing shared state without sufficient synchronization.</p>
<hr />
<h2>The Role of a Spinlock</h2>
<p>A spinlock provides mutual exclusion.</p>
<p>Its purpose is to ensure that only one execution context can enter a protected critical section at a time.</p>
<p>The basic concept is:</p>
<ol>
<li>A thread attempts to acquire the lock.</li>
<li>If the lock is available, the thread acquires it.</li>
<li>The thread accesses the protected resource.</li>
<li>The thread releases the lock.</li>
<li>Another waiting thread can acquire the lock.</li>
</ol>
<p>This prevents two threads from modifying the same protected data simultaneously.</p>
<hr />
<h2>Critical Section</h2>
<p>A <strong>critical section</strong> is a portion of code that accesses shared data and therefore must be protected from concurrent modification.</p>
<p>In the counter example, the critical section contains the counter update.</p>
<p>The conceptual execution becomes:</p>
<table>
<thead>
<tr>
<th>Step</th>
<th>Thread 1</th>
<th>Thread 2</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Acquires lock</td>
<td>Waits</td>
</tr>
<tr>
<td>2</td>
<td>Updates counter</td>
<td>Waits</td>
</tr>
<tr>
<td>3</td>
<td>Releases lock</td>
<td>Waits</td>
</tr>
<tr>
<td>4</td>
<td>Continues execution</td>
<td>Acquires lock</td>
</tr>
<tr>
<td>5</td>
<td>Continues</td>
<td>Updates counter</td>
</tr>
<tr>
<td>6</td>
<td>Continues</td>
<td>Releases lock</td>
</tr>
</tbody></table>
<p>The important property is that the shared counter update is serialized.</p>
<hr />
<h2>How the Two Threads Work</h2>
<p>The example uses two kernel threads.</p>
<p>Each thread performs a fixed number of counter updates.</p>
<p>The threads share:</p>
<ul>
<li>A common counter.</li>
<li>A common spinlock.</li>
</ul>
<p>Each thread also maintains its own individual count.</p>
<p>This provides two different types of information:</p>
<ul>
<li>The shared counter shows the total number of protected operations.</li>
<li>The individual counters show how many operations each thread performed.</li>
</ul>
<p>This makes the example useful for understanding both synchronization and concurrent execution.</p>
<hr />
<h2>Shared Data and Private Data</h2>
<p>The design can be divided into shared and thread-specific data.</p>
<table>
<thead>
<tr>
<th>Data</th>
<th>Purpose</th>
<th>Shared?</th>
</tr>
</thead>
<tbody><tr>
<td>Counter</td>
<td>Stores the total number of increments</td>
<td>Yes</td>
</tr>
<tr>
<td>Spinlock</td>
<td>Protects shared data</td>
<td>Yes</td>
</tr>
<tr>
<td>Thread 1 count</td>
<td>Tracks Thread 1 operations</td>
<td>No, logically thread-specific</td>
</tr>
<tr>
<td>Thread 2 count</td>
<td>Tracks Thread 2 operations</td>
<td>No, logically thread-specific</td>
</tr>
<tr>
<td>Thread identifiers</td>
<td>Identify the executing worker</td>
<td>No</td>
</tr>
</tbody></table>
<p>The shared counter requires synchronization because both threads modify it.</p>
<hr />
<h2>Why the Spinlock Protects the Counter</h2>
<p>Without synchronization, both threads can access the counter at the same time.</p>
<p>With a spinlock, access becomes mutually exclusive.</p>
<p>The conceptual relationship is:</p>
<p><strong>Two kernel threads → One shared counter → One spinlock → Controlled access</strong></p>
<p>The lock does not prevent the threads from existing simultaneously.</p>
<p>Instead, it controls when they are allowed to access the protected resource.</p>
<p>This distinction is important.</p>
<hr />
<h2>Spinlocks and Waiting</h2>
<p>A spinlock is different from a traditional sleeping synchronization mechanism.</p>
<p>When a thread cannot immediately acquire a spinlock, it waits by repeatedly checking the lock rather than putting itself to sleep.</p>
<p>This behavior is called <strong>spinning</strong>.</p>
<p>Spinning can be useful when:</p>
<ul>
<li>The protected critical section is very short.</li>
<li>The expected waiting time is small.</li>
<li>Sleeping is not appropriate in the current execution context.</li>
</ul>
<p>However, spinning also consumes CPU resources while waiting.</p>
<p>Therefore, spinlocks should generally protect short critical sections.</p>
<hr />
<h2>Why the Critical Section Should Be Small</h2>
<p>A spinlock should not be held for unnecessarily long periods.</p>
<p>Suppose Thread 1 acquires a spinlock and performs a lengthy operation while holding it.</p>
<p>Thread 2 cannot enter the protected section during that period and may continuously spin while waiting.</p>
<p>This wastes CPU time.</p>
<p>A good synchronization design therefore aims to:</p>
<ul>
<li>Acquire the lock as late as practical.</li>
<li>Perform only necessary protected operations.</li>
<li>Release the lock as soon as possible.</li>
<li>Avoid lengthy operations while holding the lock.</li>
</ul>
<p>In the counter example, the protected operation is intentionally small, making it suitable for demonstrating a spinlock.</p>
<hr />
<h2>Initial Counter Update</h2>
<p>The combined example also performs a protected counter update during module initialization.</p>
<p>This demonstrates that spinlocks are not limited to kernel-thread synchronization.</p>
<p>A spinlock can protect shared kernel data whenever multiple execution contexts could potentially access that data.</p>
<p>The initial update establishes a starting value before the worker threads perform their operations.</p>
<hr />
<h2>Final Counter Calculation</h2>
<p>The example performs one initial increment.</p>
<p>Each of the two worker threads then performs one hundred thousand increments.</p>
<p>Therefore, the expected total is:</p>
<table>
<thead>
<tr>
<th>Source</th>
<th>Increments</th>
</tr>
</thead>
<tbody><tr>
<td>Module initialization</td>
<td>1</td>
</tr>
<tr>
<td>Thread 1</td>
<td>100,000</td>
</tr>
<tr>
<td>Thread 2</td>
<td>100,000</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td><strong>200,001</strong></td>
</tr>
</tbody></table>
<p>The final counter therefore demonstrates that the protected updates were successfully preserved.</p>
<hr />
<h2>Individual Thread Counters</h2>
<p>The example also maintains an individual count for each worker.</p>
<p>The expected values are:</p>
<table>
<thead>
<tr>
<th>Thread</th>
<th>Expected Operations</th>
</tr>
</thead>
<tbody><tr>
<td>Thread 1</td>
<td>100,000</td>
</tr>
<tr>
<td>Thread 2</td>
<td>100,000</td>
</tr>
</tbody></table>
<p>These counters provide additional visibility into the work performed by each kernel thread.</p>
<p>They also help verify that both threads completed their expected workloads.</p>
<hr />
<h2>Kernel Thread Lifecycle</h2>
<p>A kernel thread has a lifecycle similar to other kernel-managed execution contexts.</p>
<p>The general lifecycle is:</p>
<ol>
<li>Module initialization begins.</li>
<li>The shared state is initialized.</li>
<li>The first worker thread is created.</li>
<li>The second worker thread is created.</li>
<li>Both threads execute concurrently.</li>
<li>Each thread performs its assigned work.</li>
<li>Each thread finishes.</li>
<li>The module can later be unloaded.</li>
<li>Cleanup ensures the thread resources are properly handled.</li>
</ol>
<p>This lifecycle demonstrates an important principle of kernel programming:</p>
<p><strong>Resources created by a kernel module must be managed carefully and cleaned up appropriately.</strong></p>
<hr />
<h2>Stopping Kernel Threads</h2>
<p>The worker design also supports a stop request.</p>
<p>A kernel thread should not simply be assumed to terminate immediately when the module is being removed.</p>
<p>Instead, the thread can periodically check whether it has been asked to stop.</p>
<p>This creates a cooperative termination mechanism.</p>
<p>The general concept is:</p>
<ul>
<li>The module requests that the worker stop.</li>
<li>The worker notices the stop request.</li>
<li>The worker exits its execution loop.</li>
<li>The worker returns.</li>
<li>Cleanup continues.</li>
</ul>
<p>This is safer than assuming that a running kernel thread can simply be terminated from outside.</p>
<hr />
<h2>Error Handling</h2>
<p>Kernel programming requires careful error handling because resource creation can fail.</p>
<p>For example, the first thread may be created successfully while the second thread fails to start.</p>
<p>In that situation, the module should not simply abandon the first thread.</p>
<p>The appropriate design is:</p>
<ol>
<li>Detect the second thread creation failure.</li>
<li>Stop the already-created first thread.</li>
<li>Clean up the partially initialized state.</li>
<li>Return the appropriate error.</li>
</ol>
<p>This is an example of <strong>failure-path cleanup</strong>.</p>
<p>Good kernel code should consider both:</p>
<ul>
<li>The successful execution path.</li>
<li>The partial-failure path.</li>
</ul>
<hr />
<h2>Why Error Handling Matters More in Kernel Code</h2>
<p>Errors in kernel code can have consequences beyond a single application.</p>
<p>Poor cleanup can result in:</p>
<ul>
<li>Resource leaks.</li>
<li>Threads continuing to run unexpectedly.</li>
<li>Invalid references.</li>
<li>Kernel instability.</li>
<li>Difficult-to-debug failures.</li>
</ul>
<p>Therefore, kernel modules should carefully manage every resource they create.</p>
<hr />
<h2>Spinlock Versus No Synchronization</h2>
<p>The difference can be summarized conceptually:</p>
<table>
<thead>
<tr>
<th>Without synchronization</th>
<th>With spinlock</th>
</tr>
</thead>
<tbody><tr>
<td>Multiple threads can update shared data simultaneously</td>
<td>Access is serialized</td>
</tr>
<tr>
<td>Race conditions are possible</td>
<td>Race conditions are prevented for the protected section</td>
</tr>
<tr>
<td>Final result may be incorrect</td>
<td>Final result is deterministic under the demonstrated workload</td>
</tr>
<tr>
<td>Shared data is vulnerable to concurrent modification</td>
<td>Shared data is protected</td>
</tr>
<tr>
<td>Debugging can be difficult</td>
<td>Access rules are explicit</td>
</tr>
</tbody></table>
<p>The spinlock does not make the threads execute sequentially overall.</p>
<p>It only serializes access to the protected critical section.</p>
<hr />
<h2>Spinlock Versus Mutex</h2>
<p>Spinlocks and mutexes are both synchronization mechanisms, but they have different characteristics.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Spinlock</th>
<th>Mutex</th>
</tr>
</thead>
<tbody><tr>
<td>Waiting behavior</td>
<td>Spins</td>
<td>Can sleep</td>
</tr>
<tr>
<td>CPU usage while waiting</td>
<td>Higher</td>
<td>Lower</td>
</tr>
<tr>
<td>Suitable for very short critical sections</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Can sleep while holding it</td>
<td>No</td>
<td>Generally no sleeping-dependent usage within the critical section</td>
</tr>
<tr>
<td>Common use</td>
<td>Short kernel critical sections</td>
<td>Longer operations where sleeping is acceptable</td>
</tr>
<tr>
<td>Main advantage</td>
<td>Very low waiting overhead for short waits</td>
<td>Avoids wasting CPU while waiting</td>
</tr>
</tbody></table>
<p>The choice depends on the execution context and the expected duration of the critical section.</p>
<p>A spinlock is particularly useful when the protected operation is short and sleeping is not appropriate.</p>
<hr />
<h2>Important Kernel Programming Considerations</h2>
<p>When using spinlocks in Linux kernel code, several principles are important.</p>
<h3>Keep Critical Sections Short</h3>
<p>Long critical sections increase contention and can waste CPU resources.</p>
<h3>Do Not Sleep While Holding a Spinlock</h3>
<p>A spinlock is designed for atomic, non-sleeping sections of kernel code.</p>
<h3>Protect the Correct Data</h3>
<p>The lock must protect every access that requires synchronization.</p>
<p>Protecting only some accesses can still leave race conditions.</p>
<h3>Release the Lock</h3>
<p>Every successful lock acquisition must have a corresponding release.</p>
<h3>Handle Failure Paths</h3>
<p>If initialization partially succeeds, previously allocated or started resources must be cleaned up.</p>
<hr />
<h2>What This Example Demonstrates</h2>
<p>The small kernel module combines several important operating-system concepts:</p>
<ul>
<li>Kernel module lifecycle.</li>
<li>Kernel threads.</li>
<li>Shared memory.</li>
<li>Race conditions.</li>
<li>Mutual exclusion.</li>
<li>Spinlocks.</li>
<li>Critical sections.</li>
<li>Thread synchronization.</li>
<li>Thread termination.</li>
<li>Error handling.</li>
<li>Resource cleanup.</li>
</ul>
<p>Because the example uses a simple counter, the synchronization behavior is easy to understand without introducing unnecessary kernel subsystems.</p>
<hr />
<h2>Conceptual Execution Flow</h2>
<p>The overall flow can be summarized as:</p>
<p><strong>Module initialization</strong></p>
<p>The module initializes its shared state and performs an initial protected update.</p>
<p><strong>Thread creation</strong></p>
<p>Two worker threads are created.</p>
<p><strong>Concurrent execution</strong></p>
<p>Both threads begin performing their assigned operations.</p>
<p><strong>Synchronization</strong></p>
<p>Before modifying the shared counter, each thread must obtain the spinlock.</p>
<p><strong>Critical section</strong></p>
<p>The counter and corresponding thread-specific statistics are updated.</p>
<p><strong>Lock release</strong></p>
<p>The thread releases the spinlock so another thread can access the protected data.</p>
<p><strong>Thread completion</strong></p>
<p>Both workers eventually complete their workloads.</p>
<p><strong>Module cleanup</strong></p>
<p>The module ensures that the worker threads have stopped and then reports the final statistics.</p>
<hr />
<h2>Key Learning Points</h2>
<p>The most important lessons from this example are:</p>
<ul>
<li>Concurrent execution creates the possibility of race conditions.</li>
<li>Shared kernel data must be synchronized appropriately.</li>
<li>A spinlock provides mutual exclusion for a critical section.</li>
<li>Spinlocks are especially useful for short, non-sleeping critical sections.</li>
<li>Kernel threads can execute concurrently and access shared kernel state.</li>
<li>Thread termination should be handled cooperatively.</li>
<li>Kernel modules must clean up resources during failure and removal.</li>
<li>Synchronization protects data; it does not eliminate concurrency.</li>
<li>A good critical section should be as small as practical.</li>
<li>Correct synchronization makes concurrent behavior predictable.</li>
</ul>
<hr />
<h2>Conclusion</h2>
<p>Linux kernel threads provide a mechanism for executing kernel-level work concurrently. While concurrency improves flexibility and allows multiple activities to progress independently, it also introduces synchronization challenges.</p>
<p>A shared counter is a simple but effective example of this problem. Two kernel threads can access the same variable simultaneously, creating the possibility of a race condition. A spinlock solves this problem by ensuring that only one thread at a time can enter the critical section responsible for modifying the shared data.</p>
<p>The combined design demonstrates more than just how a spinlock works. It also illustrates kernel-thread lifecycle management, error handling, protected initialization and cleanup, and the importance of keeping synchronization regions small.</p>
<p>The broader lesson is fundamental to kernel development:</p>
<blockquote>
<p><strong>Concurrency requires synchronization whenever multiple execution contexts access shared mutable state.</strong></p>
</blockquote>
<p>Understanding this principle provides a strong foundation for studying more advanced Linux kernel synchronization mechanisms and concurrent operating-system design.</p>
<p>GitHub Repository: 👉 <strong><a href="https://github.com/aj333git/linux_kernel_spin_lock_1">spin_lock_1</a></strong> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Linux Kernel-Priority Inheritance ]]></title><description><![CDATA[Introduction
Priority inversion is a classic scheduling problem in real-time and concurrent systems.
It occurs when a high-priority task is forced to wait for a lower-priority task, while a medium-pri]]></description><link>https://devnation.joshisfitness.com/linux-kernel-priority-inheritance</link><guid isPermaLink="true">https://devnation.joshisfitness.com/linux-kernel-priority-inheritance</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Sat, 22 Aug 2026 14:13:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/e08086e0-9702-4001-884d-54d15294074a.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p><strong>Priority inversion</strong> is a classic scheduling problem in real-time and concurrent systems.</p>
<p>It occurs when a <strong>high-priority task is forced to wait for a lower-priority task</strong>, while a medium-priority task can continue executing.</p>
<p>The basic model uses three tasks:</p>
<table>
<thead>
<tr>
<th>Task</th>
<th>Conceptual Priority</th>
<th>Role</th>
</tr>
</thead>
<tbody><tr>
<td><strong>HIGH</strong></td>
<td>80</td>
<td>Needs the shared resource</td>
</tr>
<tr>
<td><strong>MEDIUM</strong></td>
<td>50</td>
<td>Performs unrelated work</td>
</tr>
<tr>
<td><strong>LOW</strong></td>
<td>10</td>
<td>Owns the shared resource</td>
</tr>
</tbody></table>
<p>The important distinction is:</p>
<blockquote>
<p><strong>Priority inversion is the problem. Priority inheritance is one mechanism used to mitigate it.</strong></p>
</blockquote>
<p>This article explores the concept from a Linux kernel perspective using <strong>kernel threads</strong> and the Linux <code>rt_mutex</code> mechanism.</p>
<hr />
<h2>1. What Is Priority Inversion?</h2>
<p>Suppose a low-priority task obtains a mutex.</p>
<p>A high-priority task subsequently needs the same mutex.</p>
<p>The high-priority task cannot continue because the resource is currently owned by LOW.</p>
<p>The situation becomes problematic when MEDIUM gets CPU time while LOW is unable to finish its critical section.</p>
<p>The logical sequence is:</p>
<ol>
<li><p>LOW acquires the mutex.</p>
</li>
<li><p>HIGH attempts to acquire the mutex.</p>
</li>
<li><p>HIGH blocks.</p>
</li>
<li><p>MEDIUM performs unrelated work.</p>
</li>
<li><p>LOW is delayed.</p>
</li>
<li><p>HIGH remains blocked.</p>
</li>
<li><p>LOW eventually releases the mutex.</p>
</li>
<li><p>HIGH can finally continue.</p>
</li>
</ol>
<p>The surprising part is that HIGH has a higher priority than MEDIUM and LOW, yet MEDIUM can indirectly contribute to HIGH's delay.</p>
<p>That is the essence of <strong>priority inversion</strong>.</p>
<hr />
<h2>2. Priority Inversion vs Priority Inheritance</h2>
<p>These two terms should not be confused.</p>
<table>
<thead>
<tr>
<th>Concept</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Priority inversion</strong></td>
<td>A scheduling problem</td>
</tr>
<tr>
<td><strong>Priority inheritance</strong></td>
<td>A technique for mitigating that problem</td>
</tr>
<tr>
<td><strong>HIGH</strong></td>
<td>The task waiting for the resource</td>
</tr>
<tr>
<td><strong>LOW</strong></td>
<td>The task currently owning the resource</td>
</tr>
<tr>
<td><strong>MEDIUM</strong></td>
<td>A competing task that can contribute to the delay</td>
</tr>
<tr>
<td><code>rt_mutex</code></td>
<td>Linux kernel synchronization primitive associated with PI</td>
</tr>
</tbody></table>
<p>The important relationship is:</p>
<pre><code class="language-text">Priority inversion = problem
Priority inheritance = mitigation
</code></pre>
<hr />
<h2>3. The Classic Example</h2>
<p>Consider:</p>
<pre><code class="language-text">HIGH    = 80
MEDIUM  = 50
LOW     = 10
</code></pre>
<p>LOW acquires a shared resource first.</p>
<p>HIGH later needs the same resource.</p>
<p>HIGH therefore blocks.</p>
<p>If MEDIUM can execute while LOW is waiting for CPU time, HIGH's effective waiting time can increase.</p>
<p>Conceptually:</p>
<pre><code class="language-text">LOW owns resource
        ↓
HIGH needs resource
        ↓
HIGH blocks
        ↓
MEDIUM executes
        ↓
LOW is delayed
        ↓
HIGH remains blocked
</code></pre>
<p>This is why priority inversion matters in systems where predictable response time is important.</p>
<hr />
<h2>4. What Is Priority Inheritance?</h2>
<p>Priority inheritance addresses the dependency between the waiting task and the lock owner.</p>
<p>If HIGH is waiting for a mutex owned by LOW, LOW can temporarily inherit HIGH's priority.</p>
<p>Conceptually:</p>
<pre><code class="language-text">LOW priority: 10
        ↓
HIGH waits
        ↓
LOW temporarily inherits HIGH's priority
        ↓
LOW completes critical section
        ↓
LOW releases mutex
        ↓
HIGH continues
        ↓
LOW returns to its original priority
</code></pre>
<p>The goal is straightforward:</p>
<blockquote>
<p>Allow the lower-priority lock owner to finish the critical section sooner so that the higher-priority waiter can proceed.</p>
</blockquote>
<hr />
<h2>5. Why <code>rt_mutex</code> Matters in Linux</h2>
<p>The Linux kernel provides <code>rt_mutex</code> as a real-time mutex implementation with priority-inheritance support.</p>
<p>A simplified example is:</p>
<pre><code class="language-c">static struct rt_mutex lock;

rt_mutex_init(&amp;lock);

rt_mutex_lock(&amp;lock);

/* critical section */

rt_mutex_unlock(&amp;lock);
</code></pre>
<p>The important API calls are:</p>
<ul>
<li><p><code>rt_mutex_init()</code></p>
</li>
<li><p><code>rt_mutex_lock()</code></p>
</li>
<li><p><code>rt_mutex_unlock()</code></p>
</li>
</ul>
<p>In the demonstration module, the shared lock is declared as:</p>
<pre><code class="language-c">static struct rt_mutex pi_lock;
</code></pre>
<p>and initialized during module loading.</p>
<hr />
<h2>6. Kernel Threads</h2>
<p>The demonstration uses Linux kernel threads rather than ordinary user-space processes.</p>
<p>The three conceptual participants are:</p>
<ul>
<li><p><strong>LOW</strong></p>
</li>
<li><p><strong>HIGH</strong></p>
</li>
<li><p><strong>MEDIUM</strong></p>
</li>
</ul>
<p>Kernel threads can be created using APIs such as:</p>
<pre><code class="language-c">kthread_run(low_thread, NULL, "pi_low");
</code></pre>
<p>The returned <code>task_struct</code> pointer allows the module to retain a reference to the created kernel thread.</p>
<p>For example:</p>
<pre><code class="language-c">static struct task_struct *low_task;
</code></pre>
<p>The same approach is used for HIGH and MEDIUM.</p>
<hr />
<h2>7. The LOW Thread</h2>
<p>LOW is responsible for acquiring the <code>rt_mutex</code>.</p>
<p>The important operation is:</p>
<pre><code class="language-c">rt_mutex_lock(&amp;pi_lock);
</code></pre>
<p>After acquiring the lock, LOW enters its critical section.</p>
<p>The demonstration deliberately keeps LOW holding the mutex for some time so that HIGH can attempt to acquire it.</p>
<p>The important relationship is therefore:</p>
<blockquote>
<p>LOW owns the resource while HIGH needs it.</p>
</blockquote>
<p>The module also prints scheduling information before and during the interaction.</p>
<hr />
<h2>8. The HIGH Thread</h2>
<p>HIGH attempts to acquire the same mutex:</p>
<pre><code class="language-c">rt_mutex_lock(&amp;pi_lock);
</code></pre>
<p>If LOW already owns the mutex, HIGH blocks.</p>
<p>The conceptual state is:</p>
<pre><code class="language-text">HIGH
  ↓
waiting for mutex
  ↓
LOW owns mutex
</code></pre>
<p>This is the critical point at which priority inheritance becomes relevant.</p>
<p>After LOW releases the mutex, HIGH can acquire it and continue.</p>
<hr />
<h2>9. The MEDIUM Thread</h2>
<p>MEDIUM represents independent work.</p>
<p>It does not need the shared mutex.</p>
<p>Its purpose is to model the classic third participant in a priority-inversion scenario.</p>
<p>The simplified model is:</p>
<table>
<thead>
<tr>
<th>Task</th>
<th>Needs mutex?</th>
<th>Role</th>
</tr>
</thead>
<tbody><tr>
<td>LOW</td>
<td>Yes</td>
<td>Owns resource</td>
</tr>
<tr>
<td>HIGH</td>
<td>Yes</td>
<td>Waits for resource</td>
</tr>
<tr>
<td>MEDIUM</td>
<td>No</td>
<td>Performs unrelated work</td>
</tr>
</tbody></table>
<p>MEDIUM is therefore important because it illustrates how a task that has no direct relationship with the shared resource can still affect HIGH's waiting time.</p>
<hr />
<h2>10. A Linux 5.15 Constraint</h2>
<p>There is an important implementation detail in this particular experiment.</p>
<p>The target environment is <strong>Ubuntu Linux 5.15.x</strong>.</p>
<p>An earlier version attempted to use:</p>
<pre><code class="language-c">sched_setscheduler_nocheck()
</code></pre>
<p>to assign arbitrary scheduler priorities.</p>
<p>However, that scheduler interface was not exported for use by the external loadable module in the target Ubuntu kernel.</p>
<p>As a result, the module cannot simply depend on that internal scheduler interface.</p>
<p>The implementation therefore uses exported helpers such as:</p>
<pre><code class="language-c">sched_set_fifo_low(low_task);
sched_set_fifo(high_task);
</code></pre>
<p>This is an important Linux kernel development lesson:</p>
<blockquote>
<p>An API existing somewhere inside the kernel source does not automatically mean an out-of-tree module can call it.</p>
</blockquote>
<hr />
<h2>11. Theoretical Priorities vs Actual Scheduler State</h2>
<p>The textbook example commonly uses:</p>
<pre><code class="language-text">LOW    = 10
MEDIUM = 50
HIGH   = 80
</code></pre>
<p>However, those numbers should not be confused with the actual scheduler state of this module.</p>
<p>The current implementation uses the scheduler helpers available to the external module.</p>
<p>Therefore, the project deliberately distinguishes between:</p>
<h3>Conceptual model</h3>
<pre><code class="language-text">LOW    = 10
MEDIUM = 50
HIGH   = 80
</code></pre>
<h3>Actual implementation</h3>
<pre><code class="language-text">LOW    → sched_set_fifo_low()
HIGH   → sched_set_fifo()
MEDIUM  → normal kernel thread
</code></pre>
<p>The module prints actual scheduling fields such as:</p>
<ul>
<li><p><code>current-&gt;pid</code></p>
</li>
<li><p><code>current-&gt;policy</code></p>
</li>
<li><p><code>current-&gt;prio</code></p>
</li>
<li><p><code>current-&gt;normal_prio</code></p>
</li>
</ul>
<p>This is preferable to assuming that a theoretical priority value is the actual runtime value.</p>
<hr />
<h2>12. Standard Ubuntu Kernel vs PREEMPT_RT</h2>
<p>Another important limitation is kernel configuration.</p>
<p>The target environment is a standard/non-<code>PREEMPT_RT</code> Ubuntu kernel.</p>
<p>That means this project should primarily be viewed as a <strong>Linux kernel</strong> <code>rt_mutex</code> <strong>and priority-inheritance learning experiment</strong>, rather than a deterministic real-time benchmark.</p>
<p>The exact timing and scheduling behavior can depend on:</p>
<ul>
<li><p>Kernel configuration</p>
</li>
<li><p>Scheduler behavior</p>
</li>
<li><p>CPU topology</p>
</li>
<li><p>System load</p>
</li>
<li><p>Preemption configuration</p>
</li>
<li><p>Timing of <code>msleep()</code></p>
</li>
<li><p>Scheduling policy</p>
</li>
</ul>
<p>For a strict textbook real-time demonstration with controlled priorities such as <code>10 / 50 / 80</code>, a <strong>PREEMPT_RT kernel</strong> or an appropriately designed user-space POSIX experiment can be a better environment.</p>
<hr />
<h2>13. Why <code>msleep()</code> Is Used</h2>
<p>The demonstration uses delays such as:</p>
<pre><code class="language-c">msleep(1000);
</code></pre>
<p>These delays are not intended to provide precise real-time scheduling.</p>
<p>Their purpose is to create enough temporal separation for the demonstration:</p>
<ul>
<li><p>LOW gets time to start.</p>
</li>
<li><p>HIGH gets time to start.</p>
</li>
<li><p>LOW obtains the mutex.</p>
</li>
<li><p>HIGH subsequently attempts the mutex.</p>
</li>
<li><p>MEDIUM begins its work.</p>
</li>
</ul>
<p>Therefore, <code>msleep()</code> should be understood as a <strong>demonstration timing mechanism</strong>, not a real-time synchronization mechanism.</p>
<hr />
<h2>14. Module Lifecycle</h2>
<p>A kernel module has an important lifecycle:</p>
<pre><code class="language-text">Build
  ↓
Load
  ↓
Initialize
  ↓
Create kernel threads
  ↓
Run demonstration
  ↓
Synchronize completion
  ↓
Stop threads
  ↓
Unload
</code></pre>
<p>The module entry point is:</p>
<pre><code class="language-c">static int __init pi_demo_init(void)
</code></pre>
<p>The module exit point is:</p>
<pre><code class="language-c">static void __exit pi_demo_exit(void)
</code></pre>
<p>These are connected using:</p>
<pre><code class="language-c">module_init(pi_demo_init);
module_exit(pi_demo_exit);
</code></pre>
<hr />
<h2>15. Why Module Cleanup Matters</h2>
<p>Kernel thread lifecycle management is especially important.</p>
<p>An earlier version of the project experienced a kernel Oops during:</p>
<pre><code class="language-bash">sudo rmmod pi_demo
</code></pre>
<p>The reported instruction pointer was associated with:</p>
<pre><code class="language-text">kthread_stop()
</code></pre>
<p>This highlighted an important kernel-programming rule:</p>
<blockquote>
<p>Creating a kernel thread is only half of the problem. You must also correctly manage its entire lifecycle.</p>
</blockquote>
<p>A module must carefully handle:</p>
<ul>
<li><p>Thread creation</p>
</li>
<li><p>Thread execution</p>
</li>
<li><p>Thread blocking</p>
</li>
<li><p>Thread termination</p>
</li>
<li><p><code>kthread_stop()</code></p>
</li>
<li><p>Module removal</p>
</li>
</ul>
<hr />
<h2>16. Using Completion for Safe Cleanup</h2>
<p>The current design uses a kernel completion object:</p>
<pre><code class="language-c">static DECLARE_COMPLETION(demo_done);
</code></pre>
<p>HIGH signals completion after the actual demonstration:</p>
<pre><code class="language-c">complete(&amp;demo_done);
</code></pre>
<p>The module cleanup path waits for that event:</p>
<pre><code class="language-c">wait_for_completion(&amp;demo_done);
</code></pre>
<p>This gives the module a clear synchronization point before it proceeds with cleanup.</p>
<p>The lifecycle is therefore:</p>
<ol>
<li><p>Start demonstration.</p>
</li>
<li><p>HIGH reaches completion.</p>
</li>
<li><p>HIGH signals <code>demo_done</code>.</p>
</li>
<li><p>Module cleanup waits for completion.</p>
</li>
<li><p>Cleanup stops the threads.</p>
</li>
<li><p>Module is unloaded.</p>
</li>
</ol>
<p>This is safer than blindly stopping threads without considering their current state.</p>
<hr />
<h2>17. <code>task_struct</code> and Scheduler Information</h2>
<p>The module stores thread references using:</p>
<pre><code class="language-c">struct task_struct *
</code></pre>
<p>The current executing task can be accessed through:</p>
<pre><code class="language-c">current
</code></pre>
<p>The demonstration prints scheduler-related information from the current task.</p>
<p>For example:</p>
<pre><code class="language-c">pr_info("PID=%d policy=%d prio=%d normal_prio=%d\n",
        current-&gt;pid,
        current-&gt;policy,
        current-&gt;prio,
        current-&gt;normal_prio);
</code></pre>
<p>This is useful because kernel experiments should distinguish between:</p>
<ul>
<li><p>what the source code intends,</p>
</li>
<li><p>what the scheduler interface requests,</p>
</li>
<li><p>and what the kernel actually reports.</p>
</li>
</ul>
<hr />
<h2>18. Observing the Experiment with <code>dmesg</code></h2>
<p>Kernel modules normally use kernel logging APIs rather than <code>printf()</code>.</p>
<p>The demonstration uses messages such as:</p>
<pre><code class="language-c">pr_info("PI-DEMO: HIGH trying to acquire rt_mutex\n");
</code></pre>
<p>You can filter the kernel log with:</p>
<pre><code class="language-bash">sudo dmesg | grep PI-DEMO
</code></pre>
<p>For live output:</p>
<pre><code class="language-bash">sudo dmesg -w
</code></pre>
<p>This allows the experiment to be observed while the kernel threads execute.</p>
<hr />
<h2>19. Useful Commands</h2>
<h3>Build</h3>
<pre><code class="language-bash">make
</code></pre>
<h3>Check the module</h3>
<pre><code class="language-bash">ls -lh pi_demo.ko
</code></pre>
<h3>Load</h3>
<pre><code class="language-bash">sudo insmod ./pi_demo.ko
</code></pre>
<h3>Inspect output</h3>
<pre><code class="language-bash">sudo dmesg | grep PI-DEMO
</code></pre>
<h3>Follow output live</h3>
<pre><code class="language-bash">sudo dmesg -w
</code></pre>
<h3>Remove</h3>
<pre><code class="language-bash">sudo rmmod pi_demo
</code></pre>
<h3>Check whether it is loaded</h3>
<pre><code class="language-bash">lsmod | grep pi_demo
</code></pre>
<h3>Inspect recent messages</h3>
<pre><code class="language-bash">sudo dmesg | tail -30
</code></pre>
<h3>Inspect the complete PI demonstration</h3>
<pre><code class="language-bash">sudo dmesg | grep -A80 -B20 "PI-DEMO"
</code></pre>
<h3>Search for kernel problems</h3>
<pre><code class="language-bash">sudo dmesg | grep -E "BUG:|Oops:|WARNING:|PI-DEMO|kthread_stop" | tail -100
</code></pre>
<hr />
<h2>20. Recommended Laboratory Workflow</h2>
<p>A clean experiment can follow this sequence:</p>
<h3>Step 1 — Build</h3>
<pre><code class="language-bash">make
</code></pre>
<h3>Step 2 — Verify the module</h3>
<pre><code class="language-bash">ls -lh pi_demo.ko
</code></pre>
<h3>Step 3 — Load it</h3>
<pre><code class="language-bash">sudo insmod ./pi_demo.ko
</code></pre>
<h3>Step 4 — Observe the output</h3>
<pre><code class="language-bash">sudo dmesg | grep PI-DEMO
</code></pre>
<p>or:</p>
<pre><code class="language-bash">sudo dmesg -w
</code></pre>
<h3>Step 5 — Remove it after completion</h3>
<pre><code class="language-bash">sudo rmmod pi_demo
</code></pre>
<h3>Step 6 — Verify cleanup</h3>
<pre><code class="language-bash">sudo dmesg | tail -30
</code></pre>
<h3>Step 7 — Verify module state</h3>
<pre><code class="language-bash">lsmod | grep pi_demo
</code></pre>
<hr />
<h2>21. What This Project Teaches</h2>
<p>This relatively small module touches several important Linux kernel concepts.</p>
<h3>Kernel modules</h3>
<ul>
<li><p><code>module_init()</code></p>
</li>
<li><p><code>module_exit()</code></p>
</li>
<li><p><code>MODULE_LICENSE()</code></p>
</li>
<li><p><code>MODULE_AUTHOR()</code></p>
</li>
<li><p><code>MODULE_DESCRIPTION()</code></p>
</li>
<li><p><code>MODULE_VERSION()</code></p>
</li>
</ul>
<h3>Kernel threads</h3>
<ul>
<li><p><code>kthread_run()</code></p>
</li>
<li><p><code>kthread_stop()</code></p>
</li>
<li><p><code>kthread_should_stop()</code></p>
</li>
<li><p><code>struct task_struct</code></p>
</li>
</ul>
<h3>Synchronization</h3>
<ul>
<li><p><code>rt_mutex</code></p>
</li>
<li><p><code>rt_mutex_init()</code></p>
</li>
<li><p><code>rt_mutex_lock()</code></p>
</li>
<li><p><code>rt_mutex_unlock()</code></p>
</li>
</ul>
<h3>Completion</h3>
<ul>
<li><p><code>DECLARE_COMPLETION()</code></p>
</li>
<li><p><code>complete()</code></p>
</li>
<li><p><code>wait_for_completion()</code></p>
</li>
</ul>
<h3>Scheduling</h3>
<ul>
<li><p><code>sched_set_fifo()</code></p>
</li>
<li><p><code>sched_set_fifo_low()</code></p>
</li>
<li><p><code>current-&gt;policy</code></p>
</li>
<li><p><code>current-&gt;prio</code></p>
</li>
<li><p><code>current-&gt;normal_prio</code></p>
</li>
</ul>
<h3>Debugging</h3>
<ul>
<li><p><code>pr_info()</code></p>
</li>
<li><p><code>pr_err()</code></p>
</li>
<li><p><code>dmesg</code></p>
</li>
<li><p>Kernel Oops</p>
</li>
<li><p>Kernel warnings</p>
</li>
<li><p>Thread cleanup</p>
</li>
</ul>
<hr />
<h2>22. Common Conceptual Mistakes</h2>
<h3>Mistake 1: Priority inversion means LOW always runs before HIGH</h3>
<p>Not exactly.</p>
<p>The problem is the <strong>resource dependency</strong>.</p>
<p>HIGH is blocked because LOW owns a resource that HIGH needs.</p>
<hr />
<h3>Mistake 2: Priority inheritance means LOW permanently becomes HIGH priority</h3>
<p>No.</p>
<p>The inheritance is temporary and associated with the lock dependency.</p>
<p>After the relevant resource is released, the inherited priority can be removed.</p>
<hr />
<h3>Mistake 3: <code>rt_mutex</code> makes the entire system real-time</h3>
<p>No.</p>
<p>Using <code>rt_mutex</code> does not automatically transform a standard Ubuntu kernel into a deterministic real-time operating system.</p>
<p>Kernel configuration and scheduling behavior still matter.</p>
<hr />
<h3>Mistake 4: <code>sched_set_fifo()</code> lets an external module select any priority number</h3>
<p>No.</p>
<p>The exported helper does not provide arbitrary numeric priority assignment such as:</p>
<pre><code class="language-text">10
50
80
</code></pre>
<p>That was one of the important constraints encountered during development.</p>
<hr />
<h3>Mistake 5: If the code compiles, <code>rmmod</code> is automatically safe</h3>
<p>No.</p>
<p>Module cleanup is part of kernel correctness.</p>
<p>Thread lifecycle bugs can surface only during module removal.</p>
<hr />
<h2>23. Priority Inheritance in One Sentence</h2>
<blockquote>
<p><strong>Priority inheritance temporarily raises the effective priority of a lower-priority task holding a resource needed by a higher-priority task, helping the lock owner finish and release the resource sooner.</strong></p>
</blockquote>
<hr />
<h2>24. Final Takeaway</h2>
<p>Priority inversion demonstrates why <strong>synchronization and scheduling cannot be studied completely independently</strong>.</p>
<p>A mutex determines who can access a resource.</p>
<p>The scheduler determines which runnable task gets CPU time.</p>
<p>Priority inheritance connects these two concerns when a high-priority task is blocked by a lower-priority lock owner.</p>
<p>In Linux, <code>rt_mutex</code> provides the kernel mechanism used for priority inheritance.</p>
<p>This project combines:</p>
<table>
<thead>
<tr>
<th>Area</th>
<th>Linux concept</th>
</tr>
</thead>
<tbody><tr>
<td>Module</td>
<td><code>.ko</code>, <code>module_init()</code>, <code>module_exit()</code></td>
</tr>
<tr>
<td>Threads</td>
<td><code>kthread_run()</code>, <code>kthread_stop()</code></td>
</tr>
<tr>
<td>Synchronization</td>
<td><code>rt_mutex</code></td>
</tr>
<tr>
<td>Priority inheritance</td>
<td>PI behavior associated with <code>rt_mutex</code></td>
</tr>
<tr>
<td>Scheduling</td>
<td>FIFO scheduler helpers</td>
</tr>
<tr>
<td>Synchronization lifecycle</td>
<td>Completion</td>
</tr>
<tr>
<td>Diagnostics</td>
<td><code>pr_info()</code>, <code>dmesg</code></td>
</tr>
<tr>
<td>Debugging</td>
<td>Oops, warnings, cleanup analysis</td>
</tr>
</tbody></table>
<p>The most important lesson is not simply how to call <code>rt_mutex_lock()</code>.</p>
<p>It is understanding the complete relationship between:</p>
<p><strong>task → scheduler → resource → mutex → blocking → priority inheritance → critical section → unlock → task lifecycle → module cleanup.</strong></p>
<hr />
<h2>GitHub Repository</h2>
<p><strong>Priority Inheritance Repository:</strong> 👉 <a href="https://github.com/aj333git/linux_kernel_priority_inheritance"><strong>priority_inheritance</strong></a></p>
<p>Explore the complete source code, build files, and module implementation.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Linux Kernel Priority Inversion: Mutex, Scheduling and Priority Inheritance]]></title><description><![CDATA[Introduction
Priority inversion is a classic concurrency and real-time scheduling problem in operating systems.
The basic situation is simple:

A LOW-priority thread owns a mutex.
A HIGH-priority thre]]></description><link>https://devnation.joshisfitness.com/linux-kernel-priority-inversion-mutex-scheduling-and-priority-inheritance</link><guid isPermaLink="true">https://devnation.joshisfitness.com/linux-kernel-priority-inversion-mutex-scheduling-and-priority-inheritance</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[coding]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Fri, 21 Aug 2026 08:40:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/3519a99b-3611-4f9f-8523-9a16f6614a3d.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Priority inversion is a classic concurrency and real-time scheduling problem in operating systems.</p>
<p>The basic situation is simple:</p>
<ul>
<li>A <strong>LOW-priority thread</strong> owns a mutex.</li>
<li>A <strong>HIGH-priority thread</strong> needs the same mutex.</li>
<li>HIGH therefore has to wait for LOW.</li>
<li>Meanwhile, a <strong>MEDIUM-priority thread</strong> can consume CPU time.</li>
<li>LOW may be delayed from running and releasing the mutex.</li>
<li>As a result, HIGH can remain blocked longer than expected.</li>
</ul>
<p>The important idea is that the problem is not simply that HIGH is waiting for LOW.</p>
<p>The classic priority-inversion scenario is:</p>
<blockquote>
<p><strong>HIGH waits for LOW, while MEDIUM prevents LOW from running.</strong></p>
</blockquote>
<p>This creates an indirect dependency between HIGH and MEDIUM.</p>
<hr />
<h2>1. Start With the Mutex</h2>
<p>A mutex provides mutual exclusion around a critical section.</p>
<p>In Linux kernel code, a basic mutex operation looks like:</p>
<pre><code class="language-c">mutex_lock(&amp;my_mutex);

/* critical section */

mutex_unlock(&amp;my_mutex);
</code></pre>
<p>Only one thread can own the mutex at a time.</p>
<p>If another thread calls <code>mutex_lock()</code> while the mutex is already owned, that thread has to wait.</p>
<p>For example:</p>
<pre><code class="language-text">LOW  -&gt; owns mutex
HIGH -&gt; needs mutex -&gt; waits
</code></pre>
<p>This by itself is <strong>mutex blocking</strong>.</p>
<p>It is not necessarily priority inversion.</p>
<hr />
<h2>2. The LOW, MEDIUM and HIGH Model</h2>
<p>To understand priority inversion, imagine three threads:</p>
<table>
<thead>
<tr>
<th>Thread</th>
<th>Role</th>
<th>Situation</th>
</tr>
</thead>
<tbody><tr>
<td>LOW</td>
<td>Lower-priority work</td>
<td>Owns the mutex</td>
</tr>
<tr>
<td>HIGH</td>
<td>Higher-priority work</td>
<td>Needs the mutex</td>
</tr>
<tr>
<td>MEDIUM</td>
<td>Intermediate-priority work</td>
<td>Does not need the mutex</td>
</tr>
</tbody></table>
<p>The important dependency is:</p>
<pre><code class="language-text">HIGH
  ↓
waits for
  ↓
LOW
  ↓
can be delayed by
  ↓
MEDIUM
</code></pre>
<p>This is the classic pattern we want to understand.</p>
<hr />
<h2>3. What Happens Step by Step?</h2>
<h3>Step 1: LOW acquires the mutex</h3>
<p>LOW starts first and successfully executes:</p>
<pre><code class="language-c">mutex_lock(&amp;my_mutex);
</code></pre>
<p>Now LOW owns the mutex.</p>
<p>It enters its critical section and performs some work.</p>
<h3>Step 2: HIGH needs the same mutex</h3>
<p>HIGH starts and also attempts:</p>
<pre><code class="language-c">mutex_lock(&amp;my_mutex);
</code></pre>
<p>But LOW already owns the mutex.</p>
<p>Therefore HIGH must wait.</p>
<p>At this point:</p>
<pre><code class="language-text">LOW  -&gt; owns mutex
HIGH -&gt; blocked waiting for mutex
</code></pre>
<h3>Step 3: MEDIUM starts doing work</h3>
<p>MEDIUM is runnable and performs its own work.</p>
<p>The important concept is that MEDIUM does <strong>not</strong> need the mutex.</p>
<p>Nevertheless, depending on the scheduling configuration, MEDIUM can receive CPU time while LOW is waiting to run.</p>
<h3>Step 4: LOW eventually releases the mutex</h3>
<p>LOW must eventually execute:</p>
<pre><code class="language-c">mutex_unlock(&amp;my_mutex);
</code></pre>
<p>Only then can HIGH acquire the mutex and continue.</p>
<p>Therefore, HIGH's progress depends indirectly on LOW getting CPU time.</p>
<hr />
<h2>4. Why This Becomes Priority Inversion</h2>
<p>Imagine the conceptual priorities are:</p>
<table>
<thead>
<tr>
<th>Thread</th>
<th>Priority</th>
</tr>
</thead>
<tbody><tr>
<td>HIGH</td>
<td>80</td>
</tr>
<tr>
<td>MEDIUM</td>
<td>50</td>
</tr>
<tr>
<td>LOW</td>
<td>20</td>
</tr>
</tbody></table>
<p>HIGH has the highest priority.</p>
<p>However, HIGH is blocked because LOW owns the mutex.</p>
<p>If MEDIUM continues to run while LOW is unable to run and release the mutex, the higher-priority HIGH thread can remain blocked.</p>
<p>This is the surprising part:</p>
<blockquote>
<p>A HIGH-priority thread can effectively be delayed because a LOW-priority thread cannot get enough CPU time to release a resource.</p>
</blockquote>
<p>That is the essence of priority inversion.</p>
<hr />
<h2>5. Our First Kernel Module: A Simulation</h2>
<p>The example module creates three kernel threads:</p>
<ul>
<li><code>low_thread</code></li>
<li><code>medium_thread</code></li>
<li><code>high_thread</code></li>
</ul>
<p>The LOW thread acquires a mutex and holds it while simulating long work.</p>
<p>The HIGH thread later attempts to acquire the same mutex.</p>
<p>The MEDIUM thread performs additional work.</p>
<p>The core LOW-thread logic is:</p>
<pre><code class="language-c">mutex_lock(&amp;my_mutex);

pr_info("[LOW] Mutex Acquired\n");

msleep(10000);

mutex_unlock(&amp;my_mutex);
</code></pre>
<p>The HIGH thread later executes:</p>
<pre><code class="language-c">mutex_lock(&amp;my_mutex);

pr_info("[HIGH] Mutex Acquired\n");

mutex_unlock(&amp;my_mutex);
</code></pre>
<p>The result demonstrates the dependency:</p>
<pre><code class="language-text">LOW owns mutex
        ↓
HIGH needs mutex
        ↓
HIGH waits
        ↓
LOW must eventually release mutex
</code></pre>
<p>The complete example is available in the GitHub repository.</p>
<hr />
<h2>6. Important: This Is a Simulation</h2>
<p>There is an important distinction to understand.</p>
<p>The initial demonstration uses ordinary kernel threads and a normal mutex. It does <strong>not</strong> explicitly assign different scheduler priorities to LOW, MEDIUM, and HIGH.</p>
<p>It also does not use <code>rt_mutex</code> to demonstrate real priority inheritance.</p>
<p>Therefore, this first program should be treated as a <strong>conceptual priority-inversion simulation</strong>, rather than a complete real-time priority-inversion experiment.</p>
<p>The distinction is important:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Simulation</th>
<th>Real Priority-Inversion Experiment</th>
</tr>
</thead>
<tbody><tr>
<td>Kernel threads</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Mutex</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>LOW/HIGH/MED naming</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Actual scheduler priorities</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Real-time scheduling</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>SCHED_FIFO</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td><code>rt_mutex</code></td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Priority inheritance</td>
<td>No</td>
<td>Yes</td>
</tr>
</tbody></table>
<p>This makes the simulation useful as a first learning step before studying Linux real-time scheduling and priority inheritance.</p>
<hr />
<h2>7. Why <code>msleep()</code> Is Not CPU-Bound Work</h2>
<p>One subtle point is worth emphasizing.</p>
<p>A demonstration using:</p>
<pre><code class="language-c">msleep(1000);
</code></pre>
<p>is <strong>sleeping</strong>, not continuously consuming CPU.</p>
<p>Therefore, the MEDIUM thread in this particular program does not represent a true CPU-bound medium-priority workload.</p>
<p>A stronger experiment would use controlled CPU work together with explicitly configured scheduling priorities.</p>
<p>That would allow us to demonstrate the scheduler interaction more accurately.</p>
<hr />
<h2>8. The More Complete Experiment</h2>
<p>A more realistic experiment can follow this sequence:</p>
<ol>
<li>Create LOW, MEDIUM and HIGH kernel threads.</li>
<li>Assign actual scheduling priorities.</li>
<li>Use a real-time scheduling policy.</li>
<li>Start LOW first.</li>
<li>Allow LOW to acquire the mutex.</li>
<li>Start HIGH.</li>
<li>HIGH attempts to acquire the mutex and blocks.</li>
<li>Start MEDIUM.</li>
<li>MEDIUM performs CPU-bound work.</li>
<li>Observe how long LOW takes to run and release the mutex.</li>
<li>Measure HIGH's blocking time.</li>
<li>Introduce priority inheritance.</li>
<li>Repeat the experiment.</li>
<li>Compare the blocking times.</li>
</ol>
<p>This turns the simple demonstration into a proper scheduling experiment.</p>
<hr />
<h2>9. Priority Inheritance</h2>
<p>Priority inheritance is one mechanism used to mitigate priority inversion.</p>
<p>The basic idea is:</p>
<blockquote>
<p>If a HIGH-priority thread is waiting for a mutex owned by LOW, LOW can temporarily inherit HIGH's effective priority.</p>
</blockquote>
<p>Conceptually:</p>
<table>
<thead>
<tr>
<th>Thread</th>
<th>Normal Priority</th>
<th>Effective Priority</th>
</tr>
</thead>
<tbody><tr>
<td>HIGH</td>
<td>80</td>
<td>80</td>
</tr>
<tr>
<td>MEDIUM</td>
<td>50</td>
<td>50</td>
</tr>
<tr>
<td>LOW</td>
<td>20</td>
<td>80 while holding the required mutex</td>
</tr>
</tbody></table>
<p>LOW temporarily receives the higher effective priority.</p>
<p>This makes it more likely that LOW will run, finish its critical section and release the mutex.</p>
<p>Then HIGH can proceed.</p>
<hr />
<h2>10. Without Priority Inheritance</h2>
<p>Conceptually:</p>
<pre><code class="language-text">HIGH waits for LOW
        ↓
LOW remains delayed
        ↓
MEDIUM gets CPU time
        ↓
LOW releases mutex later
        ↓
HIGH waits longer
</code></pre>
<p>The important observation is that HIGH's waiting time can be affected by a thread that does not even use the mutex.</p>
<hr />
<h2>11. With Priority Inheritance</h2>
<p>With priority inheritance:</p>
<pre><code class="language-text">HIGH waits for LOW
        ↓
LOW inherits HIGH's effective priority
        ↓
LOW runs sooner
        ↓
LOW releases mutex
        ↓
HIGH continues
</code></pre>
<p>The goal is not to make LOW permanently high priority.</p>
<p>The elevated effective priority is associated with the mutex dependency and is temporary.</p>
<hr />
<h2>12. Learning Path</h2>
<p>A useful progression for studying this topic is:</p>
<h3>Stage 1: Mutex Basics</h3>
<p>Start with:</p>
<pre><code class="language-text">mutex_lock()
mutex_unlock()
</code></pre>
<p>Understand:</p>
<ul>
<li>mutual exclusion</li>
<li>critical sections</li>
<li>ownership</li>
<li>blocking</li>
</ul>
<h3>Stage 2: Mutex Blocking</h3>
<p>Build a small kernel-thread example where one thread owns a mutex and another waits for it.</p>
<h3>Stage 3: Priority-Inversion Simulation</h3>
<p>Introduce LOW, MEDIUM and HIGH threads.</p>
<p>Understand the dependency:</p>
<pre><code class="language-text">HIGH → waits for LOW → LOW can be delayed by MEDIUM
</code></pre>
<h3>Stage 4: Scheduler Interaction</h3>
<p>Study:</p>
<ul>
<li>Linux scheduler</li>
<li>task priorities</li>
<li>real-time scheduling</li>
<li><code>SCHED_FIFO</code></li>
<li>scheduling behavior</li>
</ul>
<h3>Stage 5: Priority Inheritance</h3>
<p>Then move to:</p>
<ul>
<li>priority inheritance</li>
<li><code>rt_mutex</code></li>
<li>real-time locking</li>
<li>measuring blocking time</li>
</ul>
<p>This progression makes the real-time concepts much easier to understand.</p>
<hr />
<h2>13. Why Priority Inversion Matters</h2>
<p>Priority inversion is particularly important in systems where predictable response time matters.</p>
<p>Examples include:</p>
<ul>
<li>embedded systems</li>
<li>real-time Linux</li>
<li>industrial control</li>
<li>robotics</li>
<li>automotive systems</li>
<li>telecommunications</li>
<li>industrial automation</li>
<li>safety-critical systems</li>
</ul>
<p>In such systems, simply saying "the HIGH-priority task has the highest priority" is not enough.</p>
<p>If HIGH is blocked on a resource owned by LOW, the actual behavior depends on synchronization and scheduling.</p>
<hr />
<h2>14. From Kernel Scheduling to Cybersecurity</h2>
<p>Understanding synchronization and scheduling is also useful when moving toward Linux security and low-level systems work.</p>
<p>For example, a monitoring architecture might contain components such as:</p>
<ul>
<li>Linux kernel instrumentation</li>
<li>eBPF monitoring</li>
<li>detection logic</li>
<li>security event collection</li>
<li>SOC dashboards</li>
</ul>
<p>The deeper your understanding of kernel scheduling, synchronization and task behavior, the easier it becomes to reason about low-level system behavior rather than treating the kernel as a black box.</p>
<hr />
<h2>15. Key Takeaways</h2>
<ul>
<li>A mutex protects a shared resource.</li>
<li>A thread attempting to acquire an owned mutex may block.</li>
<li>Mutex blocking alone is not necessarily priority inversion.</li>
<li>Classic priority inversion involves LOW, MEDIUM and HIGH priorities.</li>
<li>HIGH can wait for LOW because LOW owns the required mutex.</li>
<li>MEDIUM can indirectly delay HIGH by preventing LOW from progressing.</li>
<li>The first kernel-module example is a <strong>simulation</strong>, not a complete real-time scheduler experiment.</li>
<li>The example does not assign actual LOW/MEDIUM/HIGH scheduler priorities.</li>
<li>A stronger experiment should use explicit real-time scheduling priorities and controlled CPU-bound work.</li>
<li>Priority inheritance allows the lower-priority mutex owner to temporarily inherit the effective priority of a higher-priority waiter.</li>
<li>The objective is to allow the mutex owner to finish its critical section sooner and release the resource.</li>
</ul>
<hr />
<h2>Conclusion</h2>
<p>Priority inversion is a good example of why operating-system performance cannot be understood only by looking at individual thread priorities.</p>
<p>The important question is not simply:</p>
<blockquote>
<p>"Which thread has the highest priority?"</p>
</blockquote>
<p>We also need to ask:</p>
<blockquote>
<p>"Which resource is that thread waiting for, who owns it, and can that owner get enough CPU time to release it?"</p>
</blockquote>
<p>Starting with a simple mutex simulation and then progressing toward real-time scheduling and priority inheritance provides a practical way to understand this behavior inside the Linux kernel.</p>
<p>The next logical step is to build <strong>Program 6B</strong>, using actual scheduling priorities and Linux real-time synchronization mechanisms, and compare HIGH's blocking time <strong>without and with priority inheritance</strong>.</p>
<hr />
<h2>GitHub Repository</h2>
<p>Complete source code and project files:</p>
<p>👉 <strong><a href="https://github.com/aj333git/linux_kernel_priority_inversion_demo">linux_kernel_priority_inversion</a></strong></p>
]]></content:encoded></item><item><title><![CDATA[Understanding `mutex_lock_killable()` in Linux Kernel Modules]]></title><description><![CDATA[Synchronization is one of the most important concepts in Linux kernel development. When multiple kernel threads access a shared resource simultaneously, improper synchronization can lead to race condi]]></description><link>https://devnation.joshisfitness.com/understanding-mutex-lock-killable-in-linux-kernel-modules</link><guid isPermaLink="true">https://devnation.joshisfitness.com/understanding-mutex-lock-killable-in-linux-kernel-modules</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Fri, 07 Aug 2026 13:06:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/60cd8851-0c82-4329-8127-c216d8cc9934.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Synchronization is one of the most important concepts in Linux kernel development. When multiple kernel threads access a shared resource simultaneously, improper synchronization can lead to race conditions, inconsistent data, or even kernel crashes.</p>
<p>One of the synchronization primitives provided by the Linux kernel is <strong><code>mutex_lock_killable()</code></strong>. It behaves similarly to <code>mutex_lock()</code>, but allows a waiting task to return if interrupted by an appropriate fatal signal.</p>
<p>In this article, we'll explore the fundamentals of <code>mutex_lock_killable()</code> through a simple Linux Kernel Module.</p>
<hr />
<h1>Prerequisites</h1>
<p>Before following this tutorial, you should be familiar with:</p>
<ul>
<li>Linux Kernel Modules</li>
<li>C Programming</li>
<li>Kernel Threads</li>
<li>Basic Linux Commands</li>
<li>Synchronization Fundamentals</li>
</ul>
<hr />
<h1>What is a Mutex?</h1>
<p>A <strong>Mutex (Mutual Exclusion Lock)</strong> ensures that only <strong>one execution context</strong> can access a shared resource at a time.</p>
<p>Without synchronization:</p>
<ul>
<li>Race conditions occur</li>
<li>Shared data becomes inconsistent</li>
<li>Kernel behavior becomes unpredictable</li>
</ul>
<p>Using a mutex guarantees exclusive access to the critical section.</p>
<hr />
<h1>Why <code>mutex_lock_killable()</code>?</h1>
<p>The Linux kernel provides multiple mutex APIs.</p>
<table>
<thead>
<tr>
<th>API</th>
<th>Behavior</th>
</tr>
</thead>
<tbody><tr>
<td><code>mutex_lock()</code></td>
<td>Wait indefinitely until the lock becomes available</td>
</tr>
<tr>
<td><code>mutex_lock_interruptible()</code></td>
<td>Can be interrupted by interruptible signals</td>
</tr>
<tr>
<td><code>mutex_lock_killable()</code></td>
<td>Can return if interrupted by an appropriate fatal signal</td>
</tr>
</tbody></table>
<p>In many driver scenarios, allowing a blocked task to terminate gracefully is preferable to waiting forever.</p>
<hr />
<h1>Demo Overview</h1>
<p>The demonstration module creates two kernel threads.</p>
<ul>
<li>Thread-1 acquires the mutex.</li>
<li>Thread-2 attempts to acquire the same mutex.</li>
<li>Since the mutex is already held, Thread-2 blocks.</li>
<li>After Thread-1 releases the mutex, Thread-2 continues execution.</li>
</ul>
<p>This simple example illustrates how mutual exclusion works inside the Linux kernel.</p>
<hr />
<h1>Core Kernel APIs</h1>
<p>The project uses several commonly used kernel APIs.</p>
<pre><code class="language-c">DEFINE_MUTEX(my_mutex);

mutex_lock_killable(&amp;my_mutex);

mutex_unlock(&amp;my_mutex);

kthread_run(...);

msleep(5000);

pr_info(...);
</code></pre>
<p>Each API plays a specific role:</p>
<ul>
<li><code>DEFINE_MUTEX()</code> creates a mutex.</li>
<li><code>mutex_lock_killable()</code> acquires the mutex.</li>
<li><code>mutex_unlock()</code> releases it.</li>
<li><code>kthread_run()</code> creates kernel threads.</li>
<li><code>msleep()</code> simulates work.</li>
<li><code>pr_info()</code> prints kernel log messages.</li>
</ul>
<hr />
<h1>Critical Section</h1>
<p>A <strong>Critical Section</strong> is the portion of code that accesses shared resources.</p>
<p>Only one thread should execute this region at any given time.</p>
<p>In the demo:</p>
<ul>
<li>Thread-1 enters the critical section.</li>
<li>Thread-2 waits.</li>
<li>After unlocking, Thread-2 proceeds.</li>
</ul>
<p>This guarantees safe access to shared resources.</p>
<hr />
<h1>Building the Module</h1>
<p>Compile the module using:</p>
<pre><code class="language-bash">make
</code></pre>
<p>If Secure Boot is enabled, sign the kernel module before loading.</p>
<pre><code class="language-bash">sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file \
sha256 \
~/kernel_keys/MOK.key \
~/kernel_keys/MOK.crt \
mutex_killable_demo.ko
</code></pre>
<hr />
<h1>Loading the Module</h1>
<p>Insert the module:</p>
<pre><code class="language-bash">sudo insmod mutex_killable_demo.ko
</code></pre>
<p>Monitor kernel logs:</p>
<pre><code class="language-bash">sudo dmesg -wH
</code></pre>
<p>Verify the module:</p>
<pre><code class="language-bash">lsmod | grep mutex_killable_demo
</code></pre>
<p>View running kernel threads:</p>
<pre><code class="language-bash">ps -eLf | grep killable
</code></pre>
<p>Unload the module:</p>
<pre><code class="language-bash">sudo rmmod mutex_killable_demo
</code></pre>
<hr />
<h1>Expected Execution</h1>
<p>When the module runs, the output typically follows this sequence:</p>
<ol>
<li>Thread-1 starts.</li>
<li>Thread-1 acquires the mutex.</li>
<li>Thread-2 starts.</li>
<li>Thread-2 blocks while waiting.</li>
<li>Thread-1 releases the mutex.</li>
<li>Thread-2 acquires the mutex.</li>
<li>Thread-2 completes execution.</li>
<li>Module unloads successfully.</li>
</ol>
<hr />
<h1>Practical Use Cases</h1>
<p>Understanding kernel synchronization is useful when developing:</p>
<ul>
<li>Character Device Drivers</li>
<li>Platform Drivers</li>
<li>PCI Drivers</li>
<li>USB Drivers</li>
<li>Network Drivers</li>
<li>Filesystem Modules</li>
<li>Embedded Linux Systems</li>
<li>Linux Kernel Subsystems</li>
</ul>
<hr />
<h1>Key Learning Outcomes</h1>
<p>After completing this project, you should understand:</p>
<ul>
<li>Linux kernel synchronization</li>
<li>Kernel threads</li>
<li>Mutex locking</li>
<li>Critical sections</li>
<li>Blocking synchronization</li>
<li>Kernel logging</li>
<li>Mutual exclusion</li>
<li>Safe shared resource access</li>
</ul>
<hr />
<h1>Important Note</h1>
<p>In this educational example, both workers are <strong>kernel threads</strong>. Since kernel threads typically do not receive user-space signals, the behavior of <code>mutex_lock_killable()</code> appears very similar to <code>mutex_lock()</code>.</p>
<p>The primary advantage of <code>mutex_lock_killable()</code> becomes more apparent in kernel drivers where a <strong>user-space process</strong> blocks while waiting for a mutex and may receive a fatal signal.</p>
<hr />
<h1>Conclusion</h1>
<p>Although the demo is intentionally simple, it introduces several core Linux kernel concepts that appear throughout driver development.</p>
<p>Understanding synchronization primitives like <code>mutex_lock_killable()</code> is an important step toward writing reliable kernel modules and avoiding race conditions in concurrent kernel code.</p>
<p>As you continue learning Linux kernel development, you can extend this project by experimenting with additional synchronization mechanisms such as semaphores, spinlocks, completions, wait queues, and reader-writer locks.</p>
<hr />
<h1>GitHub Repository</h1>
<p>👉 <strong>GitHub Repository:</strong><br /><strong><a href="https://github.com/aj333git/linux_kernel_mutex_killable">https://github.com/aj333git/linux_kernel_mutex_killable</a></strong></p>
<p>Explore the complete source code, build files, and Linux kernel module implementation.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[ Building an F# Control Plane with a C Data Plane on Linux]]></title><description><![CDATA[Modern software systems often separate control logic from high-performance execution logic. This design is common in networking, distributed systems, operating systems, storage engines, and embedded s]]></description><link>https://devnation.joshisfitness.com/building-an-f-control-plane-with-a-c-data-plane-on-linux</link><guid isPermaLink="true">https://devnation.joshisfitness.com/building-an-f-control-plane-with-a-c-data-plane-on-linux</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Thu, 30 Jul 2026 08:36:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/d8e27639-bb4c-4f3e-9ffd-487c88e77b23.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Modern software systems often separate <strong>control logic</strong> from <strong>high-performance execution logic</strong>. This design is common in networking, distributed systems, operating systems, storage engines, and embedded software.</p>
<p>In this project, we build a simple Linux application that demonstrates this architectural pattern using:</p>
<ul>
<li><strong>F#</strong> as the <strong>Control Plane</strong></li>
<li><strong>C</strong> as the <strong>Data Plane</strong></li>
<li><strong>P/Invoke</strong> for interoperability</li>
<li><strong>Linux Shared Libraries (.so)</strong></li>
</ul>
<p>Although the example is intentionally simple, the same design scales to much larger systems.</p>
<hr />
<h1>Why Separate Control Plane and Data Plane?</h1>
<p>Different programming languages excel at different tasks.</p>
<table>
<thead>
<tr>
<th>Control Plane</th>
<th>Data Plane</th>
</tr>
</thead>
<tbody><tr>
<td>User interaction</td>
<td>High-performance computation</td>
</tr>
<tr>
<td>Input validation</td>
<td>Native execution</td>
</tr>
<tr>
<td>Business logic</td>
<td>Memory-efficient processing</td>
</tr>
<tr>
<td>Workflow orchestration</td>
<td>Optimized algorithms</td>
</tr>
<tr>
<td>F#</td>
<td>C</td>
</tr>
</tbody></table>
<p>In this project:</p>
<ul>
<li>F# collects user input.</li>
<li>The terrain data is stored in a managed array.</li>
<li>The array is passed directly to native C.</li>
<li>C prints the terrain grid.</li>
</ul>
<p>This demonstrates a clean separation of responsibilities.</p>
<hr />
<h1>Project Architecture</h1>
<p>The project consists of two independent components.</p>
<h2>Control Plane</h2>
<p>Responsibilities:</p>
<ul>
<li>Read terrain dimensions</li>
<li>Read elevation values</li>
<li>Store data in a managed array</li>
<li>Invoke native code</li>
</ul>
<p>Technology:</p>
<ul>
<li>F#</li>
<li>.NET 8</li>
</ul>
<hr />
<h2>Data Plane</h2>
<p>Responsibilities:</p>
<ul>
<li>Receive terrain data</li>
<li>Traverse the array</li>
<li>Print formatted output</li>
</ul>
<p>Technology:</p>
<ul>
<li>C</li>
<li>GCC</li>
<li>Shared Library (.so)</li>
</ul>
<hr />
<h1>Project Structure</h1>
<pre><code class="language-text">terrain_grid/
│
├── control_plane/
│   ├── Program.fs
│   ├── Terrain.fs
│   └── control_plane.fsproj
│
├── data_plane/
│   ├── terrain.c
│   ├── terrain.h
│   └── libterrain.so
│
└── README.md
</code></pre>
<hr />
<h1>The Control Plane (F#)</h1>
<p>The control plane is responsible for gathering input and forwarding it to the native library.</p>
<p>A simplified version:</p>
<pre><code class="language-fsharp">let terrain = Array.zeroCreate&lt;double&gt;(rows * cols)

Terrain.display_terrain(
    terrain,
    rows,
    cols)
</code></pre>
<p>Notice that the F# code never performs the display itself.</p>
<p>Its only responsibility is orchestration.</p>
<hr />
<h1>Calling Native C with P/Invoke</h1>
<p>The bridge between managed and native code is created with <code>DllImport</code>.</p>
<pre><code class="language-fsharp">[&lt;DllImport("libterrain.so",
    CallingConvention = CallingConvention.Cdecl)&gt;]
extern void display_terrain(
    double[] terrain,
    int rows,
    int cols)
</code></pre>
<p>P/Invoke automatically marshals the managed array into a native pointer that the C library can consume.</p>
<hr />
<h1>The Data Plane (C)</h1>
<p>The C library receives a pointer to the terrain array and prints the values.</p>
<pre><code class="language-c">void display_terrain(
    const double* terrain,
    int rows,
    int cols)
{
    printf("%8.2f",
           terrain[i * cols + j]);
}
</code></pre>
<p>Because the array is stored contiguously, indexing is straightforward.</p>
<hr />
<h1>Why Use a One-Dimensional Array?</h1>
<p>Although the terrain logically represents a matrix, it is stored as a linear array.</p>
<p>Advantages include:</p>
<ul>
<li>Contiguous memory</li>
<li>Better cache locality</li>
<li>Easier interoperability</li>
<li>Simpler pointer arithmetic</li>
<li>Lower overhead</li>
</ul>
<p>The index calculation is:</p>
<pre><code class="language-text">index = row * columns + column
</code></pre>
<p>This technique is widely used in:</p>
<ul>
<li>Scientific computing</li>
<li>Image processing</li>
<li>Game engines</li>
<li>Embedded software</li>
<li>Numerical libraries</li>
</ul>
<hr />
<h1>Building the Shared Library</h1>
<p>Compile the native library using GCC.</p>
<pre><code class="language-bash">gcc -shared -fPIC terrain.c -o libterrain.so
</code></pre>
<hr />
<h1>Building the F# Project</h1>
<pre><code class="language-bash">dotnet build
</code></pre>
<p>Run:</p>
<pre><code class="language-bash">dotnet run
</code></pre>
<hr />
<h1>Sample Output</h1>
<pre><code class="language-text">Rows : 2
Cols : 2

Elevation [0][0] : 2
Elevation [0][1] : 3
Elevation [1][0] : 4
Elevation [1][1] : 5

Terrain Grid (Elevation in meters)
----------------------------------
    2.00    3.00
    4.00    5.00
</code></pre>
<hr />
<h1>What This Example Demonstrates</h1>
<p>This small application introduces several important concepts.</p>
<ul>
<li>F# to C interoperability</li>
<li>Linux shared libraries</li>
<li>P/Invoke</li>
<li>Managed and native memory interaction</li>
<li>Control Plane / Data Plane architecture</li>
<li>One-dimensional representation of matrices</li>
</ul>
<hr />
<h1>Where This Pattern Is Used</h1>
<p>The same architecture appears in many production systems.</p>
<ul>
<li>Network packet processing</li>
<li>Linux networking subsystems</li>
<li>Storage engines</li>
<li>Embedded firmware</li>
<li>Robotics</li>
<li>High-performance computing</li>
<li>Scientific simulations</li>
<li>CAD applications</li>
<li>GIS software</li>
<li>Image processing pipelines</li>
</ul>
<p>The complexity may increase, but the architectural principle remains the same.</p>
<hr />
<h1>Possible Extensions</h1>
<p>This project can easily be expanded by adding features such as:</p>
<ul>
<li>Terrain statistics</li>
<li>Height normalization</li>
<li>Gradient calculation</li>
<li>Heat map generation</li>
<li>Terrain smoothing</li>
<li>File import/export</li>
<li>CSV support</li>
<li>Binary terrain format</li>
<li>OpenGL visualization</li>
<li>GIS integration</li>
</ul>
<hr />
<h1>Conclusion</h1>
<p>This project demonstrates how managed and native languages can work together effectively.</p>
<p>F# provides expressive and concise application logic, while C delivers predictable native execution. By combining the two through P/Invoke, developers can build applications that are both productive and performant.</p>
<p>Although the terrain grid application is intentionally small, it illustrates a design pattern that scales to much larger systems in systems programming, embedded development, and high-performance computing.</p>
<hr />
<h2>GitHub Repository</h2>
<p><strong>terrain_grid</strong></p>
<p><a href="https://github.com/aj333git/Civil_Mech_apps/tree/main/terrain_grid">https://github.com/aj333git/Civil_Mech_apps/tree/main/terrain_grid</a></p>
<hr />
]]></content:encoded></item><item><title><![CDATA[Integrating F# with Native C Using P/Invoke for Engineering Computation]]></title><description><![CDATA[Introduction
Engineering software often combines multiple programming languages to leverage their individual strengths. A common approach is to implement computational algorithms in native C or C++ wh]]></description><link>https://devnation.joshisfitness.com/integrating-f-with-native-c-using-p-invoke-for-engineering-computation</link><guid isPermaLink="true">https://devnation.joshisfitness.com/integrating-f-with-native-c-using-p-invoke-for-engineering-computation</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Wed, 29 Jul 2026 06:21:18 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/9ef36c4a-c4b0-4bd4-932c-baca248891c2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1>
<p>Engineering software often combines multiple programming languages to leverage their individual strengths. A common approach is to implement computational algorithms in native C or C++ while developing the user interface and application logic using higher-level technologies.</p>
<p>This project demonstrates that architecture by building a simple <strong>Beam Load Calculator</strong> where:</p>
<ul>
<li><p>F# provides the application layer</p>
</li>
<li><p>Native C performs the numerical computation</p>
</li>
<li><p>P/Invoke connects both layers</p>
</li>
</ul>
<p>Although the calculation is intentionally simple, the architecture closely resembles that used in professional engineering and scientific applications.</p>
<hr />
<h1>Project Overview</h1>
<p>The application computes the <strong>total load</strong> acting on a beam by summing multiple point loads entered by the user.</p>
<p>The project also introduces:</p>
<ul>
<li><p>Foreign Function Interface (FFI)</p>
</li>
<li><p>Platform Invocation (P/Invoke)</p>
</li>
<li><p>Shared libraries (<code>.so</code>)</p>
</li>
<li><p>Cross-language programming</p>
</li>
<li><p>Basic engineering computation</p>
</li>
</ul>
<hr />
<h1>Technology Stack</h1>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Technology</th>
</tr>
</thead>
<tbody><tr>
<td>Application</td>
<td>F#</td>
</tr>
<tr>
<td>Runtime</td>
<td>.NET</td>
</tr>
<tr>
<td>Native Library</td>
<td>C</td>
</tr>
<tr>
<td>Interoperability</td>
<td>P/Invoke</td>
</tr>
<tr>
<td>Operating System</td>
<td>Linux</td>
</tr>
</tbody></table>
<hr />
<h1>Project Structure</h1>
<pre><code class="language-text">beam_load_calc_

├── beam_load.c
├── beam_load.h
├── beam_load_cal/
│   ├── Program.fs
│   └── beam_load_cal.fsproj
└── README.md
</code></pre>
<hr />
<h1>Architecture</h1>
<p>The application separates the computational engine from the application layer.</p>
<ul>
<li><p>F# reads user input.</p>
</li>
<li><p>P/Invoke calls the native library.</p>
</li>
<li><p>C computes the total beam load.</p>
</li>
<li><p>F# displays the result.</p>
</li>
</ul>
<p>This separation makes the computational logic reusable and independent of the user interface.</p>
<hr />
<h1>Native C Function</h1>
<p>The numerical computation is implemented in C.</p>
<pre><code class="language-c">double calculate_total_load(const double loads[], int size)
{
    double total = 0.0;

    for (int i = 0; i &lt; size; i++)
        total += loads[i];

    return total;
}
</code></pre>
<hr />
<h1>Calling Native Code from F#</h1>
<p>The native function is imported using <code>DllImport</code>.</p>
<pre><code class="language-fsharp">[&lt;DllImport("./beam_load.so")&gt;]
extern double calculate_total_load(double[] loads, int size)
</code></pre>
<p>Once imported, it behaves like a normal F# function.</p>
<hr />
<h1>Computer Science Concepts</h1>
<p>This project introduces several important software engineering topics.</p>
<ul>
<li><p>Foreign Function Interface (FFI)</p>
</li>
<li><p>Platform Invocation (P/Invoke)</p>
</li>
<li><p>Shared Libraries</p>
</li>
<li><p>Dynamic Linking</p>
</li>
<li><p>Arrays</p>
</li>
<li><p>Functional Programming</p>
</li>
<li><p>Cross-language Programming</p>
</li>
<li><p>Native Interoperability</p>
</li>
<li><p>Modular Software Design</p>
</li>
</ul>
<hr />
<h1>Civil and Mechanical Engineering Concepts</h1>
<p>From an engineering perspective, the project demonstrates:</p>
<ul>
<li><p>Beam</p>
</li>
<li><p>Point Load</p>
</li>
<li><p>Resultant Load</p>
</li>
<li><p>Load Summation</p>
</li>
<li><p>Engineering Computation</p>
</li>
</ul>
<p>Although simple, these concepts form the starting point for structural analysis.</p>
<hr />
<h1>Algorithm Analysis</h1>
<p>The algorithm visits every load exactly once.</p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Complexity</th>
</tr>
</thead>
<tbody><tr>
<td>Time Complexity</td>
<td><strong>O(n)</strong></td>
</tr>
<tr>
<td>Space Complexity</td>
<td><strong>O(n)</strong></td>
</tr>
<tr>
<td>Auxiliary Space</td>
<td><strong>O(1)</strong></td>
</tr>
</tbody></table>
<p>This provides a practical example of applying algorithm analysis to an engineering computation.</p>
<hr />
<h1>Build</h1>
<p>Compile the native library.</p>
<pre><code class="language-bash">gcc -shared -fPIC beam_load.c -o beam_load.so
</code></pre>
<p>Build the F# application.</p>
<pre><code class="language-bash">cd beam_load_cal
dotnet build
</code></pre>
<p>Run the project.</p>
<pre><code class="language-bash">dotnet run
</code></pre>
<hr />
<h1>Why This Architecture Matters</h1>
<p>Many commercial engineering applications separate the computational engine from the application layer.</p>
<p>Examples include:</p>
<ul>
<li><p>CAD Software</p>
</li>
<li><p>Structural Analysis Software</p>
</li>
<li><p>Finite Element Analysis</p>
</li>
<li><p>Scientific Computing</p>
</li>
<li><p>Simulation Platforms</p>
</li>
<li><p>Robotics</p>
</li>
<li><p>Embedded Systems</p>
</li>
</ul>
<p>Using native libraries for computation improves portability and allows computational code to be reused across different applications.</p>
<hr />
<h1>Future Roadmap</h1>
<p>This project serves as a foundation for a larger engineering toolkit.</p>
<p>Planned enhancements include:</p>
<ul>
<li><p>Uniformly Distributed Load (UDL)</p>
</li>
<li><p>Support Reactions</p>
</li>
<li><p>Shear Force Diagram</p>
</li>
<li><p>Bending Moment Diagram</p>
</li>
<li><p>Beam Deflection</p>
</li>
<li><p>Material Properties</p>
</li>
<li><p>Unit Conversion</p>
</li>
<li><p>PDF Report Generation</p>
</li>
<li><p>Avalonia Desktop GUI</p>
</li>
</ul>
<hr />
<h1>Key Takeaways</h1>
<p>After completing this project, you should understand:</p>
<ul>
<li><p>How F# communicates with native C libraries</p>
</li>
<li><p>How shared libraries work on Linux</p>
</li>
<li><p>Basic Platform Invocation (P/Invoke)</p>
</li>
<li><p>Cross-language software architecture</p>
</li>
<li><p>Applying programming concepts to engineering problems</p>
</li>
</ul>
<hr />
<h1>Conclusion</h1>
<p>This Beam Load Calculator demonstrates how a modern .NET application can integrate with native C code using P/Invoke. While the current implementation focuses on a simple load summation problem, the same architecture can be extended to support more advanced engineering calculations and desktop applications.</p>
<p>By combining F# for application development with C for computational routines, the project illustrates a scalable design that is applicable to engineering software, scientific computing, and high-performance numerical applications.</p>
<hr />
<h2>Source Code</h2>
<p>GitHub Repository: 👉 <strong><a href="https://github.com/aj333git/Civil_Mech_apps/tree/main/beam_load_calc_">beam_load_calc</a></strong> Explore the complete source code, build files, and module implementation on GitHub.</p>
<hr />
<p><strong>If you found this project useful, consider giving the repository a ⭐ and sharing your feedback.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Linux Kernel Deadlock ]]></title><description><![CDATA[Deadlocks are one of the most common synchronization problems encountered in operating systems and concurrent programming. Although the concept is frequently introduced in textbooks, observing it insi]]></description><link>https://devnation.joshisfitness.com/linux-kernel-deadlock</link><guid isPermaLink="true">https://devnation.joshisfitness.com/linux-kernel-deadlock</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Tue, 28 Jul 2026 11:31:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/3d2e1a41-df5c-414d-80a3-51025e64fd97.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Deadlocks are one of the most common synchronization problems encountered in operating systems and concurrent programming. Although the concept is frequently introduced in textbooks, observing it inside the Linux kernel provides a much deeper understanding of why proper lock ordering is essential.</p>
<p>In this project, I built a <strong>Linux Kernel Loadable Module (LKM)</strong> that intentionally creates a deadlock using <strong>two kernel threads</strong> and <strong>two mutexes</strong>. The same module also contains a corrected implementation that eliminates the deadlock by enforcing a consistent lock acquisition order.</p>
<p>The objective of this project is educational. It demonstrates not only how deadlocks occur, but also how to debug synchronization issues using kernel logs and how to manage kernel thread lifecycles correctly.</p>
<hr />
<h1>Project Overview</h1>
<p>The module supports two execution modes.</p>
<table>
<thead>
<tr>
<th>Mode</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>mode=1</code></td>
<td>Intentionally creates a deadlock</td>
</tr>
<tr>
<td><code>mode=2</code></td>
<td>Demonstrates the corrected implementation</td>
</tr>
</tbody></table>
<p>Both modes use the same synchronization primitives but differ in the order in which mutexes are acquired.</p>
<hr />
<h1>Technologies Used</h1>
<ul>
<li>Linux Kernel Modules (LKM)</li>
<li>Kernel Threads (<code>kthread</code>)</li>
<li>Mutex Synchronization</li>
<li>Linux Kernel Logging (<code>pr_info</code>)</li>
<li>Module Parameters</li>
<li><code>dmesg</code></li>
<li>Kernel Build System</li>
</ul>
<hr />
<h1>Understanding the Deadlock</h1>
<p>The demonstration creates two worker threads.</p>
<p>The first thread acquires:</p>
<pre><code class="language-text">LockA

↓

LockB
</code></pre>
<p>The second thread acquires:</p>
<pre><code class="language-text">LockB

↓

LockA
</code></pre>
<p>Once each thread acquires its first mutex, both wait forever for the second mutex.</p>
<p>Neither thread can proceed.</p>
<p>This is the classic circular waiting condition that produces a deadlock.</p>
<hr />
<h1>Deadlock Demonstration</h1>
<p>The worker thread acquires the first mutex, waits briefly, and then attempts to acquire the second mutex.</p>
<p>Example:</p>
<pre><code class="language-c">mutex_lock(&amp;lockA);

msleep(2000);

mutex_lock(&amp;lockB);
</code></pre>
<p>The second worker performs the opposite operation.</p>
<pre><code class="language-c">mutex_lock(&amp;lockB);

msleep(2000);

mutex_lock(&amp;lockA);
</code></pre>
<p>Running both threads simultaneously causes each thread to wait indefinitely.</p>
<hr />
<h1>Deadlock Prevention</h1>
<p>The solution is surprisingly simple.</p>
<p>Both threads acquire the mutexes in exactly the same order.</p>
<pre><code class="language-c">mutex_lock(&amp;lockA);

mutex_lock(&amp;lockB);
</code></pre>
<p>Since every thread follows the same locking sequence, circular waiting is eliminated.</p>
<hr />
<h1>Kernel Threads</h1>
<p>The module creates two kernel threads using <code>kthread_run()</code>.</p>
<p>Example:</p>
<pre><code class="language-c">thread1 = kthread_run(worker1, NULL, "thread1");
</code></pre>
<p>Each worker performs its task once and then exits.</p>
<p>This project is intentionally kept small so that the synchronization behavior remains easy to observe.</p>
<hr />
<h1>Module Parameters</h1>
<p>The module behavior is controlled through a module parameter.</p>
<pre><code class="language-bash">sudo insmod deadlock_demo.ko mode=1
</code></pre>
<p>or</p>
<pre><code class="language-bash">sudo insmod deadlock_demo.ko mode=2
</code></pre>
<p>This makes it possible to compare the incorrect and corrected implementations without modifying the source code.</p>
<hr />
<h1>Building the Module</h1>
<p>Compile the module using the kernel build system.</p>
<pre><code class="language-bash">make
</code></pre>
<p>If Secure Boot is enabled, sign the module before loading it.</p>
<pre><code class="language-bash">sudo /usr/src/linux-headers-$(uname -r)/scripts/sign-file \
sha256 \
~/kernel_keys/MOK.key \
~/kernel_keys/MOK.crt \
deadlock_demo.ko
</code></pre>
<hr />
<h1>Running the Demonstration</h1>
<p>Load the deadlock version.</p>
<pre><code class="language-bash">sudo insmod deadlock_demo.ko mode=1
</code></pre>
<p>Monitor kernel messages.</p>
<pre><code class="language-bash">dmesg -w
</code></pre>
<p>Load the corrected implementation.</p>
<pre><code class="language-bash">sudo insmod deadlock_demo.ko mode=2
</code></pre>
<p>Unload the module.</p>
<pre><code class="language-bash">sudo rmmod deadlock_demo
</code></pre>
<hr />
<h1>Debugging with dmesg</h1>
<p>The Linux kernel provides detailed diagnostic information through <code>dmesg</code>.</p>
<p>Useful commands include:</p>
<pre><code class="language-bash">dmesg | tail -100
</code></pre>
<pre><code class="language-bash">dmesg | grep deadlock_demo
</code></pre>
<p>Kernel logs make it much easier to understand thread execution, lock acquisition, and module initialization.</p>
<hr />
<h1>Two Important Bugs Encountered</h1>
<p>While implementing this demonstration, I encountered two issues that were <strong>not</strong> caused by the deadlock itself.</p>
<h2>1. Incorrect use of <code>kthread_stop()</code></h2>
<p>The worker threads in the corrected implementation naturally terminate after completing their work.</p>
<p>Attempting to stop already-finished threads during module removal resulted in kernel warnings and crashes.</p>
<p>The fix was to avoid calling <code>kthread_stop()</code> for one-shot worker threads.</p>
<hr />
<h2>2. Missing <code>IS_ERR()</code> Validation</h2>
<p>Initially, the return value of <code>kthread_run()</code> was not validated.</p>
<p>Proper kernel programming requires checking whether thread creation failed.</p>
<p>Example:</p>
<pre><code class="language-c">if (IS_ERR(thread1))
</code></pre>
<p>Adding this validation makes the module more robust and avoids invalid pointer usage.</p>
<p>A detailed analysis of both debugging sessions will be presented in a future article.</p>
<hr />
<h1>Key Concepts Covered</h1>
<ul>
<li>Linux Kernel Modules</li>
<li>Kernel Threads</li>
<li>Mutexes</li>
<li>Mutual Exclusion</li>
<li>Critical Sections</li>
<li>Deadlocks</li>
<li>Deadlock Prevention</li>
<li>Lock Ordering</li>
<li>Module Parameters</li>
<li>Kernel Logging</li>
<li>Thread Lifecycle</li>
<li>Basic Kernel Debugging</li>
</ul>
<hr />
<h1>What I have  Learned</h1>
<p>By studying this project,I have   gained hands-on experience with:</p>
<ul>
<li>Writing Linux Kernel Modules</li>
<li>Creating kernel threads</li>
<li>Synchronizing shared resources</li>
<li>Understanding why deadlocks occur</li>
<li>Preventing deadlocks using proper lock ordering</li>
<li>Reading kernel logs</li>
<li>Debugging synchronization problems</li>
</ul>
<hr />
<h1>Future Articles</h1>
<p>This project is the first step in a larger Linux kernel synchronization series.</p>
<p>Upcoming articles will provide a deeper discussion of:</p>
<ul>
<li>Complete source code walkthrough</li>
<li>Thread lifecycle management</li>
<li><code>kthread_run()</code> internals</li>
<li><code>kthread_stop()</code> best practices</li>
<li><code>IS_ERR()</code>, <code>ERR_PTR()</code>, and <code>PTR_ERR()</code></li>
<li>Linux kernel debugging techniques</li>
<li>Kernel call trace analysis</li>
<li>Synchronization best practices</li>
</ul>
<hr />
<h1>Conclusion</h1>
<p>Deadlocks are easier to understand when they can be reproduced in a controlled environment.</p>
<p>This Linux Kernel Module demonstrates both an incorrect synchronization strategy and its corrected implementation using only two kernel threads and two mutexes. Although the project is intentionally small, it illustrates several important concepts that frequently appear in operating system design and Linux kernel development.</p>
<p>Understanding synchronization primitives at this level provides a solid foundation for exploring more advanced topics such as semaphores, read-write locks, completions, wait queues, workqueues, RCU, and lock-free programming.</p>
<hr />
<h2>GitHub Repository</h2>
<p>Source code for this project is available at:</p>
<p><strong><a href="https://github.com/aj333git/linux_kernel_deadlock_demo">https://github.com/aj333git/linux_kernel_deadlock_demo</a></strong></p>
]]></content:encoded></item><item><title><![CDATA[Bitmap vs IDA in Linux Kernel: Understanding Region Allocation with a Kernel Module]]></title><description><![CDATA[Memory and resource allocation are fundamental operations inside the Linux kernel. Whether assigning device IDs, managing CPU masks, allocating interrupt vectors, or tracking hardware resources, the k]]></description><link>https://devnation.joshisfitness.com/bitmap-vs-ida-in-linux-kernel-understanding-region-allocation-with-a-kernel-module</link><guid isPermaLink="true">https://devnation.joshisfitness.com/bitmap-vs-ida-in-linux-kernel-understanding-region-allocation-with-a-kernel-module</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Wed, 22 Jul 2026 06:43:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/f48a85b8-ad68-46ec-af65-d9a3254e482e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Memory and resource allocation are fundamental operations inside the Linux kernel. Whether assigning device IDs, managing CPU masks, allocating interrupt vectors, or tracking hardware resources, the kernel relies on specialized data structures optimized for different allocation patterns.</p>
<p>Recently, an interesting <strong>Linux Kernel Mailing List (LKML)</strong> discussion initiated by <strong>Yury Norov</strong> explored different approaches for region allocation, comparing <strong>Bitmap</strong>, <strong>IDA</strong>, and <strong>Maple Tree</strong>. Inspired by that discussion, I built a small Linux Kernel Module (LKM) to understand how Bitmap and IDA work internally and to benchmark their allocation time.</p>
<p>This article walks through the concepts, implementation, and practical differences between these allocators.</p>
<hr />
<h1>Why This Topic Matters</h1>
<p>Kernel developers frequently face questions such as:</p>
<ul>
<li>Should a resource be represented as individual IDs?</li>
<li>Should contiguous regions be allocated?</li>
<li>Which data structure scales better as the number of resources grows?</li>
<li>How much overhead does each allocator introduce?</li>
</ul>
<p>The answer depends entirely on the allocation problem.</p>
<hr />
<h1>Motivation</h1>
<p>The implementation was inspired by the following LKML discussion:</p>
<p><strong>Message-ID</strong></p>
<pre><code>20260717053241.916441-1-ynorov@nvidia.com
</code></pre>
<p>The discussion compares several allocation mechanisms for variable-sized regions, including:</p>
<ul>
<li>Bitmap</li>
<li>IDA</li>
<li>Maple Tree</li>
</ul>
<p>Although this module implements only Bitmap and IDA, understanding these two allocators provides an excellent foundation before exploring Maple Tree.</p>
<hr />
<h1>Understanding Bitmap Allocation</h1>
<p>A bitmap represents every resource using a single bit.</p>
<p>Each bit has only two possible states:</p>
<ul>
<li><strong>0 → Free</strong></li>
<li><strong>1 → Allocated</strong></li>
</ul>
<p>When a contiguous region is required, the kernel searches for consecutive zero bits and marks them as allocated.</p>
<p>This approach is extremely memory efficient because one bit represents one resource.</p>
<h2>Common Kernel APIs</h2>
<pre><code class="language-c">bitmap_zalloc()

bitmap_find_next_zero_area()

bitmap_set()

bitmap_clear()

bitmap_free()
</code></pre>
<hr />
<h1>Bitmap Allocation Workflow</h1>
<ol>
<li>Allocate bitmap memory.</li>
<li>Search for the next free contiguous region.</li>
<li>Mark the bits as allocated.</li>
<li>Perform work.</li>
<li>Clear the bits.</li>
<li>Free the bitmap.</li>
</ol>
<hr />
<h1>Understanding IDA</h1>
<p>IDA stands for <strong>Integer ID Allocator</strong>.</p>
<p>Unlike Bitmap, IDA does <strong>not</strong> allocate contiguous regions.</p>
<p>Instead, it allocates unique integer identifiers.</p>
<p>Typical output might be:</p>
<pre><code>0
1
2
3
4
5
</code></pre>
<p>Each allocation is completely independent.</p>
<p>IDA is widely used throughout the Linux kernel whenever objects require unique identifiers.</p>
<h2>Common Kernel APIs</h2>
<pre><code class="language-c">ida_init()

ida_alloc()

ida_free()

ida_destroy()
</code></pre>
<hr />
<h1>IDA Allocation Workflow</h1>
<ol>
<li>Initialize IDA.</li>
<li>Allocate one integer ID.</li>
<li>Use the ID.</li>
<li>Return the ID.</li>
<li>Destroy the allocator.</li>
</ol>
<hr />
<h1>Why Bitmap and IDA Solve Different Problems</h1>
<p>Although both allocate resources, they are designed for different scenarios.</p>
<p>Bitmap focuses on <strong>contiguous regions</strong>, while IDA focuses on <strong>unique identifiers</strong>.</p>
<p>Examples include:</p>
<h3>Bitmap</h3>
<ul>
<li>CPU masks</li>
<li>Memory regions</li>
<li>DMA regions</li>
<li>Block allocation</li>
<li>Fixed resource maps</li>
</ul>
<h3>IDA</h3>
<ul>
<li>Device numbers</li>
<li>Driver IDs</li>
<li>Kernel object identifiers</li>
<li>Subsystem IDs</li>
</ul>
<hr />
<h1>Linux Kernel Module Overview</h1>
<p>The module supports three execution modes.</p>
<h2>Mode 1</h2>
<p>Runs only the Bitmap allocator.</p>
<pre><code class="language-bash">sudo insmod region_demo.ko mode=1
</code></pre>
<hr />
<h2>Mode 2</h2>
<p>Runs only the IDA allocator.</p>
<pre><code class="language-bash">sudo insmod region_demo.ko mode=2
</code></pre>
<hr />
<h2>Mode 3</h2>
<p>Runs both allocators for comparison.</p>
<pre><code class="language-bash">sudo insmod region_demo.ko mode=3
</code></pre>
<hr />
<h1>Measuring Allocation Time</h1>
<p>The module measures allocation latency using the kernel timing API.</p>
<pre><code class="language-c">start = ktime_get();

/* allocation */

end = ktime_get();

ktime_to_ns(end - start);
</code></pre>
<p>Although the benchmark is intentionally simple, it demonstrates how kernel operations can be measured at nanosecond resolution.</p>
<hr />
<h1>Example Kernel Output</h1>
<p>Bitmap</p>
<pre><code>Region allocator demo loaded

Bitmap allocated region

start=0 size=8

Bitmap alloc time 13800 ns
</code></pre>
<p>IDA</p>
<pre><code>IDA allocated id=0

IDA allocated id=1

IDA allocated id=2

...

IDA alloc time 19200 ns
</code></pre>
<h1>Bitmap vs IDA</h1>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Bitmap</th>
<th>IDA</th>
</tr>
</thead>
<tbody><tr>
<td>Stores</td>
<td>Bits</td>
<td>Integer IDs</td>
</tr>
<tr>
<td>Allocation Type</td>
<td>Contiguous regions</td>
<td>Individual IDs</td>
</tr>
<tr>
<td>Memory Usage</td>
<td>Very low</td>
<td>Dynamic</td>
</tr>
<tr>
<td>Sparse Allocation</td>
<td>Not ideal</td>
<td>Excellent</td>
</tr>
<tr>
<td>Contiguous Allocation</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Primary Use</td>
<td>Resource maps</td>
<td>Kernel object IDs</td>
</tr>
<tr>
<td>Typical Search</td>
<td>Bit scanning</td>
<td>Tree/XArray traversal</td>
</tr>
</tbody></table>
<hr />
<h1>Where Does Maple Tree Fit?</h1>
<p>Modern Linux kernels increasingly use <strong>Maple Tree</strong> for managing variable-sized ranges efficiently.</p>
<p>Compared with Bitmap and IDA, Maple Tree offers:</p>
<ul>
<li>Better scalability</li>
<li>Efficient range management</li>
<li>Reduced tree overhead</li>
<li>Excellent performance for large sparse address spaces</li>
</ul>
<p>Many newer kernel subsystems are gradually adopting Maple Tree where traditional tree-based structures were previously used.</p>
<hr />
<h1>Key Takeaways</h1>
<ul>
<li>Bitmap is ideal for contiguous resource allocation.</li>
<li>IDA is designed for allocating unique integer identifiers.</li>
<li>Both allocators solve different problems and are widely used throughout the Linux kernel.</li>
<li>Measuring allocator performance helps understand the trade-offs between different kernel data structures.</li>
<li>Learning Bitmap and IDA provides an excellent foundation before exploring Maple Tree and more advanced kernel memory management techniques.</li>
</ul>
<hr />
<h1>Conclusion</h1>
<p>Kernel allocation is much more than simply requesting memory. Different kernel subsystems require different allocation strategies depending on whether they manage contiguous regions, sparse identifiers, or large variable-sized ranges.</p>
<p>This small Linux Kernel Module demonstrates how Bitmap and IDA operate internally, provides a simple timing benchmark, and connects practical experimentation with an ongoing LKML discussion. If you're learning Linux kernel development, implementing these allocators yourself is one of the best ways to understand the design decisions behind modern kernel resource management.</p>
<hr />
<h2>Source Code</h2>
<p>GitHub Repository</p>
<p><strong><a href="https://github.com/aj333git/linux_kernel_bitmap_ida">https://github.com/aj333git/linux_kernel_bitmap_ida</a></strong></p>
<hr />
<h2>References</h2>
<ul>
<li>Linux Kernel Documentation</li>
<li>Linux Kernel Bitmap API</li>
<li>Linux Kernel IDA API</li>
<li>Linux Kernel Mailing List (LKML)</li>
<li>LKML Message-ID: <code>20260717053241.916441-1-ynorov@nvidia.com</code></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Understanding the Linux Scheduler with a Kernel Module]]></title><description><![CDATA[The Linux scheduler is one of the most important components of the operating system. Every running program, background service, and kernel thread eventually interacts with the scheduler.
In this artic]]></description><link>https://devnation.joshisfitness.com/understanding-the-linux-scheduler-with-a-kernel-module</link><guid isPermaLink="true">https://devnation.joshisfitness.com/understanding-the-linux-scheduler-with-a-kernel-module</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Thu, 16 Jul 2026 09:50:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/57dd8f52-d2bb-45c2-8dc4-3739d3b622d1.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Linux scheduler is one of the most important components of the operating system. Every running program, background service, and kernel thread eventually interacts with the scheduler.</p>
<p>In this article, I will build a <strong>Linux Kernel Module (LKM)</strong> that exposes scheduler information through the <strong><code>/proc</code> filesystem</strong>, allowing us to inspect processes directly from kernel space.</p>
<p>The module targets <strong>Ubuntu 22.04 (Linux Kernel 5.15.x)</strong> and uses only modern kernel APIs.</p>
<hr />
<h1>What I will  Learn</h1>
<p>By the end of this article I will understand:</p>
<ul>
<li>Linux scheduler fundamentals</li>
<li>What <code>task_struct</code> represents</li>
<li>The <code>current</code> process pointer</li>
<li>Process priorities</li>
<li>Nice values</li>
<li>Process states</li>
<li>CPU assignment</li>
<li>The <code>/proc</code> filesystem</li>
<li>The <code>seq_file</code> interface</li>
<li>Safe kernel reads using <code>READ_ONCE()</code></li>
<li>Process iteration using <code>for_each_process()</code></li>
</ul>
<hr />
<h1>Why Build This Project?</h1>
<p>Most Linux users interact with commands like:</p>
<pre><code class="language-bash">ps
top
htop
</code></pre>
<p>These utilities obtain process information from the kernel.</p>
<p>Instead of only using these tools, this project demonstrates <strong>how the kernel itself provides scheduler information</strong>.</p>
<p>This makes it an excellent project for learning:</p>
<ul>
<li>Linux Kernel Programming</li>
<li>Operating Systems</li>
<li>Device Driver Development</li>
<li>Embedded Linux</li>
<li>Linux Internals</li>
</ul>
<hr />
<h1>Project Overview</h1>
<p>The kernel module creates a new file:</p>
<pre><code class="language-text">/proc/scheduler_demo
</code></pre>
<p>Reading this file displays scheduler information about every process currently running on the system.</p>
<p>Example:</p>
<pre><code class="language-bash">cat /proc/scheduler_demo
</code></pre>
<hr />
<h1>How the Module Works</h1>
<p>The execution flow is straightforward:</p>
<ol>
<li>Load the kernel module.</li>
<li>Register a new <code>/proc</code> entry.</li>
<li>The user reads the file.</li>
<li>The kernel invokes a callback.</li>
<li>Process information is collected.</li>
<li>Results are returned to userspace.</li>
</ol>
<hr />
<h1>Building Blocks Used</h1>
<table>
<thead>
<tr>
<th>Component</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td>Kernel Module</td>
<td>Extends kernel functionality</td>
</tr>
<tr>
<td><code>/proc</code></td>
<td>Exposes runtime kernel information</td>
</tr>
<tr>
<td><code>seq_file</code></td>
<td>Safely generates formatted output</td>
</tr>
<tr>
<td><code>task_struct</code></td>
<td>Represents a process</td>
</tr>
<tr>
<td>Scheduler APIs</td>
<td>Read scheduler information</td>
</tr>
</tbody></table>
<hr />
<h1>Understanding <code>task_struct</code></h1>
<p>Every process in Linux is represented by a <code>task_struct</code>.</p>
<p>It contains information such as:</p>
<ul>
<li>Process ID</li>
<li>Process name</li>
<li>Scheduling priority</li>
<li>Nice value</li>
<li>Current CPU</li>
<li>Memory information</li>
<li>Parent and child relationships</li>
<li>Process state</li>
<li>Credentials</li>
<li>Scheduling class</li>
</ul>
<p>Nearly every scheduler-related API operates on a <code>task_struct</code>.</p>
<hr />
<h1>The <code>current</code> Pointer</h1>
<p>Linux always knows which process is currently executing.</p>
<p>That process is accessible through:</p>
<pre><code class="language-cpp">current
</code></pre>
<p>From this pointer we can obtain information such as:</p>
<ul>
<li>PID</li>
<li>Process name</li>
<li>Priority</li>
<li>Nice value</li>
<li>Current scheduler state</li>
</ul>
<hr />
<h1>Enumerating Every Process</h1>
<p>The kernel provides an iterator for traversing every process.</p>
<pre><code class="language-cpp">for_each_process(task)
{
    /* Scheduler information */
}
</code></pre>
<p>This macro walks through the kernel's process list and allows the module to inspect each task.</p>
<hr />
<h1>Reading the Current CPU</h1>
<p>Every process executes on a CPU core.</p>
<p>The kernel provides:</p>
<pre><code class="language-cpp">task_cpu(task)
</code></pre>
<p>which returns the CPU currently associated with that task.</p>
<p>This is useful when studying:</p>
<ul>
<li>SMP systems</li>
<li>CPU scheduling</li>
<li>Load balancing</li>
<li>Processor affinity</li>
</ul>
<hr />
<h1>Understanding Priorities</h1>
<p>Linux scheduling uses several priority values.</p>
<p>This project prints:</p>
<ul>
<li>Scheduler priority</li>
<li>Static priority</li>
<li>Normal priority</li>
<li>Nice value</li>
</ul>
<p>Together these values determine how the scheduler treats a process.</p>
<hr />
<h1>Nice Values</h1>
<p>User processes can influence scheduling through the <strong>nice value</strong>.</p>
<p>Typical range:</p>
<table>
<thead>
<tr>
<th>Nice Value</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td>-20</td>
<td>Highest priority</td>
</tr>
<tr>
<td>0</td>
<td>Default</td>
</tr>
<tr>
<td>+19</td>
<td>Lowest priority</td>
</tr>
</tbody></table>
<p>The module retrieves it using:</p>
<pre><code class="language-cpp">task_nice(task)
</code></pre>
<hr />
<h1>Process States</h1>
<p>Processes constantly transition between states.</p>
<p>Examples include:</p>
<ul>
<li>Running</li>
<li>Runnable</li>
<li>Sleeping</li>
<li>Stopped</li>
<li>Zombie</li>
</ul>
<p>The module safely reads the scheduler state using:</p>
<pre><code class="language-cpp">READ_ONCE(task-&gt;__state)
</code></pre>
<p>Using <code>READ_ONCE()</code> prevents compiler optimizations from producing inconsistent reads when scheduler data changes concurrently.</p>
<hr />
<h1>Detecting Runnable Tasks</h1>
<p>The module checks whether a process is runnable using:</p>
<pre><code class="language-cpp">task_is_running(task)
</code></pre>
<p>This modern helper is preferred over manually interpreting scheduler state bits.</p>
<hr />
<h1>Why Use <code>/proc</code>?</h1>
<p>The <code>/proc</code> filesystem is designed to expose runtime kernel and process information.</p>
<p>Examples include:</p>
<pre><code class="language-text">/proc/cpuinfo
/proc/meminfo
/proc/modules
/proc/uptime
</code></pre>
<p>Our module simply adds another entry:</p>
<pre><code class="language-text">/proc/scheduler_demo
</code></pre>
<hr />
<h1>Why <code>seq_file</code>?</h1>
<p>Kernel output can become very large.</p>
<p>Instead of manually managing buffers, Linux provides the <strong><code>seq_file</code></strong> interface.</p>
<p>Benefits include:</p>
<ul>
<li>Automatic buffering</li>
<li>Safe iteration</li>
<li>Large output support</li>
<li>Simpler implementation</li>
<li>Better maintainability</li>
</ul>
<p>The module prints information using:</p>
<pre><code class="language-cpp">seq_printf(...)
</code></pre>
<hr />
<h1>Creating the <code>/proc</code> Entry</h1>
<p>The module creates the file using:</p>
<pre><code class="language-cpp">proc_create(...)
</code></pre>
<p>When the module is unloaded, it removes the entry using:</p>
<pre><code class="language-cpp">remove_proc_entry(...)
</code></pre>
<p>This keeps the filesystem clean and avoids leaving stale entries behind.</p>
<hr />
<h1>Kernel Module Lifecycle</h1>
<p>Every Linux Kernel Module follows a lifecycle.</p>
<p>Initialization:</p>
<pre><code class="language-cpp">module_init(...)
</code></pre>
<p>Cleanup:</p>
<pre><code class="language-cpp">module_exit(...)
</code></pre>
<p>Initialization registers resources, while cleanup releases them before the module is unloaded.</p>
<hr />
<hr />
<h1>APIs Covered</h1>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>current</code></td>
<td>Current executing process</td>
</tr>
<tr>
<td><code>task_struct</code></td>
<td>Process descriptor</td>
</tr>
<tr>
<td><code>for_each_process()</code></td>
<td>Iterate over all processes</td>
</tr>
<tr>
<td><code>task_cpu()</code></td>
<td>CPU associated with a task</td>
</tr>
<tr>
<td><code>task_nice()</code></td>
<td>Retrieve nice value</td>
</tr>
<tr>
<td><code>task_is_running()</code></td>
<td>Check runnable state</td>
</tr>
<tr>
<td><code>READ_ONCE()</code></td>
<td>Safe concurrent read</td>
</tr>
<tr>
<td><code>proc_create()</code></td>
<td>Create <code>/proc</code> entry</td>
</tr>
<tr>
<td><code>remove_proc_entry()</code></td>
<td>Remove <code>/proc</code> entry</td>
</tr>
<tr>
<td><code>seq_printf()</code></td>
<td>Generate <code>/proc</code> output</td>
</tr>
<tr>
<td><code>single_open()</code></td>
<td>Connect <code>/proc</code> with callback</td>
</tr>
<tr>
<td><code>module_init()</code></td>
<td>Module initialization</td>
</tr>
<tr>
<td><code>module_exit()</code></td>
<td>Module cleanup</td>
</tr>
</tbody></table>
<hr />
<h1>Key Takeaways</h1>
<p>This project demonstrates several important Linux kernel concepts in a compact and practical example.</p>
<p>You learned how to:</p>
<ul>
<li>Create a Linux Kernel Module</li>
<li>Add custom entries to the <code>/proc</code> filesystem</li>
<li>Traverse every process in the kernel</li>
<li>Read scheduler metadata</li>
<li>Display process priorities and nice values</li>
<li>Access CPU information</li>
<li>Safely inspect process states</li>
<li>Generate formatted kernel output using <code>seq_file</code></li>
<li>Follow modern Linux Kernel 5.15 programming practices</li>
</ul>
<p>Although intentionally simple, this module forms a strong foundation for studying advanced scheduler topics such as the Completely Fair Scheduler (CFS), scheduling classes, CPU affinity, load balancing, kernel threads, and scheduler internals.</p>
<hr />
<h1>Conclusion</h1>
<p>The Linux scheduler is responsible for deciding <strong>which process runs, when it runs, and on which CPU</strong>. By exposing scheduler information through a custom <code>/proc</code> entry, this project provides a practical way to explore those internals without modifying the kernel itself.</p>
<p>For learning Linux kernel programming, operating systems, embedded Linux, or device driver development, implementing small projects like this is one of the most effective ways to understand how the kernel works beneath the surface.</p>
<hr />
<p>GitHub Repository: 👉 <strong><a href="https://github.com/aj333git/linux_kernel_scheduler">linux_kernel_scheduler</a></strong> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Using Kernel Mutexes ]]></title><description><![CDATA[Linux Kernel Mutexes Explained with a Mini Driver
Concurrency is a fundamental aspect of Linux kernel programming. Device drivers often execute in multiple contexts, making synchronization essential w]]></description><link>https://devnation.joshisfitness.com/using-kernel-mutexes</link><guid isPermaLink="true">https://devnation.joshisfitness.com/using-kernel-mutexes</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Sat, 11 Jul 2026 14:19:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/35243d45-4de8-4d48-b05f-ca9eec31d047.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Linux Kernel Mutexes Explained with a Mini Driver</h1>
<p>Concurrency is a fundamental aspect of Linux kernel programming. Device drivers often execute in multiple contexts, making synchronization essential whenever shared data is accessed.</p>
<p>One of the most widely used synchronization primitives in the Linux kernel is the <strong>mutex</strong>. A mutex ensures that only one execution context can access a shared resource at a time, preventing race conditions and preserving data consistency.</p>
<p>In this article, I will build a mental model around Linux mutexes using a small driver that demonstrates how multiple kernel threads safely share a common driver context.</p>
<hr />
<h1>Why Do Device Drivers Need Synchronization?</h1>
<p>Modern Linux systems execute many threads concurrently.</p>
<p>Imagine a network driver where one thread transmits packets while another receives packets and a third periodically gathers statistics.</p>
<p>All of them access the same driver state.</p>
<p>Without synchronization, concurrent updates can corrupt shared data.</p>
<p>Typical shared driver state includes:</p>
<ul>
<li><p>Packet counters</p>
</li>
<li><p>Device status</p>
</li>
<li><p>Buffers</p>
</li>
<li><p>Hardware configuration</p>
</li>
<li><p>Runtime statistics</p>
</li>
</ul>
<p>Whenever multiple execution contexts access shared mutable data, synchronization becomes necessary.</p>
<hr />
<h1>Driver Context</h1>
<p>A common Linux driver design pattern is to store all runtime information inside a single structure called the <strong>Driver Context</strong>.</p>
<p>Instead of scattering global variables throughout the driver, everything is encapsulated into one object.</p>
<p>Example:</p>
<pre><code class="language-c">struct driver_context {
    struct mutex lock;
    int tx_packets;
    int rx_packets;
    bool device_enabled;
    char device_name[32];
};
</code></pre>
<p>This approach improves:</p>
<ul>
<li><p>Maintainability</p>
</li>
<li><p>Readability</p>
</li>
<li><p>Encapsulation</p>
</li>
<li><p>Synchronization</p>
</li>
<li><p>Scalability</p>
</li>
</ul>
<p>Nearly every production-quality Linux driver maintains some form of private context structure.</p>
<hr />
<h1>Shared Writable Data</h1>
<p>Inside the driver context are variables that multiple threads may both read and modify.</p>
<p>Examples include:</p>
<ul>
<li><p><code>tx_packets</code></p>
</li>
<li><p><code>rx_packets</code></p>
</li>
<li><p><code>device_enabled</code></p>
</li>
</ul>
<p>These variables are called <strong>Shared Writable Data</strong> because:</p>
<ul>
<li><p>multiple threads access them</p>
</li>
<li><p>their values change during execution</p>
</li>
</ul>
<p>Since concurrent access is possible, synchronization is required.</p>
<hr />
<h1>Critical Sections</h1>
<p>A <strong>Critical Section</strong> is the portion of code that accesses shared writable data.</p>
<p>Only one execution context should execute a critical section at any given time.</p>
<p>A mutex creates this protected region.</p>
<p>Example:</p>
<pre><code class="language-c">mutex_lock(&amp;ctx-&gt;lock);

ctx-&gt;tx_packets++;

mutex_unlock(&amp;ctx-&gt;lock);
</code></pre>
<p>Everything between <code>mutex_lock()</code> and <code>mutex_unlock()</code> belongs to the critical section.</p>
<hr />
<h1>Linux Mutex APIs</h1>
<p>The Linux kernel provides a small but powerful mutex API.</p>
<h3>mutex_init()</h3>
<p>Initializes a mutex before it can be used.</p>
<pre><code class="language-c">mutex_init(&amp;ctx-&gt;lock);
</code></pre>
<hr />
<h3>mutex_lock()</h3>
<p>Acquires exclusive ownership of the mutex.</p>
<p>If another thread already owns it, the caller sleeps until the mutex becomes available.</p>
<pre><code class="language-c">mutex_lock(&amp;ctx-&gt;lock);
</code></pre>
<hr />
<h3>mutex_lock_interruptible()</h3>
<p>Works similarly to <code>mutex_lock()</code>, but allows the waiting task to be interrupted by a signal.</p>
<pre><code class="language-c">if (mutex_lock_interruptible(&amp;ctx-&gt;lock))
    return -EINTR;
</code></pre>
<hr />
<h3>mutex_unlock()</h3>
<p>Releases the mutex so another waiting thread can proceed.</p>
<pre><code class="language-c">mutex_unlock(&amp;ctx-&gt;lock);
</code></pre>
<hr />
<h3>mutex_destroy()</h3>
<p>Destroys a dynamically initialized mutex during cleanup.</p>
<pre><code class="language-c">mutex_destroy(&amp;ctx-&gt;lock);
</code></pre>
<hr />
<h1>Worker Threads</h1>
<p>The demo launches three kernel threads.</p>
<h2>TX Thread</h2>
<p>Responsible for transmitting packets.</p>
<p>Responsibilities include:</p>
<ul>
<li><p>Acquire mutex</p>
</li>
<li><p>Update TX counter</p>
</li>
<li><p>Release mutex</p>
</li>
</ul>
<hr />
<h2>RX Thread</h2>
<p>Responsible for receiving packets.</p>
<p>It demonstrates the use of <code>mutex_lock_interruptible()</code> while updating the receive counter.</p>
<hr />
<h2>Statistics Thread</h2>
<p>Periodically reads the driver state.</p>
<p>Although it performs only reads, it still acquires the mutex because the shared data may be changing concurrently.</p>
<hr />
<h1>Why Lock During Reads?</h1>
<p>Many beginners assume only writers require synchronization.</p>
<p>This is incorrect.</p>
<p>Suppose the TX thread updates a packet counter while the Statistics thread is reading it.</p>
<p>Without synchronization, the reader may observe inconsistent state.</p>
<p>Production Linux drivers therefore commonly synchronize both readers and writers whenever they access shared mutable data.</p>
<hr />
<h1>Race Conditions</h1>
<p>A race condition occurs whenever multiple execution contexts modify shared data without proper synchronization.</p>
<p>Consider a shared counter with an initial value of 5.</p>
<p>Two CPUs increment it simultaneously.</p>
<p>Each CPU reads the value 5, increments it, and writes back 6.</p>
<p>The expected value is 7, but the final value becomes 6.</p>
<p>One increment is lost.</p>
<p>This classic problem is known as a <strong>Race Condition</strong>.</p>
<p>Mutexes prevent this by allowing only one thread to execute the critical section at a time.</p>
<hr />
<h1>Lock Contention</h1>
<p>Lock contention occurs when multiple threads attempt to acquire the same mutex simultaneously.</p>
<p>Only one thread can own the mutex.</p>
<p>The remaining threads wait until it becomes available.</p>
<p>Some contention is expected in concurrent systems.</p>
<p>However, excessive contention reduces:</p>
<ul>
<li><p>Throughput</p>
</li>
<li><p>Parallelism</p>
</li>
<li><p>Overall performance</p>
</li>
</ul>
<hr />
<h1>Sleeping While Holding a Mutex</h1>
<p>One important characteristic of Linux mutexes is that the owner is allowed to sleep while holding the lock.</p>
<p>For demonstration purposes, the TX thread intentionally sleeps after acquiring the mutex.</p>
<p>This makes lock contention easy to observe because other threads remain blocked while the mutex is held.</p>
<p>Although this behavior is useful for teaching synchronization, production drivers generally avoid holding mutexes longer than necessary.</p>
<hr />
<h1>Production Driver vs Demonstration Driver</h1>
<p>The objective of this project is education rather than performance.</p>
<p>The demonstration intentionally keeps the mutex for a longer duration so waiting threads can be observed.</p>
<p>A production-quality driver typically follows a different philosophy.</p>
<p>Keep critical sections:</p>
<ul>
<li><p>Small</p>
</li>
<li><p>Predictable</p>
</li>
<li><p>Efficient</p>
</li>
</ul>
<p>Protect only the shared resource.</p>
<p>Release the mutex immediately after the shared state has been updated.</p>
<p>Long critical sections increase contention and reduce concurrency.</p>
<hr />
<h1>Key Concepts</h1>
<table>
<thead>
<tr>
<th>Concept</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td>Driver Context</td>
<td>Stores the runtime state of a driver</td>
</tr>
<tr>
<td>Shared Writable Data</td>
<td>Variables accessed by multiple threads</td>
</tr>
<tr>
<td>Critical Section</td>
<td>Code that accesses shared mutable data</td>
</tr>
<tr>
<td>Mutex</td>
<td>Ensures mutual exclusion</td>
</tr>
<tr>
<td>Race Condition</td>
<td>Concurrent unsynchronized access causing incorrect results</td>
</tr>
<tr>
<td>Lock Contention</td>
<td>Multiple threads competing for the same mutex</td>
</tr>
</tbody></table>
<hr />
<h1>Interview Takeaways</h1>
<p>If asked about mutexes during a Linux kernel interview, remember these points:</p>
<ul>
<li><p>A mutex protects shared writable data.</p>
</li>
<li><p>Only one thread may own a mutex at a time.</p>
</li>
<li><p>Mutexes are sleeping locks.</p>
</li>
<li><p><code>mutex_lock_interruptible()</code> allows interrupted waits.</p>
</li>
<li><p>Critical sections should be kept as short as possible.</p>
</li>
<li><p>Driver contexts encapsulate shared runtime state.</p>
</li>
<li><p>Production drivers synchronize both readers and writers.</p>
</li>
</ul>
<hr />
<h1>Conclusion</h1>
<p>The purpose of this mini driver is not to demonstrate multithreading itself.</p>
<p>The worker threads simply create concurrent access.</p>
<p>The real lesson is understanding how a single Linux mutex protects a shared driver context, ensuring safe access to shared mutable data while preventing race conditions.</p>
<p>Once these core ideas become clear, you'll recognize the same synchronization pattern throughout the Linux kernel and in production-quality device drivers.</p>
<hr />
<p>GitHub Repository: 👉 <a href="https://github.com/aj333git/linux_kernel_mutex4"><strong>linux_kernel_mutex4</strong></a> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Linux Kernel Mutexes: Safe Synchronization with Kernel Threads]]></title><description><![CDATA[Modern Linux kernel development is fundamentally about correctness under concurrency. Whether we're writing a character driver, platform driver, network subsystem, or filesystem code, multiple executi]]></description><link>https://devnation.joshisfitness.com/linux-kernel-mutexes-safe-synchronization-with-kernel-threads</link><guid isPermaLink="true">https://devnation.joshisfitness.com/linux-kernel-mutexes-safe-synchronization-with-kernel-threads</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Thu, 09 Jul 2026 10:54:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/1e98cefb-01ec-4aa3-9623-92d08866a332.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Modern Linux kernel development is fundamentally about <strong>correctness under concurrency</strong>. Whether we're writing a character driver, platform driver, network subsystem, or filesystem code, multiple execution contexts often access the same shared data simultaneously. Without proper synchronization, race conditions can corrupt kernel state and produce unpredictable behavior.</p>
<p>One of the most widely used synchronization primitives in Linux is the <strong>mutex</strong>. Unlike spinlocks, mutexes are <strong>sleeping locks</strong>, making them ideal for protecting shared resources in process context where blocking is allowed.</p>
<p>In this article, I'll build a Linux kernel module that demonstrates mutex synchronization using two competing kernel threads while exploring the design principles behind mutexes.</p>
<hr />
<h1>Why Do We Need Mutexes?</h1>
<p>Consider two kernel threads incrementing the same shared counter.</p>
<p>Without synchronization, both threads may read the same value before either writes it back, causing one update to be lost.</p>
<p>This classic race condition leads to inconsistent program behavior.</p>
<p>A mutex ensures that <strong>only one thread can enter the critical section at a time</strong>, preserving data integrity.</p>
<hr />
<h1>Project Overview</h1>
<p>The module demonstrates:</p>
<ul>
<li><p>Linux kernel threads (<code>kthread_run()</code>)</p>
</li>
<li><p>Shared resource protection</p>
</li>
<li><p>Dynamic memory allocation</p>
</li>
<li><p>Static mutex initialization</p>
</li>
<li><p>Dynamic mutex initialization</p>
</li>
<li><p>Critical sections</p>
</li>
<li><p>Safe synchronization</p>
</li>
<li><p>Module initialization and cleanup</p>
</li>
</ul>
<p>The shared driver context contains both the protected data and the mutex.</p>
<pre><code class="language-c">struct demo_context {
    int shared_counter;
    struct mutex lock;
};
</code></pre>
<p>The counter is accessed by two independent kernel threads, both competing for the same mutex.</p>
<hr />
<h1>Static vs Dynamic Mutex Initialization</h1>
<p>Linux provides two ways to initialize a mutex.</p>
<h2>Static Initialization</h2>
<p>Static mutexes are initialized automatically before the module starts executing.</p>
<pre><code class="language-c">static DEFINE_MUTEX(global_mutex);
</code></pre>
<p>This approach is ideal for global or module-wide locks whose lifetime matches the module.</p>
<h3>Advantages</h3>
<ul>
<li><p>No initialization call required</p>
</li>
<li><p>Simple and efficient</p>
</li>
<li><p>Lifetime equals module lifetime</p>
</li>
</ul>
<hr />
<h2>Dynamic Initialization</h2>
<p>When mutexes are embedded inside dynamically allocated objects, they must be initialized explicitly.</p>
<pre><code class="language-c">ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);

mutex_init(&amp;ctx-&gt;lock);
</code></pre>
<p>This is the preferred approach for driver-specific objects allocated at runtime.</p>
<h3>Advantages</h3>
<ul>
<li><p>Works with dynamically allocated structures</p>
</li>
<li><p>Common in device drivers</p>
</li>
<li><p>Flexible for multiple device instances</p>
</li>
</ul>
<hr />
<h1>Creating Kernel Threads</h1>
<p>The module launches two worker threads.</p>
<pre><code class="language-c">thread1 = kthread_run(worker, (void *)1, "mutex_thread1");

thread2 = kthread_run(worker, (void *)2, "mutex_thread2");
</code></pre>
<p>Both execute the same worker function and continuously compete for the mutex.</p>
<hr />
<h1>Entering the Critical Section</h1>
<p>The critical section begins when the mutex is acquired.</p>
<pre><code class="language-c">mutex_lock(&amp;ctx-&gt;lock);

ctx-&gt;shared_counter++;

mutex_unlock(&amp;ctx-&gt;lock);
</code></pre>
<p>If another thread already owns the mutex, the current thread is automatically put to sleep until the lock becomes available.</p>
<p>Unlike busy waiting, sleeping conserves CPU resources and improves overall system efficiency.</p>
<hr />
<h1>Sleeping Inside a Mutex</h1>
<p>One interesting aspect of this example is that the worker intentionally sleeps while holding the mutex.</p>
<pre><code class="language-c">msleep(1000);
</code></pre>
<p>This demonstrates an important property of Linux mutexes:</p>
<ul>
<li><p>Sleeping <strong>is allowed</strong> while holding a mutex.</p>
</li>
<li><p>Sleeping <strong>is forbidden</strong> while holding a spinlock.</p>
</li>
</ul>
<p>Although sleeping inside a mutex is legal, real production code should keep critical sections as short as possible to minimize lock contention.</p>
<hr />
<h1>Understanding the Worker Thread</h1>
<p>Each worker repeatedly performs the following sequence:</p>
<ol>
<li><p>Acquire the mutex.</p>
</li>
<li><p>Increment the shared counter.</p>
</li>
<li><p>Print the updated value.</p>
</li>
<li><p>Sleep briefly.</p>
</li>
<li><p>Release the mutex.</p>
</li>
<li><p>Sleep outside the critical section.</p>
</li>
</ol>
<p>This repeated competition clearly demonstrates serialized access to shared data.</p>
<hr />
<h1>Expected Kernel Output</h1>
<p>A typical execution looks like this:</p>
<pre><code class="language-text">===== Mutex Demo Loaded =====

Static mutex locked once

Thread 1 acquired mutex
Thread 1 Counter=1
Thread 1 releasing mutex

Thread 2 acquired mutex
Thread 2 Counter=2
Thread 2 releasing mutex
</code></pre>
<p>Notice that the counter always increases sequentially.</p>
<p>There is never simultaneous access to the protected resource.</p>
<hr />
<h1>Important Mutex APIs</h1>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>DEFINE_MUTEX()</code></td>
<td>Static initialization</td>
</tr>
<tr>
<td><code>mutex_init()</code></td>
<td>Dynamic initialization</td>
</tr>
<tr>
<td><code>mutex_lock()</code></td>
<td>Acquire mutex</td>
</tr>
<tr>
<td><code>mutex_unlock()</code></td>
<td>Release mutex</td>
</tr>
<tr>
<td><code>kthread_run()</code></td>
<td>Create kernel thread</td>
</tr>
<tr>
<td><code>kthread_stop()</code></td>
<td>Stop kernel thread</td>
</tr>
<tr>
<td><code>msleep()</code></td>
<td>Sleep in process context</td>
</tr>
</tbody></table>
<hr />
<h1>Essential Mutex Rules</h1>
<h2>1. Only One Owner</h2>
<p>Only one task may own a mutex at any moment.</p>
<p>Any additional thread attempting to acquire it will sleep until it becomes available.</p>
<hr />
<h2>2. Owner Must Unlock</h2>
<p>The thread that acquires the mutex must also release it.</p>
<p>Unlocking a mutex from another thread leads to undefined behavior.</p>
<hr />
<h2>3. Recursive Locking Is Not Allowed</h2>
<p>Attempting to acquire the same mutex twice from the same thread causes a deadlock.</p>
<p>Avoid recursive locking unless a different synchronization primitive is specifically designed for it.</p>
<hr />
<h2>4. Mutexes May Sleep</h2>
<p>Because <code>mutex_lock()</code> may block, mutexes are valid only in <strong>process context</strong>.</p>
<p>They are commonly used inside:</p>
<ul>
<li><p>Kernel threads</p>
</li>
<li><p>System calls</p>
</li>
<li><p>Character device operations</p>
</li>
<li><p>Driver read/write methods</p>
</li>
</ul>
<hr />
<h2>5. Never Use Mutexes in Atomic Context</h2>
<p>Mutexes should never be used inside:</p>
<ul>
<li><p>Interrupt handlers</p>
</li>
<li><p>SoftIRQs</p>
</li>
<li><p>Tasklets</p>
</li>
<li><p>Timers</p>
</li>
<li><p>Other atomic contexts</p>
</li>
</ul>
<p>Blocking is not permitted in these execution contexts.</p>
<hr />
<h2>6. Keep Critical Sections Small</h2>
<p>The protected region should contain only the minimum required operations.</p>
<p>Smaller critical sections improve scalability, reduce contention, and increase overall system responsiveness.</p>
<hr />
<h2>7. Follow Consistent Lock Ordering</h2>
<p>When multiple locks are required, always acquire them in the same order throughout the codebase.</p>
<p>Consistent ordering is one of the simplest and most effective techniques for preventing deadlocks.</p>
<hr />
<h1>Module Lifecycle</h1>
<h2>Module Initialization</h2>
<p>During module loading, the following sequence occurs:</p>
<ul>
<li><p>Allocate driver context</p>
</li>
<li><p>Initialize dynamic mutex</p>
</li>
<li><p>Demonstrate static mutex</p>
</li>
<li><p>Launch two kernel threads</p>
</li>
</ul>
<hr />
<h2>Module Cleanup</h2>
<p>During module removal:</p>
<ul>
<li><p>Stop both kernel threads</p>
</li>
<li><p>Free allocated memory</p>
</li>
<li><p>Exit cleanly</p>
</li>
</ul>
<p>Proper cleanup ensures that no kernel resources are leaked.</p>
<hr />
<h1>Where Are Mutexes Used?</h1>
<p>Mutexes appear throughout the Linux kernel and are commonly used in:</p>
<ul>
<li><p>Character device drivers</p>
</li>
<li><p>Platform drivers</p>
</li>
<li><p>USB drivers</p>
</li>
<li><p>PCI drivers</p>
</li>
<li><p>I2C drivers</p>
</li>
<li><p>SPI drivers</p>
</li>
<li><p>Filesystems</p>
</li>
<li><p>Network drivers</p>
</li>
<li><p>Virtual device drivers</p>
</li>
<li><p>Embedded Linux systems</p>
</li>
</ul>
<p>Typical protected resources include:</p>
<ul>
<li><p>Device state</p>
</li>
<li><p>Hardware registers</p>
</li>
<li><p>Linked lists</p>
</li>
<li><p>Queues</p>
</li>
<li><p>Buffers</p>
</li>
<li><p>Configuration structures</p>
</li>
<li><p>Statistics</p>
</li>
<li><p>Driver context objects</p>
</li>
</ul>
<hr />
<h1>Final Thoughts</h1>
<p>Mutexes are among the most important synchronization primitives in Linux kernel development. Understanding when to use them—and equally important, when <strong>not</strong> to use them—is fundamental for writing reliable kernel modules and production-quality device drivers.</p>
<p>This demonstration illustrates the complete lifecycle of mutex usage, from initialization and lock acquisition to protecting shared resources and performing clean module shutdown. Once these fundamentals are mastered, I can confidently move on to advanced synchronization mechanisms such as semaphores, completions, wait queues, spinlocks, reader-writer locks, RCU, and lock-free programming techniques.</p>
<hr />
<p>GitHub Repository: 👉 <strong><a href="https://github.com/aj333git/linux_kernel_mutex3">linux_kernel_mutex3</a></strong> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Synchronization Using `struct mutex` in Linux Kernel Modules]]></title><description><![CDATA[A hands-on Linux Kernel Module (LKM) demonstrating kernel mutexes, kernel threads, critical sections, thread synchronization, and proper module lifecycle management.


Table of Contents

Overview
Lear]]></description><link>https://devnation.joshisfitness.com/synchronization-using-struct-mutex-in-linux-kernel-modules</link><guid isPermaLink="true">https://devnation.joshisfitness.com/synchronization-using-struct-mutex-in-linux-kernel-modules</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Fri, 03 Jul 2026 10:04:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/fa50276b-de82-4e6d-84ef-285c1a656611.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>A <strong>hands-on Linux Kernel Module (LKM)</strong> demonstrating kernel mutexes, kernel threads, critical sections, thread synchronization, and proper module lifecycle management.</p>
</blockquote>
<hr />
<h1>Table of Contents</h1>
<ul>
<li>Overview</li>
<li>Learning Objectives</li>
<li>Concepts Covered</li>
<li>Project Structure</li>
<li>Build Requirements</li>
<li>Compilation</li>
<li>Module Signing (Secure Boot)</li>
<li>Loading the Module</li>
<li>Viewing Kernel Logs</li>
<li>Unloading the Module</li>
<li>Execution Flow</li>
<li>Program Architecture</li>
<li>Source Code Walkthrough</li>
<li>Kernel Threads</li>
<li>Driver Private Context</li>
<li>Understanding Mutex</li>
<li>Critical Section</li>
<li><code>mutex_lock()</code></li>
<li><code>mutex_lock_interruptible()</code></li>
<li>Thread Competition</li>
<li>Expected Execution Timeline</li>
<li>Kernel Log Explanation</li>
<li>Module Cleanup</li>
<li>Important Kernel APIs</li>
<li>Why Mutex Instead of Spinlock?</li>
<li>Common Interview Questions</li>
<li>Exercises</li>
<li>References</li>
</ul>
<hr />
<h1>Overview</h1>
<p>This project demonstrates one of the most fundamental synchronization primitives in the Linux kernel:</p>
<ul>
<li><code>struct mutex</code></li>
</ul>
<p>The module creates <strong>two kernel threads</strong> that continuously compete for a shared mutex while modifying a shared variable.</p>
<p>The program intentionally introduces contention so the kernel scheduler blocks one thread while the other owns the mutex.</p>
<p>This is exactly how real Linux device drivers protect shared resources.</p>
<p>Examples include</p>
<ul>
<li>USB Drivers</li>
<li>PCI Drivers</li>
<li>Character Drivers</li>
<li>I2C Drivers</li>
<li>SPI Drivers</li>
<li>Network Drivers</li>
<li>Filesystem Drivers</li>
</ul>
<hr />
<h1>Learning Objectives</h1>
<p>After completing this example you should understand</p>
<ul>
<li>Linux Kernel Modules</li>
<li>Kernel Threads</li>
<li>Driver Private Data</li>
<li>Shared Resources</li>
<li>Race Conditions</li>
<li>Critical Sections</li>
<li>Sleeping Locks</li>
<li>Mutex Initialization</li>
<li>Mutex Acquisition</li>
<li>Mutex Release</li>
<li>Interruptible Waiting</li>
<li>Thread Scheduling</li>
<li>Proper Cleanup</li>
</ul>
<hr />
<h1>Concepts Covered</h1>
<table>
<thead>
<tr>
<th>Concept</th>
<th>Demonstrated</th>
</tr>
</thead>
<tbody><tr>
<td>Linux Kernel Module</td>
<td>✅</td>
</tr>
<tr>
<td><code>struct mutex</code></td>
<td>✅</td>
</tr>
<tr>
<td><code>mutex_init()</code></td>
<td>✅</td>
</tr>
<tr>
<td><code>mutex_lock()</code></td>
<td>✅</td>
</tr>
<tr>
<td><code>mutex_unlock()</code></td>
<td>✅</td>
</tr>
<tr>
<td><code>mutex_lock_interruptible()</code></td>
<td>✅</td>
</tr>
<tr>
<td><code>mutex_destroy()</code></td>
<td>✅</td>
</tr>
<tr>
<td>Kernel Threads</td>
<td>✅</td>
</tr>
<tr>
<td><code>kthread_run()</code></td>
<td>✅</td>
</tr>
<tr>
<td><code>kthread_stop()</code></td>
<td>✅</td>
</tr>
<tr>
<td>Shared Data</td>
<td>✅</td>
</tr>
<tr>
<td>Critical Section</td>
<td>✅</td>
</tr>
<tr>
<td>Thread Contention</td>
<td>✅</td>
</tr>
<tr>
<td>Race Condition Prevention</td>
<td>✅</td>
</tr>
<tr>
<td>Proper Module Cleanup</td>
<td>✅</td>
</tr>
</tbody></table>
<hr />
<h1>Project Structure</h1>
<pre><code>mutex_demo/
│
├── Makefile
├── mutex_demo.c
└── README.md
</code></pre>
<hr />
<h1>Build Requirements</h1>
<ul>
<li>Linux Kernel Headers</li>
<li>GCC</li>
<li>Make</li>
<li>Root Privileges</li>
<li>Secure Boot Keys (if Secure Boot enabled)</li>
</ul>
<h1>High Level Execution Flow</h1>
<pre><code>           insmod
              │
              ▼
     module_init()
              │
              ▼
     Initialize Mutex
              │
              ▼
      shared_counter=0
              │
              ▼
    Create Kernel Thread T1
              │
              ▼
    Create Kernel Thread T2
              │
              ▼
   Both compete for mutex
              │
              ▼
 Enter Critical Section
              │
              ▼
 Increment Counter
              │
              ▼
 Release Mutex
              │
              ▼
 Repeat
              │
              ▼
         rmmod
              │
              ▼
     Stop Both Threads
              │
              ▼
     Destroy Mutex
              │
              ▼
       Module Exit
</code></pre>
<hr />
<h1>Program Architecture</h1>
<pre><code>                    +------------------------+
                    | Linux Kernel Module    |
                    +-----------+------------+
                                |
                                |
                    +-----------v------------+
                    | Driver Private Context |
                    +------------------------+
                    | shared_counter         |
                    | struct mutex mymtx     |
                    +-----------+------------+
                                |
          +---------------------+---------------------+
          |                                           |
          |                                           |
+---------v---------+                     +-----------v----------+
| Kernel Thread T1  |                     | Kernel Thread T2     |
| mutex_lock()      |                     | mutex_lock_interruptible() |
+---------+---------+                     +-----------+----------+
          |                                           |
          +---------------------+---------------------+
                                |
                                ▼
                        Shared Counter
</code></pre>
<hr />
<h1>Driver Private Context</h1>
<pre><code class="language-c">struct mydrv_priv
{
    int shared_counter;
    struct mutex mymtx;
};
</code></pre>
<p>This structure stores</p>
<ul>
<li>Driver state</li>
<li>Shared resources</li>
<li>Synchronization objects</li>
</ul>
<p>Nearly every Linux device driver maintains a private structure similar to this.</p>
<hr />
<h1>Shared Counter</h1>
<pre><code class="language-c">drvctx.shared_counter++;
</code></pre>
<p>Both threads modify this variable.</p>
<p>Without synchronization</p>
<pre><code>T1 reads 10

T2 reads 10

T1 writes 11

T2 writes 11
</code></pre>
<p>Expected</p>
<pre><code>12
</code></pre>
<p>Actual</p>
<pre><code>11
</code></pre>
<p>This is called a</p>
<h1>Race Condition</h1>
<hr />
<h1>Critical Section</h1>
<p>A <strong>critical section</strong> is any code accessing shared resources.</p>
<pre><code>mutex_lock()

↓

Modify Shared Data

↓

mutex_unlock()
</code></pre>
<p>In this example</p>
<pre><code class="language-c">mutex_lock(&amp;drvctx.mymtx);

drvctx.shared_counter++;

mutex_unlock(&amp;drvctx.mymtx);
</code></pre>
<p>Only one thread may execute this block at any time.</p>
<hr />
<h1>Kernel Threads</h1>
<p>The module creates two kernel threads.</p>
<pre><code>Thread 1

↓

worker_lock()
</code></pre>
<pre><code>Thread 2

↓

worker_interruptible()
</code></pre>
<p>Creation</p>
<pre><code class="language-c">kthread_run()
</code></pre>
<p>Stopping</p>
<pre><code class="language-c">kthread_stop()
</code></pre>
<p>Thread loop</p>
<pre><code class="language-c">while (!kthread_should_stop())
</code></pre>
<p>This is the standard Linux kernel thread pattern.</p>
<hr />
<h1>Understanding Mutex</h1>
<p>Mutex means</p>
<blockquote>
<p>Mutual Exclusion</p>
</blockquote>
<p>Only one thread may own the mutex.</p>
<pre><code>          Mutex

      Locked
         │
         ▼

      Thread 1

Thread 2 waits

Thread 3 waits
</code></pre>
<p>Once unlocked</p>
<pre><code>Scheduler wakes

↓

Next waiting thread
</code></pre>
<hr />
<h1>mutex_init()</h1>
<pre><code class="language-c">mutex_init(&amp;drvctx.mymtx);
</code></pre>
<p>Initializes the mutex.</p>
<p>Internally</p>
<pre><code>Unlocked

Owner = NULL

Wait Queue = Empty
</code></pre>
<hr />
<h1>mutex_lock()</h1>
<pre><code class="language-c">mutex_lock(&amp;drvctx.mymtx);
</code></pre>
<p>If mutex is free</p>
<pre><code>Acquire immediately
</code></pre>
<p>If mutex is busy</p>
<pre><code>Sleep

↓

Scheduler switches CPU

↓

Wake later
</code></pre>
<p>This is called a <strong>sleeping lock</strong>.</p>
<hr />
<h1>mutex_unlock()</h1>
<pre><code class="language-c">mutex_unlock(&amp;drvctx.mymtx);
</code></pre>
<p>Releases ownership.</p>
<p>If another thread is waiting</p>
<pre><code>Wake waiting thread

↓

Scheduler

↓

Acquire mutex
</code></pre>
<hr />
<h1>mutex_lock_interruptible()</h1>
<pre><code class="language-c">ret = mutex_lock_interruptible(&amp;drvctx.mymtx);
</code></pre>
<p>Unlike</p>
<pre><code class="language-c">mutex_lock()
</code></pre>
<p>this version may return early if interrupted.</p>
<p>Return value</p>
<pre><code>0

↓

Lock acquired
</code></pre>
<p>Non-zero</p>
<pre><code>Interrupted while waiting
</code></pre>
<p>Program</p>
<pre><code class="language-c">if (ret)
{
    printk(...);
    continue;
}
</code></pre>
<hr />
<h1>Thread Competition</h1>
<pre><code>Time

T1 -------------------- LOCK ------------------- UNLOCK

                    T2 waiting

                              LOCK

                              UNLOCK

T1 waiting

LOCK

UNLOCK
</code></pre>
<p>Only one thread executes inside the critical section.</p>
<hr />
<h1>Expected Timeline</h1>
<p>Counter</p>
<pre><code>0
</code></pre>
<p>Thread 1</p>
<pre><code>Acquire Mutex

Counter=0

Increment

Counter=1

Sleep

Unlock
</code></pre>
<p>Thread 2</p>
<pre><code>Waiting...

Acquire

Counter=1

Increment

Counter=2

Unlock
</code></pre>
<p>Thread 1</p>
<pre><code>Acquire

Counter=2

Increment

Counter=3
</code></pre>
<p>and so on.</p>
<hr />
<h1>Expected Kernel Log</h1>
<pre><code>Mutex Demo: Module Loaded

Mutex initialized

T1: waiting for mutex

T1: acquired mutex, counter=0

T2: waiting for mutex (interruptible)

T1: releasing mutex, counter=1

T2: acquired mutex, counter=1

T2: releasing mutex, counter=2

T1: acquired mutex, counter=2

T1: releasing mutex, counter=3

...
</code></pre>
<p>Observe</p>
<ul>
<li>No overlapping critical sections</li>
<li>Counter always increases correctly</li>
<li>Mutex serializes access</li>
</ul>
<hr />
<h1>Module Cleanup</h1>
<pre><code>rmmod

↓

module_exit()

↓

kthread_stop(T1)

↓

kthread_stop(T2)

↓

mutex_destroy()

↓

Exit
</code></pre>
<hr />
<h1>mutex_destroy()</h1>
<pre><code class="language-c">mutex_destroy(&amp;drvctx.mymtx);
</code></pre>
<p>Normally performs little work.</p>
<p>Useful when</p>
<pre><code>CONFIG_DEBUG_MUTEXES=y
</code></pre>
<p>Kernel debug builds perform additional consistency checks.</p>
<hr />
<h1>Important Kernel APIs</h1>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>module_init()</code></td>
<td>Module entry point</td>
</tr>
<tr>
<td><code>module_exit()</code></td>
<td>Module exit point</td>
</tr>
<tr>
<td><code>kthread_run()</code></td>
<td>Create kernel thread</td>
</tr>
<tr>
<td><code>kthread_stop()</code></td>
<td>Stop kernel thread</td>
</tr>
<tr>
<td><code>kthread_should_stop()</code></td>
<td>Thread termination check</td>
</tr>
<tr>
<td><code>mutex_init()</code></td>
<td>Initialize mutex</td>
</tr>
<tr>
<td><code>mutex_lock()</code></td>
<td>Acquire mutex</td>
</tr>
<tr>
<td><code>mutex_unlock()</code></td>
<td>Release mutex</td>
</tr>
<tr>
<td><code>mutex_lock_interruptible()</code></td>
<td>Interruptible acquire</td>
</tr>
<tr>
<td><code>mutex_destroy()</code></td>
<td>Destroy mutex</td>
</tr>
<tr>
<td><code>printk()</code></td>
<td>Kernel logging</td>
</tr>
<tr>
<td><code>msleep()</code></td>
<td>Sleep current thread</td>
</tr>
</tbody></table>
<hr />
<h1>Why Use Mutex?</h1>
<p>Advantages</p>
<ul>
<li>Simple API</li>
<li>Prevents race conditions</li>
<li>Sleeping lock</li>
<li>Scheduler friendly</li>
<li>No busy waiting</li>
<li>Excellent for long critical sections</li>
</ul>
<p>Ideal for</p>
<ul>
<li>Device Drivers</li>
<li>Filesystems</li>
<li>Networking</li>
<li>USB</li>
<li>Character Drivers</li>
</ul>
<hr />
<h1>Mutex vs Spinlock</h1>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Mutex</th>
<th>Spinlock</th>
</tr>
</thead>
<tbody><tr>
<td>Sleeps</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Busy Wait</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Scheduler Friendly</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Long Critical Sections</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Interrupt Context</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Process Context</td>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody></table>
<hr />
<h1>Real Driver Examples</h1>
<p>Mutexes commonly protect</p>
<pre><code>Device Registers

Configuration Structures

Driver State

Shared Buffers

Reference Counters

Linked Lists

Open File State

Device Queues
</code></pre>
<hr />
<h1>Key Takeaways</h1>
<p>This project demonstrates</p>
<ul>
<li>Linux Kernel Module lifecycle</li>
<li>Driver private context</li>
<li>Shared resource protection</li>
<li>Mutex initialization</li>
<li>Mutex acquisition</li>
<li>Mutex release</li>
<li>Interruptible mutex locking</li>
<li>Kernel thread creation</li>
<li>Thread synchronization</li>
<li>Scheduler interaction</li>
<li>Critical section protection</li>
<li>Race condition avoidance</li>
<li>Safe module cleanup</li>
</ul>
<p>Although intentionally simple, the synchronization pattern used here is the same pattern employed throughout production Linux kernel drivers.</p>
<hr />
<h2>Summary</h2>
<p>This Linux Kernel Module serves as a compact yet practical introduction to <strong>sleeping synchronization</strong> in the Linux kernel. By creating two competing kernel threads that protect a shared resource with a mutex, it demonstrates the complete lifecycle of mutex usage—from initialization and acquisition to release and cleanup—while reinforcing essential concepts such as race conditions, critical sections, scheduler interaction, and proper kernel module design. It provides a solid foundation before progressing to more advanced synchronization primitives such as spinlocks, semaphores, completions, wait queues, reader-writer locks, and Read-Copy-Update (RCU).</p>
<p>GitHub Repository: 👉 <strong><a href="https://github.com/aj333git/linux_kernel_mutex">linux_kernel_mutex</a></strong> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Mutex vs Spinlock]]></title><description><![CDATA[Introduction
Concurrency is everywhere inside the Linux kernel. Multiple threads, processes, softirqs, tasklets, and interrupt handlers can access the same shared data simultaneously.
Without synchron]]></description><link>https://devnation.joshisfitness.com/mutex-vs-spinlock</link><guid isPermaLink="true">https://devnation.joshisfitness.com/mutex-vs-spinlock</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Thu, 25 Jun 2026 06:15:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/8edd099d-4b13-47ed-bada-defd9c0cb54e.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1>
<p>Concurrency is everywhere inside the Linux kernel. Multiple threads, processes, softirqs, tasklets, and interrupt handlers can access the same shared data simultaneously.</p>
<p>Without synchronization, this leads to:</p>
<ul>
<li><p>Race conditions</p>
</li>
<li><p>Data corruption</p>
</li>
<li><p>Unpredictable behavior</p>
</li>
<li><p>Difficult-to-debug kernel crashes</p>
</li>
</ul>
<p>Two of the most common synchronization primitives used by kernel developers are:</p>
<ul>
<li><p><strong>Mutex</strong></p>
</li>
<li><p><strong>Spinlock</strong></p>
</li>
</ul>
<p>Although both protect critical sections, they work very differently internally and are designed for different situations.</p>
<hr />
<h1>The Locking Problem</h1>
<p>Imagine three kernel threads attempting to update the same shared counter:</p>
<pre><code class="language-c">shared_counter++;
</code></pre>
<p>If all threads execute this simultaneously, the result becomes unpredictable.</p>
<p>To avoid this, we protect the critical section:</p>
<pre><code class="language-c">lock();

shared_counter++;

unlock();
</code></pre>
<p>Only one thread can enter the protected region at a time.</p>
<p>The important question is:</p>
<blockquote>
<p>What happens to the threads that fail to acquire the lock?</p>
</blockquote>
<p>The answer depends on whether we're using a <strong>mutex</strong> or a <strong>spinlock</strong>.</p>
<hr />
<h1>How a Mutex Works</h1>
<p>A mutex allows only one owner.</p>
<p>When a thread attempts to acquire a locked mutex:</p>
<ol>
<li><p>It cannot proceed.</p>
</li>
<li><p>It is put to sleep.</p>
</li>
<li><p>The scheduler removes it from the CPU.</p>
</li>
<li><p>It waits until the mutex becomes available.</p>
</li>
</ol>
<p>Example:</p>
<pre><code class="language-c">mutex_lock(&amp;my_mutex);

/* critical section */

mutex_unlock(&amp;my_mutex);
</code></pre>
<h2>Characteristics</h2>
<ul>
<li><p>Blocking lock</p>
</li>
<li><p>Sleeping is allowed</p>
</li>
<li><p>Context switch occurs</p>
</li>
<li><p>Suitable for long critical sections</p>
</li>
</ul>
<hr />
<h1>How a Spinlock Works</h1>
<p>A spinlock behaves differently.</p>
<p>If a thread cannot acquire the lock:</p>
<ul>
<li><p>It does <strong>not sleep</strong></p>
</li>
<li><p>It repeatedly checks whether the lock is available</p>
</li>
<li><p>It continuously waits ("spins")</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="language-c">spin_lock(&amp;my_lock);

/* critical section */

spin_unlock(&amp;my_lock);
</code></pre>
<p>Conceptually:</p>
<pre><code class="language-c">while (lock_is_busy)
    ;
</code></pre>
<p>Real Linux implementations are much more optimized than this simple representation.</p>
<hr />
<h1>Why Spinning Can Be Faster</h1>
<p>Putting a thread to sleep is expensive.</p>
<p>The kernel must:</p>
<ol>
<li><p>Invoke the scheduler</p>
</li>
<li><p>Save thread state</p>
</li>
<li><p>Perform a context switch</p>
</li>
<li><p>Wake the thread later</p>
</li>
<li><p>Perform another context switch</p>
</li>
</ol>
<p>A mutex therefore incurs at least:</p>
<pre><code class="language-text">Sleep Context Switch
+
Wakeup Context Switch
</code></pre>
<p>For very short critical sections, this overhead can exceed the actual work being protected.</p>
<hr />
<h1>The Performance Rule</h1>
<p>Let:</p>
<ul>
<li><p><code>t_locked</code> = time spent in critical section</p>
</li>
<li><p><code>t_ctxsw</code> = context switch time</p>
</li>
</ul>
<p>If:</p>
<pre><code class="language-text">t_locked &lt; 2 × t_ctxsw
</code></pre>
<p>then using a mutex becomes inefficient.</p>
<p>The system spends more time managing threads than performing useful work.</p>
<p>This phenomenon is known as <strong>thrashing</strong>.</p>
<p>In such cases, a spinlock is often the better choice.</p>
<hr />
<h1>Mutex vs Spinlock Comparison</h1>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Mutex</th>
<th>Spinlock</th>
</tr>
</thead>
<tbody><tr>
<td>Waiting strategy</td>
<td>Sleep</td>
<td>Spin</td>
</tr>
<tr>
<td>Context switch</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Can block</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Can sleep inside critical section</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Interrupt-safe</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Overhead</td>
<td>Higher</td>
<td>Lower</td>
</tr>
<tr>
<td>Best for</td>
<td>Long critical sections</td>
<td>Short critical sections</td>
</tr>
</tbody></table>
<hr />
<h1>Atomic Context Changes Everything</h1>
<p>The Linux kernel has a very important rule:</p>
<blockquote>
<p>Code running in atomic context cannot sleep.</p>
</blockquote>
<p>Examples include:</p>
<ul>
<li><p>Interrupt handlers</p>
</li>
<li><p>Softirqs</p>
</li>
<li><p>Tasklets</p>
</li>
<li><p>Other atomic execution paths</p>
</li>
</ul>
<p>Since mutexes sleep internally, they cannot be used here.</p>
<p>Incorrect:</p>
<pre><code class="language-c">irq_handler()
{
    mutex_lock(&amp;lock);   /* WRONG */
}
</code></pre>
<p>Correct:</p>
<pre><code class="language-c">irq_handler()
{
    spin_lock(&amp;lock);

    /* critical section */

    spin_unlock(&amp;lock);
}
</code></pre>
<hr />
<h1>Sleeping Inside a Spinlock Is Forbidden</h1>
<p>This is a common beginner mistake.</p>
<p>Never do:</p>
<pre><code class="language-c">spin_lock(&amp;lock);

msleep(100);

spin_unlock(&amp;lock);
</code></pre>
<p>Or:</p>
<pre><code class="language-c">spin_lock(&amp;lock);

wait_event(...);

spin_unlock(&amp;lock);
</code></pre>
<p>A spinlock assumes the holder will release it quickly.</p>
<p>Sleeping while holding a spinlock can freeze the system or trigger kernel warnings.</p>
<hr />
<h1>Practical Decision Guide</h1>
<h2>Use a Spinlock When</h2>
<ul>
<li><p>Running in interrupt context</p>
</li>
<li><p>Running in atomic context</p>
</li>
<li><p>Critical section is extremely short</p>
</li>
<li><p>Sleeping is not allowed</p>
</li>
<li><p>Maximum performance is required</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="language-c">spin_lock(&amp;lock);
counter++;
spin_unlock(&amp;lock);
</code></pre>
<hr />
<h2>Use a Mutex When</h2>
<ul>
<li><p>Running in process context</p>
</li>
<li><p>Blocking I/O may occur</p>
</li>
<li><p>Sleeping may occur</p>
</li>
<li><p>Critical section is relatively long</p>
</li>
</ul>
<p>Example:</p>
<pre><code class="language-c">mutex_lock(&amp;lock);

copy_to_user(...);

mutex_unlock(&amp;lock);
</code></pre>
<hr />
<h1>Determining the Current Context</h1>
<p>Linux provides helpers to determine where code is executing.</p>
<p>Example:</p>
<pre><code class="language-c">if (in_task())
{
    /* process context */
}
else
{
    /* atomic or interrupt context */
}
</code></pre>
<p>General rule:</p>
<ul>
<li><p>Process context → mutex or spinlock</p>
</li>
<li><p>Interrupt/atomic context → spinlock only</p>
</li>
</ul>
<hr />
<h1>Mental Model</h1>
<p>Think of the locks this way:</p>
<h3>Mutex</h3>
<blockquote>
<p>"I can't get the lock. I'll sleep until someone wakes me."</p>
</blockquote>
<h3>Spinlock</h3>
<blockquote>
<p>"I can't get the lock. I'll keep checking until it becomes available."</p>
</blockquote>
<p>That single difference determines almost every practical use case.</p>
<hr />
<h1>Key Takeaways</h1>
<ul>
<li><p>Both mutexes and spinlocks protect critical sections.</p>
</li>
<li><p>Mutex losers sleep and later wake up.</p>
</li>
<li><p>Spinlock losers remain active and wait.</p>
</li>
<li><p>Mutexes have higher overhead because of context switching.</p>
</li>
<li><p>Spinlocks are ideal for short, non-blocking operations.</p>
</li>
<li><p>Mutexes are ideal for longer operations that may sleep.</p>
</li>
<li><p>Never use a mutex in interrupt or atomic context.</p>
</li>
<li><p>Never sleep while holding a spinlock.</p>
</li>
</ul>
<p>Choosing the correct lock is one of the most important design decisions in Linux kernel development. Understanding when threads sleep and when they spin is the foundation of writing safe kernel code.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Worker Pool in F# with MailboxProcessor]]></title><description><![CDATA[Introduction
While studying concurrent network programming, I explored how to implement a worker pool in F# using MailboxProcessor, F#'s built-in actor abstraction.
The example launches multiple worke]]></description><link>https://devnation.joshisfitness.com/building-a-worker-pool-in-f-with-mailboxprocessor</link><guid isPermaLink="true">https://devnation.joshisfitness.com/building-a-worker-pool-in-f-with-mailboxprocessor</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Wed, 24 Jun 2026 09:36:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/be8c60b5-421f-431e-9092-2b2e95e68a66.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>While studying concurrent network programming, I explored how to implement a worker pool in F# using <code>MailboxProcessor</code>, F#'s built-in actor abstraction.</p>
<p>The example launches multiple workers that process port numbers concurrently. A <code>CountdownEvent</code> is used to wait until all work items have been completed before shutting down the workers gracefully.</p>
<p>This approach is conceptually similar to Go's goroutines and channels but follows a more actor-oriented design.</p>
<hr />
<h2>Core Components</h2>
<p>The implementation consists of three main pieces:</p>
<table>
<thead>
<tr>
<th>Component</th>
<th>Responsibility</th>
</tr>
</thead>
<tbody><tr>
<td>MailboxProcessor</td>
<td>Worker actor</td>
</tr>
<tr>
<td>Message Type</td>
<td>Communication protocol</td>
</tr>
<tr>
<td>CountdownEvent</td>
<td>Completion tracking</td>
</tr>
</tbody></table>
<hr />
<h2>Defining Messages</h2>
<p>Workers communicate through strongly typed messages.</p>
<pre><code class="language-fsharp">type Message =
    | Port of int
    | Stop
</code></pre>
<p>This provides a clear protocol:</p>
<ul>
<li><p><code>Port</code> → process a port number</p>
</li>
<li><p><code>Stop</code> → terminate the worker</p>
</li>
</ul>
<p>Unlike string-based messaging, the compiler verifies message correctness.</p>
<hr />
<h2>Creating a Worker</h2>
<p>Each worker runs as an independent actor.</p>
<pre><code class="language-fsharp">let worker (id: int) =
    MailboxProcessor.Start(fun inbox -&gt;
        let rec loop () = async {
            let! msg = inbox.Receive()

            match msg with
            | Port p -&gt;
                printfn "Worker %d processed port %d" id p
                return! loop ()

            | Stop -&gt;
                ()
        }
        loop ()
    )
</code></pre>
<p>Important characteristics:</p>
<ul>
<li><p>Sequential message processing</p>
</li>
<li><p>No explicit locking</p>
</li>
<li><p>Independent execution context</p>
</li>
<li><p>Message-driven behavior</p>
</li>
</ul>
<hr />
<h2>Tracking Completion</h2>
<p>To emulate Go's <code>WaitGroup</code>, the example uses <code>CountdownEvent</code>.</p>
<pre><code class="language-fsharp">let completed = CountdownEvent(1024)
</code></pre>
<p>Each processed port decrements the counter.</p>
<pre><code class="language-fsharp">completed.Signal() |&gt; ignore
</code></pre>
<p>The main thread blocks until all tasks are finished.</p>
<pre><code class="language-fsharp">completed.Wait()
</code></pre>
<hr />
<h2>Creating the Worker Pool</h2>
<p>A pool of 100 workers is created.</p>
<pre><code class="language-fsharp">let workers =
    [|
        for i in 1 .. 100 -&gt;
            worker i
    |]
</code></pre>
<p>Each worker owns its mailbox and processes incoming messages independently.</p>
<hr />
<h2>Dispatching Work</h2>
<p>Port numbers are distributed across workers.</p>
<pre><code class="language-fsharp">for port in 1 .. 1024 do
    let index = port % 100
    workers.[index].Post(Port port)
</code></pre>
<p>This creates a simple round-robin scheduling strategy.</p>
<hr />
<h2>Graceful Shutdown</h2>
<p>After all work has completed, a termination message is sent.</p>
<pre><code class="language-fsharp">for w in workers do
    w.Post(Stop)
</code></pre>
<p>This avoids abruptly terminating active workers.</p>
<hr />
<h2>Go vs F# Concurrency</h2>
<p>The design maps naturally to concepts familiar to Go developers.</p>
<table>
<thead>
<tr>
<th>Go</th>
<th>F#</th>
</tr>
</thead>
<tbody><tr>
<td>Goroutine</td>
<td>MailboxProcessor</td>
</tr>
<tr>
<td>Channel</td>
<td>Mailbox</td>
</tr>
<tr>
<td>WaitGroup</td>
<td>CountdownEvent</td>
</tr>
<tr>
<td>Send Message</td>
<td>Post</td>
</tr>
<tr>
<td>Close Channel</td>
<td>Stop Message</td>
</tr>
</tbody></table>
<p>Although the implementation style differs, both approaches rely on message passing rather than shared-state synchronization.</p>
<hr />
<h2>Why MailboxProcessor?</h2>
<p><code>MailboxProcessor</code> offers several advantages:</p>
<ul>
<li><p>Actor-style concurrency</p>
</li>
<li><p>Strongly typed messages</p>
</li>
<li><p>No manual lock management</p>
</li>
<li><p>Clear separation of worker responsibilities</p>
</li>
<li><p>Scales well for network and backend services</p>
</li>
</ul>
<p>This makes it a useful building block for:</p>
<ul>
<li><p>Port scanners</p>
</li>
<li><p>TCP servers</p>
</li>
<li><p>Telemetry systems</p>
</li>
<li><p>Chat applications</p>
</li>
<li><p>Distributed services</p>
</li>
<li><p>IoT backends</p>
</li>
</ul>
<hr />
<h2>Conclusion</h2>
<p>F#'s <code>MailboxProcessor</code> provides a concise and powerful way to implement concurrent worker pools. By combining actors with typed messages and synchronization primitives such as <code>CountdownEvent</code>, I can build systems that are both scalable and easier to reason about than traditional shared-memory approaches.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Linux Kernel Mutex Synchronization with Kernel Threads]]></title><description><![CDATA[Introduction
Concurrency is everywhere inside the Linux kernel. Multiple execution contexts may attempt to access the same data simultaneously, leading to race conditions and corrupted state.
In this ]]></description><link>https://devnation.joshisfitness.com/understanding-linux-kernel-mutex-synchronization-with-kernel-threads</link><guid isPermaLink="true">https://devnation.joshisfitness.com/understanding-linux-kernel-mutex-synchronization-with-kernel-threads</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[coding]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Wed, 24 Jun 2026 09:01:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/8fb17613-86e5-4504-a516-22c73705fab8.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1>
<p>Concurrency is everywhere inside the Linux kernel. Multiple execution contexts may attempt to access the same data simultaneously, leading to race conditions and corrupted state.</p>
<p>In this article, I build a simple kernel module that launches two kernel threads and protects a shared global counter using a mutex. Along the way, I explore:</p>
<ul>
<li><p>Kernel threads</p>
</li>
<li><p>Shared resources</p>
</li>
<li><p>Critical sections</p>
</li>
<li><p>Race conditions</p>
</li>
<li><p>Mutex synchronization</p>
</li>
<li><p><code>mutex_lock_interruptible()</code></p>
</li>
<li><p>Thread lifecycle management</p>
</li>
</ul>
<hr />
<h1>The Problem: Shared Data</h1>
<p>Consider a global variable shared by multiple kernel threads:</p>
<pre><code class="language-c">static int shared_resource = 0;
</code></pre>
<p>Both threads increment this variable repeatedly.</p>
<pre><code class="language-c">shared_resource++;
</code></pre>
<p>At first glance this looks harmless, but the operation is actually composed of multiple CPU instructions:</p>
<ol>
<li><p>Read value</p>
</li>
<li><p>Increment value</p>
</li>
<li><p>Write value back</p>
</li>
</ol>
<p>If two threads perform these steps simultaneously, updates can be lost.</p>
<hr />
<h1>Understanding Race Conditions</h1>
<p>Without synchronization:</p>
<pre><code class="language-text">Thread-1 reads 5
Thread-2 reads 5

Thread-1 writes 6
Thread-2 writes 6
</code></pre>
<p>Expected result:</p>
<pre><code class="language-text">5 → 6 → 7
</code></pre>
<p>Actual result:</p>
<pre><code class="language-text">5 → 6
</code></pre>
<p>One increment disappears.</p>
<p>This is known as a <strong>race condition</strong>.</p>
<hr />
<h1>Enter the Mutex</h1>
<p>Linux provides mutexes to guarantee mutual exclusion.</p>
<p>The module defines a mutex as:</p>
<pre><code class="language-c">static DEFINE_MUTEX(my_shared_mutex);
</code></pre>
<p>A mutex ensures that only one thread can enter a critical section at a time.</p>
<hr />
<h1>Critical Section Protection</h1>
<p>The shared counter update is wrapped by the mutex:</p>
<pre><code class="language-c">if (mutex_lock_interruptible(&amp;my_shared_mutex))
    return -EINTR;

shared_resource++;

mutex_unlock(&amp;my_shared_mutex);
</code></pre>
<p>This guarantees that concurrent updates occur safely.</p>
<hr />
<h1>Why Use mutex_lock_interruptible()</h1>
<p>Linux provides two common mutex acquisition APIs:</p>
<table>
<thead>
<tr>
<th>API</th>
<th>Interruptible</th>
<th>Behavior</th>
</tr>
</thead>
<tbody><tr>
<td><code>mutex_lock()</code></td>
<td>No</td>
<td>Waits indefinitely</td>
</tr>
<tr>
<td><code>mutex_lock_interruptible()</code></td>
<td>Yes</td>
<td>Can be interrupted by signals</td>
</tr>
</tbody></table>
<p>Example:</p>
<pre><code class="language-c">mutex_lock_interruptible(&amp;my_shared_mutex);
</code></pre>
<p>Unlike <code>mutex_lock()</code>, the interruptible version can abort waiting and return an error if a signal arrives.</p>
<hr />
<h1>Return Values</h1>
<p>A successful lock acquisition returns:</p>
<pre><code class="language-c">0
</code></pre>
<p>If interrupted before obtaining the lock:</p>
<pre><code class="language-c">-EINTR
</code></pre>
<p>This allows the thread to exit gracefully rather than waiting forever.</p>
<hr />
<h1>Creating Kernel Threads</h1>
<p>The module launches two kernel threads.</p>
<pre><code class="language-c">thread1 = kthread_run(
    my_kthread_func,
    "Thread-1",
    "kthread_one");
</code></pre>
<pre><code class="language-c">thread2 = kthread_run(
    my_kthread_func,
    "Thread-2",
    "kthread_two");
</code></pre>
<p>Each thread repeatedly:</p>
<ul>
<li><p>Acquires the mutex</p>
</li>
<li><p>Updates the counter</p>
</li>
<li><p>Releases the mutex</p>
</li>
<li><p>Sleeps briefly</p>
</li>
<li><p>Repeats</p>
</li>
</ul>
<hr />
<h1>Why task_struct Matters</h1>
<p>Thread handles are stored as:</p>
<pre><code class="language-c">static struct task_struct *thread1;
static struct task_struct *thread2;
</code></pre>
<p>Every Linux task is represented internally by a <code>task_struct</code>.</p>
<p>These handles allow the module to:</p>
<ul>
<li><p>Stop threads</p>
</li>
<li><p>Manage thread lifecycle</p>
</li>
<li><p>Track execution state</p>
</li>
</ul>
<hr />
<h1>Graceful Thread Shutdown</h1>
<p>The worker loop uses:</p>
<pre><code class="language-c">while (!kthread_should_stop())
</code></pre>
<p>When the module unloads:</p>
<pre><code class="language-c">kthread_stop(thread1);
kthread_stop(thread2);
</code></pre>
<p>The threads detect the stop request and exit cleanly.</p>
<p>This is the recommended Linux kernel thread shutdown pattern.</p>
<hr />
<h1>Sleeping Locks</h1>
<p>Mutexes are sleeping locks.</p>
<p>This means they may block and schedule another task while waiting.</p>
<p>Because of this, mutexes are appropriate in:</p>
<ul>
<li><p>Kernel threads</p>
</li>
<li><p>Process context</p>
</li>
<li><p>System call paths</p>
</li>
</ul>
<p>They are <strong>not</strong> suitable for:</p>
<ul>
<li><p>Interrupt handlers</p>
</li>
<li><p>SoftIRQs</p>
</li>
<li><p>Atomic contexts</p>
</li>
</ul>
<p>Sleeping is forbidden in those environments.</p>
<hr />
<h1>Mutex Ownership Rules</h1>
<p>A mutex has strict ownership semantics.</p>
<p>Correct:</p>
<pre><code class="language-c">mutex_lock(&amp;lock);

/* critical section */

mutex_unlock(&amp;lock);
</code></pre>
<p>The same thread that acquires the lock must release it.</p>
<p>Violating this rule can trigger kernel warnings and undefined behavior.</p>
<hr />
<h1>Expected Kernel Output</h1>
<p>After loading the module:</p>
<pre><code class="language-text">Initializing Mutex Kthread Module

Thread-1: Secured lock. Shared Resource value = 1

Thread-2: Secured lock. Shared Resource value = 2

Thread-1: Secured lock. Shared Resource value = 3
</code></pre>
<p>The counter increases sequentially because only one thread owns the mutex at any given moment.</p>
<h1>Key Takeaways</h1>
<ul>
<li><p>Shared kernel data requires synchronization.</p>
</li>
<li><p>Race conditions occur when multiple threads modify data concurrently.</p>
</li>
<li><p>Mutexes provide mutual exclusion.</p>
</li>
<li><p><code>mutex_lock_interruptible()</code> allows signal-aware waiting.</p>
</li>
<li><p>Mutexes are sleeping locks and should not be used in interrupt context.</p>
</li>
<li><p>Kernel threads are managed using <code>task_struct</code>.</p>
</li>
<li><p><code>kthread_stop()</code> enables clean thread termination.</p>
</li>
</ul>
<p>Understanding mutexes is one of the foundational steps toward mastering Linux kernel synchronization and building reliable concurrent kernel code.</p>
<p>GitHub Repository: 👉 <a href="https://github.com/aj333git/linux_kernel_mutex2"><strong>linux_kernel_mutex</strong></a> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Concurrent Port Scanning in F# with Tasks]]></title><description><![CDATA[Introduction
Scanning one TCP port at a time is simple, but it is inefficient. Network operations spend most of their time waiting for remote hosts to respond. Instead of scanning ports sequentially, ]]></description><link>https://devnation.joshisfitness.com/concurrent-port-scanning-in-f-with-tasks</link><guid isPermaLink="true">https://devnation.joshisfitness.com/concurrent-port-scanning-in-f-with-tasks</guid><category><![CDATA[Hashnode]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[dotnet]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Mon, 22 Jun 2026 09:07:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/1a98a0b3-4495-4d2c-95f4-7403817b683b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Scanning one TCP port at a time is simple, but it is inefficient. Network operations spend most of their time waiting for remote hosts to respond. Instead of scanning ports sequentially, we can launch multiple connection attempts concurrently and significantly reduce the total scan time.</p>
<p>In .NET, the Task Parallel Library (TPL) provides a lightweight mechanism for running large numbers of asynchronous operations without creating hundreds or thousands of operating system threads.</p>
<hr />
<h2>Why Concurrent Scanning?</h2>
<p>A sequential scanner performs the following workflow:</p>
<pre><code class="language-text">Scan Port 1
Wait
Scan Port 2
Wait
Scan Port 3
Wait
...
</code></pre>
<p>This approach wastes time because the CPU sits idle while waiting for network responses.</p>
<p>A concurrent scanner launches many connection attempts simultaneously:</p>
<pre><code class="language-text">Port 1  ─┐
Port 2  ─┼─&gt; Running Together
Port 3  ─┤
...
Port N  ─┘
</code></pre>
<p>The result is a much faster scan.</p>
<hr />
<h2>The F# Scanner</h2>
<pre><code class="language-fsharp">let scanPort port =
    task {
        try
            use client = new TcpClient()

            do! client.ConnectAsync("scanme.nmap.org", port)

            printfn "%d open" port
        with
        | _ -&gt; ()
    }
</code></pre>
<h3>What Happens Here?</h3>
<table>
<thead>
<tr>
<th>Statement</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>task {}</code></td>
<td>Creates an asynchronous Task</td>
</tr>
<tr>
<td><code>TcpClient()</code></td>
<td>Creates a TCP client</td>
</tr>
<tr>
<td><code>ConnectAsync()</code></td>
<td>Attempts a non-blocking connection</td>
</tr>
<tr>
<td><code>printfn</code></td>
<td>Displays open ports</td>
</tr>
<tr>
<td><code>try/with</code></td>
<td>Ignores failed connections</td>
</tr>
</tbody></table>
<p>If the connection succeeds, the port is considered open.</p>
<hr />
<h2>Launching 1024 Concurrent Scans</h2>
<pre><code class="language-fsharp">[1 .. 1024]
|&gt; List.map scanPort
|&gt; Task.WhenAll
|&gt; fun t -&gt; t.Wait()
</code></pre>
<p>This compact pipeline performs three important operations.</p>
<h3>1. Generate Port Numbers</h3>
<pre><code class="language-fsharp">[1 .. 1024]
</code></pre>
<p>Creates a list of ports from 1 through 1024.</p>
<h3>2. Create Scan Tasks</h3>
<pre><code class="language-fsharp">List.map scanPort
</code></pre>
<p>Transforms:</p>
<pre><code class="language-text">[1;2;3;...;1024]
</code></pre>
<p>into:</p>
<pre><code class="language-text">[Task1;Task2;Task3;...;Task1024]
</code></pre>
<p>Each task represents one asynchronous connection attempt.</p>
<h3>3. Wait for Completion</h3>
<pre><code class="language-fsharp">Task.WhenAll
</code></pre>
<p>Combines all scan tasks into a single master task.</p>
<pre><code class="language-fsharp">fun t -&gt; t.Wait()
</code></pre>
<p>Blocks until every scan operation finishes.</p>
<hr />
<h2>Execution Flow</h2>
<pre><code class="language-text">Ports List
     |
     v
Create Scan Tasks
     |
     v
Task1 Task2 Task3 ... Task1024
     |
     v
Task.WhenAll
     |
     v
Single Master Task
     |
     v
Wait()
</code></pre>
<hr />
<h2>Why Tasks Instead of Threads?</h2>
<p>Creating 1024 operating system threads would be expensive.</p>
<p>Tasks provide:</p>
<ul>
<li>Lower memory consumption</li>
<li>Better scalability</li>
<li>Efficient I/O scheduling</li>
<li>Simpler concurrency management</li>
<li>Integration with async network APIs</li>
</ul>
<p>For network-heavy workloads such as port scanners, Tasks are typically the preferred solution in modern .NET applications.</p>
<hr />
<h2>Final Thoughts</h2>
<p>Concurrent scanning demonstrates a fundamental principle of network programming: <strong>don't wait on one connection when you can wait on many simultaneously</strong>.</p>
<p>Using <code>TcpClient.ConnectAsync()</code> together with <code>Task.WhenAll()</code> allows F# developers to build scalable network tools with surprisingly little code while taking advantage of the .NET runtime's efficient asynchronous I/O infrastructure.</p>
<hr />
]]></content:encoded></item><item><title><![CDATA[ Understanding Mutexes, Concurrency, and Character Device Drivers in Linux Kernel Modules]]></title><description><![CDATA[Introduction
Synchronization bugs are among the most difficult issues to debug in kernel-space software. A simple character device driver can become unsafe when multiple processes access shared resour]]></description><link>https://devnation.joshisfitness.com/understanding-mutexes-concurrency-and-character-device-drivers-in-linux-kernel-modules</link><guid isPermaLink="true">https://devnation.joshisfitness.com/understanding-mutexes-concurrency-and-character-device-drivers-in-linux-kernel-modules</guid><category><![CDATA[coding]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Linux]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Mon, 22 Jun 2026 08:19:05 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/113c147d-0fac-4743-9186-99a024caf5c6.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1>
<p>Synchronization bugs are among the most difficult issues to debug in kernel-space software. A simple character device driver can become unsafe when multiple processes access shared resources concurrently.</p>
<p>In this article, I build and analyze a Linux character device driver that demonstrates four important kernel concepts:</p>
<ul>
<li><p>Mutex synchronization</p>
</li>
<li><p>Concurrency control</p>
</li>
<li><p>Character device drivers</p>
</li>
<li><p>Linux version compatibility</p>
</li>
</ul>
<p>The driver creates a device node named:</p>
<pre><code class="language-text">/dev/mydevice
</code></pre>
<p>and returns a simple message to userspace when read.</p>
<hr />
<h1>Concept 1: Mutex Synchronization</h1>
<p>A mutex ensures that only one execution context accesses a critical section at a time.</p>
<p>The driver declares a mutex using:</p>
<pre><code class="language-c">static DEFINE_MUTEX(dev_mutex);
</code></pre>
<p>Before accessing shared state, the driver acquires the lock:</p>
<pre><code class="language-c">if (mutex_lock_interruptible(&amp;dev_mutex))
    return -ERESTARTSYS;
</code></pre>
<p>and releases it when finished:</p>
<pre><code class="language-c">mutex_unlock(&amp;dev_mutex);
</code></pre>
<h2>Why Use a Mutex?</h2>
<p>Without synchronization, multiple processes could simultaneously execute the read handler and modify shared data.</p>
<p>Benefits of mutexes include:</p>
<ul>
<li><p>Preventing race conditions</p>
</li>
<li><p>Protecting shared kernel data</p>
</li>
<li><p>Simplifying synchronization logic</p>
</li>
<li><p>Allowing sleeping operations safely</p>
</li>
</ul>
<p>Unlike spinlocks, mutexes can safely surround operations such as:</p>
<pre><code class="language-c">copy_to_user(...)
</code></pre>
<p>which may sleep.</p>
<hr />
<h1>Concept 2: Concurrency in Device Drivers</h1>
<p>Concurrency occurs when multiple execution contexts attempt to access the same resource at the same time.</p>
<p>Consider several terminals executing:</p>
<pre><code class="language-bash">cat /dev/mydevice
</code></pre>
<p>simultaneously.</p>
<p>Without synchronization:</p>
<ul>
<li><p>Multiple threads may enter the read handler together</p>
</li>
<li><p>Shared state can become inconsistent</p>
</li>
<li><p>Race conditions become possible</p>
</li>
</ul>
<p>With mutex protection:</p>
<ul>
<li><p>Access becomes serialized</p>
</li>
<li><p>Shared state remains consistent</p>
</li>
<li><p>Device behavior becomes predictable</p>
</li>
</ul>
<p>Kernel developers must always assume that a driver may be accessed concurrently.</p>
<hr />
<h1>Concept 3: Character Device Drivers</h1>
<p>A character device transfers data as a stream of bytes between user space and kernel space.</p>
<p>Common examples include:</p>
<pre><code class="language-text">/dev/null
/dev/random
/dev/tty
</code></pre>
<p>Our module registers a character device using:</p>
<pre><code class="language-c">major_num = register_chrdev(
    0,
    "mydevice",
    &amp;fops
);
</code></pre>
<p>Passing zero requests a dynamically allocated major number.</p>
<hr />
<h2>File Operations Interface</h2>
<p>The kernel communicates with the driver through a file operations table:</p>
<pre><code class="language-c">static const struct file_operations fops = {
    .open    = dev_open,
    .read    = dev_read,
    .release = dev_release,
};
</code></pre>
<p>This maps standard system calls to driver callbacks.</p>
<table>
<thead>
<tr>
<th>User Action</th>
<th>Driver Function</th>
</tr>
</thead>
<tbody><tr>
<td>open()</td>
<td>dev_open()</td>
</tr>
<tr>
<td>read()</td>
<td>dev_read()</td>
</tr>
<tr>
<td>close()</td>
<td>dev_release()</td>
</tr>
</tbody></table>
<hr />
<h2>Safe User-Space Communication</h2>
<p>Kernel memory cannot be accessed directly from user space.</p>
<p>Instead, Linux provides helper APIs such as:</p>
<pre><code class="language-c">copy_to_user(buf, msg_data, len);
</code></pre>
<p>This function:</p>
<ul>
<li><p>Validates user-space addresses</p>
</li>
<li><p>Handles page faults safely</p>
</li>
<li><p>Prevents invalid memory access</p>
</li>
</ul>
<p>It is the standard mechanism for transferring data from kernel space to user space.</p>
<hr />
<h1>Read-Once Device Behavior</h1>
<p>The driver implements a simple read-once mechanism.</p>
<p>The key logic is:</p>
<pre><code class="language-c">if (*ppos &gt; 0)
    return 0;
</code></pre>
<p>After the first successful read:</p>
<ul>
<li><p>File position advances</p>
</li>
<li><p>Subsequent reads return EOF</p>
</li>
<li><p>Behavior mimics many virtual kernel files</p>
</li>
</ul>
<p>This pattern is commonly used in educational and demonstration drivers.</p>
<hr />
<h1>Concept 4: Linux Version Compatibility</h1>
<p>Kernel APIs evolve over time.</p>
<p>A driver that compiles on one kernel version may fail on another if APIs change.</p>
<p>To support multiple kernels, the module uses:</p>
<pre><code class="language-c">#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(6,4,0)
</code></pre>
<p>For newer kernels:</p>
<pre><code class="language-c">class_create("mydevice_class");
</code></pre>
<p>For older kernels:</p>
<pre><code class="language-c">class_create(
    THIS_MODULE,
    "mydevice_class"
);
</code></pre>
<p>This allows a single codebase to compile across multiple Linux releases.</p>
<hr />
<h1>Important Kernel APIs</h1>
<table>
<thead>
<tr>
<th>API</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td>register_chrdev()</td>
<td>Register character device</td>
</tr>
<tr>
<td>unregister_chrdev()</td>
<td>Remove character device</td>
</tr>
<tr>
<td>class_create()</td>
<td>Create device class</td>
</tr>
<tr>
<td>device_create()</td>
<td>Create device node</td>
</tr>
<tr>
<td>copy_to_user()</td>
<td>Transfer data to user space</td>
</tr>
<tr>
<td>DEFINE_MUTEX()</td>
<td>Declare mutex</td>
</tr>
<tr>
<td>mutex_lock_interruptible()</td>
<td>Acquire mutex</td>
</tr>
<tr>
<td>mutex_unlock()</td>
<td>Release mutex</td>
</tr>
</tbody></table>
<hr />
<h1>What This Project Demonstrates</h1>
<p>This small module covers several important kernel-development concepts:</p>
<ul>
<li><p>Character device registration</p>
</li>
<li><p>Dynamic device creation</p>
</li>
<li><p>User-space interaction</p>
</li>
<li><p>Mutex-based synchronization</p>
</li>
<li><p>Concurrency protection</p>
</li>
<li><p>Read-once semantics</p>
</li>
<li><p>Cross-version kernel compatibility</p>
</li>
</ul>
<p>Although simple, these concepts appear repeatedly in production Linux drivers.</p>
<hr />
<h1>Conclusion</h1>
<p>Character device drivers provide an excellent introduction to Linux kernel development. Even a small driver can expose important topics such as synchronization, concurrency, memory safety, and API compatibility.</p>
<p>By combining mutex protection with a clean character-device interface, this example demonstrates how Linux drivers safely interact with user-space applications while maintaining correctness under concurrent access.</p>
<hr />
<h2>Source Code</h2>
<p>GitHub Repository: 👉 <a href="https://github.com/aj333git/linux_kernel_con_c_1"><strong>linux_kernel_con_c_1</strong></a> Explore the complete source code, build files, and module implementation on GitHub.</p>
]]></content:encoded></item><item><title><![CDATA[Building a Simple Nonconcurrent TCP Port Scanner in F#]]></title><description><![CDATA[Building a Simple Nonconcurrent TCP Port Scanner in F#
Port scanning is one of the most fundamental techniques in networking and security. Before diving into high-performance concurrent scanners, it's]]></description><link>https://devnation.joshisfitness.com/building-a-simple-nonconcurrent-tcp-port-scanner-in-f</link><guid isPermaLink="true">https://devnation.joshisfitness.com/building-a-simple-nonconcurrent-tcp-port-scanner-in-f</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[coding]]></category><category><![CDATA[Hashnode]]></category><category><![CDATA[dotnet]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Sun, 21 Jun 2026 10:16:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/f3751fee-c19b-4a88-ab72-e65e72e0486a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Building a Simple Nonconcurrent TCP Port Scanner in F#</h1>
<p>Port scanning is one of the most fundamental techniques in networking and security. Before diving into high-performance concurrent scanners, it's useful to understand how a basic scanner works by checking <strong>one port at a time</strong>.</p>
<p>In this article, we'll build the foundation of a <strong>nonconcurrent TCP port scanner</strong> using F#.</p>
<hr />
<h2>What Is a Port Scanner?</h2>
<p>A port scanner attempts to connect to ports on a target system and determines whether those ports are:</p>
<table>
<thead>
<tr>
<th>State</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td>Open</td>
<td>A service is listening and accepts connections</td>
</tr>
<tr>
<td>Closed</td>
<td>No service is listening</td>
</tr>
<tr>
<td>Filtered</td>
<td>Traffic is blocked by a firewall or filtering device</td>
</tr>
</tbody></table>
<p>TCP ports range from:</p>
<pre><code class="language-text">1 - 65535
</code></pre>
<p>For demonstration purposes, we'll scan only:</p>
<pre><code class="language-text">1 - 1024
</code></pre>
<p>These are commonly known as the well-known ports.</p>
<hr />
<h2>Step 1: Generate Target Addresses</h2>
<p>Before attempting any network connections, we need a way to generate:</p>
<pre><code class="language-text">hostname:port
</code></pre>
<p>combinations.</p>
<p>In F#, a simple loop can accomplish this.</p>
<pre><code class="language-fsharp">open System

for i in 1 .. 1024 do
    let address = sprintf "scanme.nmap.org:%d" i
    printfn "%s" address
</code></pre>
<p>Example output:</p>
<pre><code class="language-text">scanme.nmap.org:1
scanme.nmap.org:2
scanme.nmap.org:3
...
scanme.nmap.org:1024
</code></pre>
<hr />
<h2>Understanding <code>sprintf</code></h2>
<p>The <code>sprintf</code> function formats strings similarly to C's <code>printf</code>.</p>
<pre><code class="language-fsharp">let address = sprintf "scanme.nmap.org:%d" i
</code></pre>
<p>Here:</p>
<table>
<thead>
<tr>
<th>Component</th>
<th>Purpose</th>
</tr>
</thead>
<tbody><tr>
<td><code>%d</code></td>
<td>Integer placeholder</td>
</tr>
<tr>
<td><code>i</code></td>
<td>Current port number</td>
</tr>
<tr>
<td><code>sprintf</code></td>
<td>Returns a formatted string</td>
</tr>
</tbody></table>
<p>For port <code>80</code>, the generated string becomes:</p>
<pre><code class="language-text">scanme.nmap.org:80
</code></pre>
<hr />
<h2>Step 2: Attempt a TCP Connection</h2>
<p>A TCP scanner determines whether a port is open by trying to establish a connection.</p>
<p>Conceptually:</p>
<pre><code class="language-text">Connect to target port
    |
    +-- Success -&gt; Open
    |
    +-- Error -&gt; Closed/Filtered
</code></pre>
<p>In .NET, this is typically done using:</p>
<pre><code class="language-fsharp">System.Net.Sockets.TcpClient
</code></pre>
<p>Minimal example:</p>
<pre><code class="language-fsharp">let client = new System.Net.Sockets.TcpClient()
</code></pre>
<p>If the connection succeeds, the port is likely open.</p>
<hr />
<h2>Step 3: Always Close Connections</h2>
<p>A successful connection consumes operating system resources.</p>
<p>Good network citizenship requires closing connections immediately after testing.</p>
<p>Conceptually:</p>
<pre><code class="language-fsharp">client.Close()
</code></pre>
<p>Benefits:</p>
<ul>
<li>Releases socket resources</li>
<li>Prevents connection leaks</li>
<li>Reduces system overhead</li>
<li>Mimics professional scanner behavior</li>
</ul>
<hr />
<h2>Scanner Workflow</h2>
<p>The complete nonconcurrent scanning algorithm is straightforward:</p>
<pre><code class="language-text">for each port
    generate address
    attempt TCP connection

    if success
        print OPEN
        close connection

    else
        continue
</code></pre>
<hr />
<h2>Why Is It Called Nonconcurrent?</h2>
<p>Only one port is tested at a time.</p>
<pre><code class="language-text">Port 1  -&gt; wait
Port 2  -&gt; wait
Port 3  -&gt; wait
...
Port 1024
</code></pre>
<p>Advantages:</p>
<ul>
<li>Easy to understand</li>
<li>Easy to debug</li>
<li>Minimal code complexity</li>
</ul>
<p>Disadvantages:</p>
<ul>
<li>Slow</li>
<li>Network latency accumulates</li>
<li>Does not scale to large scans</li>
</ul>
<p>Modern scanners solve this using:</p>
<ul>
<li>Threads</li>
<li>Async I/O</li>
<li>Tasks</li>
<li>Event-driven networking</li>
</ul>
<hr />
<h2>Educational Value</h2>
<p>Even though professional scanners use concurrency, a nonconcurrent scanner teaches several important networking concepts:</p>
<ul>
<li>TCP connection establishment</li>
<li>Socket programming</li>
<li>Port states</li>
<li>Error handling</li>
<li>Resource management</li>
<li>Network reconnaissance fundamentals</li>
</ul>
<p>Understanding this sequential model makes it much easier to appreciate how high-performance scanners achieve their speed.</p>
<hr />
<h2>Key Takeaways</h2>
<ul>
<li>TCP scanners determine port availability by attempting connections.</li>
<li>A loop can generate target addresses for thousands of ports.</li>
<li><code>sprintf</code> provides convenient address formatting in F#.</li>
<li>Successful connections should always be closed.</li>
<li>Nonconcurrent scanners are simple but relatively slow.</li>
<li>This approach forms the foundation for advanced concurrent port scanners.</li>
</ul>
<hr />
<p>A nonconcurrent scanner may not be the fastest tool in a security engineer's toolkit, but it provides an excellent introduction to how network discovery and TCP-based reconnaissance actually work under the hood.</p>
]]></content:encoded></item><item><title><![CDATA[Building a TCP Port Scanner in F#]]></title><description><![CDATA[Introduction
One of the best ways to understand TCP networking is by building a simple port scanner.
A port scanner attempts to connect to remote TCP ports and determines whether they are available. W]]></description><link>https://devnation.joshisfitness.com/building-a-tcp-port-scanner-in-f</link><guid isPermaLink="true">https://devnation.joshisfitness.com/building-a-tcp-port-scanner-in-f</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[coding]]></category><category><![CDATA[cybersecurity]]></category><category><![CDATA[Hashnode]]></category><dc:creator><![CDATA[Amit Joshi]]></dc:creator><pubDate>Sat, 20 Jun 2026 08:33:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/60eaa7126d962b01bdecf236/7379e287-2c38-42eb-849f-9a4c501b557f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1>Introduction</h1>
<p>One of the best ways to understand TCP networking is by building a simple port scanner.</p>
<p>A port scanner attempts to connect to remote TCP ports and determines whether they are available. While the implementation may be small, it exposes several important networking concepts:</p>
<ul>
<li>TCP connections</li>
<li>Client-server communication</li>
<li>TCP handshakes</li>
<li>Open and closed ports</li>
<li>Exception handling</li>
<li>Socket programming</li>
<li>F# pattern matching</li>
</ul>
<p>This article explores how a simple F# program can test TCP port availability and introduces the exception-handling syntax commonly used in networking applications.</p>
<hr />
<h1>What Is a TCP Port?</h1>
<p>A TCP port is a logical communication endpoint.</p>
<p>Servers listen on ports waiting for incoming connections.</p>
<p>Examples:</p>
<table>
<thead>
<tr>
<th>Service</th>
<th>Port</th>
</tr>
</thead>
<tbody><tr>
<td>HTTP</td>
<td>80</td>
</tr>
<tr>
<td>HTTPS</td>
<td>443</td>
</tr>
<tr>
<td>SSH</td>
<td>22</td>
</tr>
<tr>
<td>SMTP</td>
<td>25</td>
</tr>
<tr>
<td>FTP</td>
<td>21</td>
</tr>
</tbody></table>
<p>When a client wants to communicate with a service, it attempts to establish a TCP connection to the target port.</p>
<hr />
<h1>What Is Port Scanning?</h1>
<p>Port scanning is the process of testing one or more ports to determine whether they are accepting connections.</p>
<p>A scanner typically reports:</p>
<table>
<thead>
<tr>
<th>State</th>
<th>Meaning</th>
</tr>
</thead>
<tbody><tr>
<td>Open</td>
<td>Service accepts connections</td>
</tr>
<tr>
<td>Closed</td>
<td>Service rejects connections</td>
</tr>
<tr>
<td>Filtered</td>
<td>Firewall blocks traffic</td>
</tr>
<tr>
<td>Unreachable</td>
<td>Host cannot be reached</td>
</tr>
</tbody></table>
<p>Port scanners are widely used in:</p>
<ul>
<li>Network administration</li>
<li>Security auditing</li>
<li>Asset discovery</li>
<li>Troubleshooting</li>
<li>Cybersecurity assessments</li>
</ul>
<hr />
<h1>Understanding TCP Connections</h1>
<p>Before data can be exchanged, TCP establishes a connection between client and server.</p>
<p>The client sends a connection request.</p>
<p>The server responds.</p>
<p>Once both sides agree, communication begins.</p>
<p>If the connection succeeds, the port is considered open.</p>
<p>If the connection fails, the scanner can infer that the service is unavailable or inaccessible.</p>
<hr />
<h1>Connecting with TcpClient</h1>
<p>The .NET networking library provides the <code>TcpClient</code> class.</p>
<p>A connection can be created using:</p>
<pre><code class="language-fsharp">use client =
    new TcpClient("scanme.nmap.org", 80)
</code></pre>
<p>This statement attempts to connect to:</p>
<ul>
<li>Host: <code>scanme.nmap.org</code></li>
<li>Port: <code>80</code></li>
</ul>
<p>If the connection succeeds, the object is created successfully.</p>
<hr />
<h1>A Minimal TCP Scanner</h1>
<p>The entire scanner can fit into a few lines of code.</p>
<pre><code class="language-fsharp">try
    use client =
        new TcpClient("scanme.nmap.org", 80)

    printfn "Connection successful"

with
| :? SocketException -&gt;
    printfn "Connection failed"
</code></pre>
<p>The scanner attempts a TCP connection.</p>
<p>Success indicates an open port.</p>
<p>Failure generates a networking exception.</p>
<hr />
<h1>Why Error Handling Matters</h1>
<p>Networks are unpredictable.</p>
<p>Many things can go wrong:</p>
<ul>
<li>Host offline</li>
<li>Service unavailable</li>
<li>Firewall blocking traffic</li>
<li>DNS resolution failure</li>
<li>Routing problems</li>
</ul>
<p>Instead of crashing, the application should handle these failures gracefully.</p>
<p>That is where exception handling becomes important.</p>
<hr />
<h1>Understanding the try Block</h1>
<p>The <code>try</code> keyword marks code that might fail.</p>
<p>Example:</p>
<pre><code class="language-fsharp">try
    connect()
</code></pre>
<p>Meaning:</p>
<pre><code class="language-text">Attempt this operation.
If an error occurs,
handle it below.
</code></pre>
<p>Networking operations are common candidates for <code>try</code> blocks because they depend on external systems.</p>
<hr />
<h1>Understanding the with Keyword</h1>
<p>The <code>with</code> keyword begins exception handling.</p>
<p>Example:</p>
<pre><code class="language-fsharp">try
    connect()

with
</code></pre>
<p>Meaning:</p>
<pre><code class="language-text">If an exception occurs,
look for a matching handler.
</code></pre>
<p>The runtime compares the exception against each rule that follows.</p>
<hr />
<h1>Understanding the Pipe Operator</h1>
<p>The pipe symbol introduces a pattern-matching case.</p>
<p>Example:</p>
<pre><code class="language-fsharp">| pattern -&gt; action
</code></pre>
<p>Each pipe represents a possible match.</p>
<p>Example:</p>
<pre><code class="language-fsharp">with
| case1 -&gt; ...
| case2 -&gt; ...
| case3 -&gt; ...
</code></pre>
<p>The first matching case executes.</p>
<hr />
<h1>Understanding the Type Test Operator</h1>
<p>One of the most important operators in F# exception handling is:</p>
<pre><code class="language-fsharp">:?
</code></pre>
<p>This performs a runtime type check.</p>
<p>Example:</p>
<pre><code class="language-fsharp">:? SocketException
</code></pre>
<p>Meaning:</p>
<pre><code class="language-text">Is this exception a SocketException?
</code></pre>
<p>If yes, the match succeeds.</p>
<p>If no, F# continues searching for another handler.</p>
<hr />
<h1>Understanding SocketException</h1>
<p><code>SocketException</code> is a .NET exception used for networking errors.</p>
<p>Namespace:</p>
<pre><code class="language-fsharp">System.Net.Sockets
</code></pre>
<p>Typical causes include:</p>
<table>
<thead>
<tr>
<th>Error</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td>Connection Refused</td>
<td>Service not listening</td>
</tr>
<tr>
<td>Timeout</td>
<td>No response received</td>
</tr>
<tr>
<td>Host Not Found</td>
<td>DNS lookup failed</td>
</tr>
<tr>
<td>Network Unreachable</td>
<td>Routing issue</td>
</tr>
<tr>
<td>Connection Reset</td>
<td>Peer closed connection</td>
</tr>
</tbody></table>
<p>Because networking failures are common, <code>SocketException</code> appears frequently in TCP applications.</p>
<hr />
<h1>Understanding the Arrow Operator</h1>
<p>The arrow operator is:</p>
<pre><code class="language-fsharp">-&gt;
</code></pre>
<p>It means:</p>
<pre><code class="language-text">If this pattern matches,
execute the code on the right.
</code></pre>
<p>Example:</p>
<pre><code class="language-fsharp">| :? SocketException -&gt;
    printfn "Connection failed"
</code></pre>
<p>Meaning:</p>
<pre><code class="language-text">If the exception is a SocketException,
print an error message.
</code></pre>
<hr />
<h1>Execution Flow</h1>
<p>Let's walk through the scanner step by step.</p>
<h3>Step 1</h3>
<p>Attempt TCP connection.</p>
<pre><code class="language-fsharp">new TcpClient(...)
</code></pre>
<h3>Step 2</h3>
<p>Connection succeeds.</p>
<p>Output:</p>
<pre><code class="language-text">Connection successful
</code></pre>
<p>or</p>
<h3>Step 3</h3>
<p>Connection fails.</p>
<p>A <code>SocketException</code> is thrown.</p>
<h3>Step 4</h3>
<p>The exception handler matches:</p>
<pre><code class="language-fsharp">:? SocketException
</code></pre>
<h3>Step 5</h3>
<p>The failure message is displayed.</p>
<pre><code class="language-text">Connection failed
</code></pre>
<hr />
<h1>Why Port Scanners Use Exceptions</h1>
<p>Port scanners depend heavily on connection outcomes.</p>
<p>Successful connection:</p>
<pre><code class="language-text">Port Open
</code></pre>
<p>Connection refused:</p>
<pre><code class="language-text">Port Closed
</code></pre>
<p>Timeout:</p>
<pre><code class="language-text">Port Filtered
</code></pre>
<p>Host unreachable:</p>
<pre><code class="language-text">Target Unreachable
</code></pre>
<p>Exceptions provide a simple way to classify these outcomes.</p>
<hr />
<h1>Real-World Applications</h1>
<p>TCP scanning forms the foundation of:</p>
<ul>
<li>Vulnerability assessment</li>
<li>Service discovery</li>
<li>Asset inventory</li>
<li>Penetration testing</li>
<li>Network troubleshooting</li>
<li>Security monitoring</li>
</ul>
<p>Understanding how scanners work also helps administrators better understand firewall behavior and network exposure.</p>
<hr />
<h1>Key Takeaways</h1>
<ul>
<li>TCP scanners determine port availability by attempting connections.</li>
<li><code>TcpClient</code> provides a simple way to establish TCP sessions.</li>
<li>Successful connections indicate open ports.</li>
<li>Failed connections generate exceptions.</li>
<li><code>SocketException</code> represents common networking failures.</li>
<li><code>try</code> identifies code that may fail.</li>
<li><code>with</code> starts exception handling.</li>
<li><code>|</code> introduces pattern-matching cases.</li>
<li><code>:?</code> performs runtime type testing.</li>
<li><code>-&gt;</code> specifies the action to execute after a successful match.</li>
<li>Concurrency is essential for high-performance scanning.</li>
</ul>
<hr />
<h1>Conclusion</h1>
<p>Building a TCP port scanner is an excellent introduction to networking and systems programming.</p>
<p>Even a small scanner demonstrates several foundational concepts, including TCP connections, port states, socket programming, exception handling, and pattern matching.</p>
<p>For F# developers, understanding how <code>SocketException</code> integrates with pattern matching provides a clean and expressive way to handle networking failures while building reliable network applications.</p>
<pre><code>
</code></pre>
]]></content:encoded></item></channel></rss>