<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel xmlns:content="http://purl.org/rss/1.0/modules/content" xmlns:media="http://search.yahoo.com/mrss/"><title>numerodix blog</title><link>http://www.matusiak.eu/numerodix/blog/</link><description>A blog about nothing</description><atom:link href="http://www.matusiak.eu/numerodix/blog/feed/" rel="self"></atom:link><language>en-us</language><lastBuildDate>Thu, 29 Apr 2021 20:40:05 +0000</lastBuildDate><item><title>Writing a new memory device - /dev/clipboard</title><link>http://www.matusiak.eu/numerodix/blog/2021/4/29/writing-new-memory-device-devclipboard/</link><description>


            &lt;div class="post-936 post hentry" id="post-936"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;April 29th, 2021&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c936.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;This article contains code for how to implement a simple device driver in the kernel. The quality of this code is... proof of concept quality. If you're planning to do serious kernel development please &lt;strong&gt;don't&lt;/strong&gt; use this code as a starting point.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today we're going to use what we learned &lt;a href="/numerodix/blog/2021/4/28/what-happens-when-you-pipe-stuff-devnull/"&gt;last time about /dev/null&lt;/a&gt; and take it to the next level. We're going to write a new memory device in the kernel. We will call it &lt;code&gt;/dev/clipboard&lt;/code&gt;. No, it's not an existing device. Go ahead and check on your system! &lt;img class="wp-smiley" src="http://www.matusiak.eu/static/smilies/smile.png"&gt;&lt;/p&gt;
&lt;p&gt;Why the name &lt;code&gt;/dev/clipboard&lt;/code&gt;? Because our new device will work just like a clipboard does. First you write bytes to it, and those bytes are saved. Later you come back and read from the device and it gives you back the same bytes. If you write to it again you overwrite what was there before. (This is not one of those fancy clipboards with multiple slots where you can choose which slot to retrieve.)&lt;/p&gt;
&lt;p&gt;Here's a demo of how it works:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# save to clipboard&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;abc 123&amp;quot;&lt;/span&gt; &amp;gt; /dev/clipboard 

&lt;span class="c"&gt;# retrieve from clipboard&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;cat /dev/clipboard
abc 123
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;For convenience we will also print a message to the kernel log whenever someone writes to or reads from the clipboard:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dmesg  &lt;span class="c"&gt;# just after the &amp;#39;echo&amp;#39; command&lt;/span&gt;
Saved 8 bytes to /dev/clipboard

&lt;span class="nv"&gt;$ &lt;/span&gt;dmesg  &lt;span class="c"&gt;# just after the &amp;#39;cat&amp;#39; command&lt;/span&gt;
Returned 8 bytes from /dev/clipboard
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Pretty neat, huh? Being able to just add a feature to the kernel like that. &lt;img class="wp-smiley" src="http://www.matusiak.eu/static/smilies/cool.png"&gt;&lt;/p&gt;
&lt;p&gt;We'll do all our work in &lt;code&gt;drivers/char/mem.c&lt;/code&gt;, right next to where &lt;code&gt;/dev/null&lt;/code&gt; and the other &lt;code&gt;/dev/xxx&lt;/code&gt; memory device drivers live.&lt;/p&gt;
&lt;p&gt;First, let's think about where the user's bytes will be kept.. they obviously have to be kept somewhere by the kernel, in the kernel's own memory. We'll keep it simple here and just use a static array of a fixed size. That means we're placing this array in one of the data segments of the kernel's binary, a segment that will be loaded and available at runtime. We'll use 4096 bytes as the size of the array, and that means we're adding 4kb to the kernel's memory footprint (so we don't want to make it too big):&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;#define CLIPBOARD_BUFSIZE 4096&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;clipboard_buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CLIPBOARD_BUFSIZE&lt;/code&gt; is a macro that decides how big the fixed array is - a constant. &lt;code&gt;clipboard_buffer&lt;/code&gt; is the array itself.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;clipboard_size&lt;/code&gt; is a variable that reflects how many bytes of user data the array currently holds. This will change every time we write to the clipboard.&lt;/p&gt;
&lt;p&gt;Okay, that's it for storage. Now let's turn to how we tell the kernel that this new device exists. We'll add it to the bottom of the list of devices implemented in this file:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;memdev&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;umode_t&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fops&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;fmode_t&lt;/span&gt; &lt;span class="n"&gt;fmode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;devlist&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DEVMEM_MINOR&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;mem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;null&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;null_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;port_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;zero&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zero_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;full&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;full_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;random&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;random_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;urandom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;urandom_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmsg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmsg_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;clipboard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;clipboard_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;And we need to populate a &lt;code&gt;file_operations&lt;/code&gt; struct. This is how we tell the kernel what a user can actually do with this new device. In our case, we want the user to be able to open it, read from it, or write to it, then close it. To achieve that we just need to implement a read and a write function. We can populate the other fields with stub functions that do nothing:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="n"&gt;clipboard_fops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llseek&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null_lseek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_clipboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_clipboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splice_write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splice_write_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Alright, we need a read function and a write function. Let's start with write first, because it's what the user will use first. What does the write function need to do?&lt;/p&gt;
&lt;p&gt;Well, when the user writes to the clipboard that write should overwrite whatever was in the clipboard before (as we said before). So let's zero the memory in the array.&lt;/p&gt;
&lt;p&gt;Next, we have an array of a fixed size. The user might write a byte string that fits or a byte string that exceeds our capacity. If the input is too big to store, we will just truncate the remainder that doesn't fit. (I haven't checked how other clipboards do this, but presumably they too have an upper limit.) Once we know how many bytes to keep, we'll copy those bytes from the user's buffer (which is transient) into our fixed array.&lt;/p&gt;
&lt;p&gt;Then we'll print a message to the kernel log to explain what we did. And finally return the number of bytes the user sent us, in order to confirm that the write succeeded. Put all of that together and we get more or less the following:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;write_clipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;__user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
			  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loff_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// erase the clipboard to an empty state&lt;/span&gt;
    &lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clipboard_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// decide how many bytes of input to keep&lt;/span&gt;
    &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// populate the clipboard&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;copy_from_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clipboard_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;EFAULT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Saved %lu bytes to /dev/clipboard&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// acknowledge all the bytes we received&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;What's the &lt;code&gt;EFAULT&lt;/code&gt; thing all about? &lt;code&gt;copy_from_user&lt;/code&gt; is a function provided by the kernel. If it fails to copy all the bytes we requested it will return a non-zero value. This makes the boolean predicate true and we enter the &lt;code&gt;if&lt;/code&gt; block. In the kernel the convention is to return a pre-defined error code prefixed with a minus sign to signal an error. We'll gloss over that here.&lt;/p&gt;
&lt;p&gt;That does it for the write function. Finally, we need the read function.&lt;/p&gt;
&lt;p&gt;The read function is a bit more tricky, because it's intended to be used to read incrementally. So a user can issue &lt;code&gt;read(1)&lt;/code&gt; to read a single byte and then call &lt;code&gt;read(1)&lt;/code&gt; again to read the next byte. Each time &lt;code&gt;read&lt;/code&gt; will return the bytes themselves and an integer which is a count of the number of bytes returned. Once there are no more bytes to return read will return the integer &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;How does the read function know how many bytes have been returned thus far? It needs to store this somewhere between calls. It turns out this is already provided for us - it's what the argument &lt;code&gt;ppos&lt;/code&gt; is for. &lt;code&gt;ppos&lt;/code&gt; is used as a cursor from the beginning of the array. We'll update &lt;code&gt;ppos&lt;/code&gt; each time to reflect where the cursor should be, and the function calling our read function will store it for us until the next call.&lt;/p&gt;
&lt;p&gt;Other than that, the read function is pretty analogous to the write function:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;read_clipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;__user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
			 &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loff_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we&amp;#39;ve already read the whole buffer, nothing more to do here&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// how many more bytes are there in the clipboard left to read?&lt;/span&gt;
    &lt;span class="n"&gt;how_many&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// see if we have space for the whole clipboard in the user buffer&lt;/span&gt;
    &lt;span class="c1"&gt;// if not we&amp;#39;ll only return the first part of the clipboard&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;how_many&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;how_many&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// populate the user buffer using the clipboard buffer&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;copy_to_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clipboard_buffer&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;EFAULT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// advance the cursor to the end position in the clipboard that we are&lt;/span&gt;
    &lt;span class="c1"&gt;// returning&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Returned %lu bytes from /dev/clipboard&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// return the number of bytes we put into the user buffer&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;And that's it! That's all the code needed to implement a simple memory device in the kernel! &lt;img class="wp-smiley" src="http://www.matusiak.eu/static/smilies/party.png"&gt;&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Thu, 29 Apr 2021 20:40:05 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2021/4/29/writing-new-memory-device-devclipboard/</guid><category>kernel</category><content:encoded>


            &lt;div class="post-936 post hentry" id="post-936"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;April 29th, 2021&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c936.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;This article contains code for how to implement a simple device driver in the kernel. The quality of this code is... proof of concept quality. If you're planning to do serious kernel development please &lt;strong&gt;don't&lt;/strong&gt; use this code as a starting point.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today we're going to use what we learned &lt;a href="/numerodix/blog/2021/4/28/what-happens-when-you-pipe-stuff-devnull/"&gt;last time about /dev/null&lt;/a&gt; and take it to the next level. We're going to write a new memory device in the kernel. We will call it &lt;code&gt;/dev/clipboard&lt;/code&gt;. No, it's not an existing device. Go ahead and check on your system! &lt;img class="wp-smiley" src="http://www.matusiak.eu/static/smilies/smile.png"&gt;&lt;/p&gt;
&lt;p&gt;Why the name &lt;code&gt;/dev/clipboard&lt;/code&gt;? Because our new device will work just like a clipboard does. First you write bytes to it, and those bytes are saved. Later you come back and read from the device and it gives you back the same bytes. If you write to it again you overwrite what was there before. (This is not one of those fancy clipboards with multiple slots where you can choose which slot to retrieve.)&lt;/p&gt;
&lt;p&gt;Here's a demo of how it works:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# save to clipboard&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;abc 123&amp;quot;&lt;/span&gt; &amp;gt; /dev/clipboard 

&lt;span class="c"&gt;# retrieve from clipboard&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;cat /dev/clipboard
abc 123
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;For convenience we will also print a message to the kernel log whenever someone writes to or reads from the clipboard:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dmesg  &lt;span class="c"&gt;# just after the &amp;#39;echo&amp;#39; command&lt;/span&gt;
Saved 8 bytes to /dev/clipboard

&lt;span class="nv"&gt;$ &lt;/span&gt;dmesg  &lt;span class="c"&gt;# just after the &amp;#39;cat&amp;#39; command&lt;/span&gt;
Returned 8 bytes from /dev/clipboard
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Pretty neat, huh? Being able to just add a feature to the kernel like that. &lt;img class="wp-smiley" src="http://www.matusiak.eu/static/smilies/cool.png"&gt;&lt;/p&gt;
&lt;p&gt;We'll do all our work in &lt;code&gt;drivers/char/mem.c&lt;/code&gt;, right next to where &lt;code&gt;/dev/null&lt;/code&gt; and the other &lt;code&gt;/dev/xxx&lt;/code&gt; memory device drivers live.&lt;/p&gt;
&lt;p&gt;First, let's think about where the user's bytes will be kept.. they obviously have to be kept somewhere by the kernel, in the kernel's own memory. We'll keep it simple here and just use a static array of a fixed size. That means we're placing this array in one of the data segments of the kernel's binary, a segment that will be loaded and available at runtime. We'll use 4096 bytes as the size of the array, and that means we're adding 4kb to the kernel's memory footprint (so we don't want to make it too big):&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cp"&gt;#define CLIPBOARD_BUFSIZE 4096&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;clipboard_buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CLIPBOARD_BUFSIZE&lt;/code&gt; is a macro that decides how big the fixed array is - a constant. &lt;code&gt;clipboard_buffer&lt;/code&gt; is the array itself.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;clipboard_size&lt;/code&gt; is a variable that reflects how many bytes of user data the array currently holds. This will change every time we write to the clipboard.&lt;/p&gt;
&lt;p&gt;Okay, that's it for storage. Now let's turn to how we tell the kernel that this new device exists. We'll add it to the bottom of the list of devices implemented in this file:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;memdev&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;umode_t&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fops&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;fmode_t&lt;/span&gt; &lt;span class="n"&gt;fmode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;devlist&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DEVMEM_MINOR&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;mem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;null&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;null_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;port_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;zero&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zero_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;full&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;full_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;random&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;random_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;urandom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;urandom_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmsg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmsg_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;clipboard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;clipboard_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;And we need to populate a &lt;code&gt;file_operations&lt;/code&gt; struct. This is how we tell the kernel what a user can actually do with this new device. In our case, we want the user to be able to open it, read from it, or write to it, then close it. To achieve that we just need to implement a read and a write function. We can populate the other fields with stub functions that do nothing:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="n"&gt;clipboard_fops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llseek&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null_lseek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_clipboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_clipboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splice_write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splice_write_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Alright, we need a read function and a write function. Let's start with write first, because it's what the user will use first. What does the write function need to do?&lt;/p&gt;
&lt;p&gt;Well, when the user writes to the clipboard that write should overwrite whatever was in the clipboard before (as we said before). So let's zero the memory in the array.&lt;/p&gt;
&lt;p&gt;Next, we have an array of a fixed size. The user might write a byte string that fits or a byte string that exceeds our capacity. If the input is too big to store, we will just truncate the remainder that doesn't fit. (I haven't checked how other clipboards do this, but presumably they too have an upper limit.) Once we know how many bytes to keep, we'll copy those bytes from the user's buffer (which is transient) into our fixed array.&lt;/p&gt;
&lt;p&gt;Then we'll print a message to the kernel log to explain what we did. And finally return the number of bytes the user sent us, in order to confirm that the write succeeded. Put all of that together and we get more or less the following:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;write_clipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;__user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
			  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loff_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// erase the clipboard to an empty state&lt;/span&gt;
    &lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clipboard_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// decide how many bytes of input to keep&lt;/span&gt;
    &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CLIPBOARD_BUFSIZE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// populate the clipboard&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;copy_from_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clipboard_buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;EFAULT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Saved %lu bytes to /dev/clipboard&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// acknowledge all the bytes we received&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;What's the &lt;code&gt;EFAULT&lt;/code&gt; thing all about? &lt;code&gt;copy_from_user&lt;/code&gt; is a function provided by the kernel. If it fails to copy all the bytes we requested it will return a non-zero value. This makes the boolean predicate true and we enter the &lt;code&gt;if&lt;/code&gt; block. In the kernel the convention is to return a pre-defined error code prefixed with a minus sign to signal an error. We'll gloss over that here.&lt;/p&gt;
&lt;p&gt;That does it for the write function. Finally, we need the read function.&lt;/p&gt;
&lt;p&gt;The read function is a bit more tricky, because it's intended to be used to read incrementally. So a user can issue &lt;code&gt;read(1)&lt;/code&gt; to read a single byte and then call &lt;code&gt;read(1)&lt;/code&gt; again to read the next byte. Each time &lt;code&gt;read&lt;/code&gt; will return the bytes themselves and an integer which is a count of the number of bytes returned. Once there are no more bytes to return read will return the integer &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;How does the read function know how many bytes have been returned thus far? It needs to store this somewhere between calls. It turns out this is already provided for us - it's what the argument &lt;code&gt;ppos&lt;/code&gt; is for. &lt;code&gt;ppos&lt;/code&gt; is used as a cursor from the beginning of the array. We'll update &lt;code&gt;ppos&lt;/code&gt; each time to reflect where the cursor should be, and the function calling our read function will store it for us until the next call.&lt;/p&gt;
&lt;p&gt;Other than that, the read function is pretty analogous to the write function:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;read_clipboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;__user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
			 &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loff_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// we&amp;#39;ve already read the whole buffer, nothing more to do here&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// how many more bytes are there in the clipboard left to read?&lt;/span&gt;
    &lt;span class="n"&gt;how_many&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clipboard_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// see if we have space for the whole clipboard in the user buffer&lt;/span&gt;
    &lt;span class="c1"&gt;// if not we&amp;#39;ll only return the first part of the clipboard&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;how_many&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;how_many&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// populate the user buffer using the clipboard buffer&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;copy_to_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clipboard_buffer&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;EFAULT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// advance the cursor to the end position in the clipboard that we are&lt;/span&gt;
    &lt;span class="c1"&gt;// returning&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Returned %lu bytes from /dev/clipboard&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// return the number of bytes we put into the user buffer&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;how_many&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;And that's it! That's all the code needed to implement a simple memory device in the kernel! &lt;img class="wp-smiley" src="http://www.matusiak.eu/static/smilies/party.png"&gt;&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c936.png" media="image"><media:title type="html">C936</media:title></media:content><media:content url="http://www.matusiak.eu/static/smilies/smile.png" media="image"><media:title type="html">Smile</media:title></media:content><media:content url="http://www.matusiak.eu/static/smilies/cool.png" media="image"><media:title type="html">Cool</media:title></media:content><media:content url="http://www.matusiak.eu/static/smilies/party.png" media="image"><media:title type="html">Party</media:title></media:content></item><item><title>What happens when you pipe stuff to /dev/null?</title><link>http://www.matusiak.eu/numerodix/blog/2021/4/28/what-happens-when-you-pipe-stuff-devnull/</link><description>


            &lt;div class="post-935 post hentry" id="post-935"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;April 28th, 2021&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c935.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;This question is one of those old chestnuts that have been around for ages. What happens when you send output to &lt;code&gt;/dev/null&lt;/code&gt;? It's singular because the bytes just seem to disappear, like into a black hole. No other file on the computer works like that. The question has taken on something of a philosophical dimension in the debates among programmers. It's almost like asking: &lt;em&gt;how do you take a piece of matter and compress it down into nothing - how is that possible?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, as of about a week ago I know the answer. And soon you will, too.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; appears as a file on the filesystem, but it's not really a file. Instead, it's something more like a border crossing. On one side - our side - &lt;code&gt;/dev/null&lt;/code&gt; is a file that we can open and write bytes into. But from the kernel's point of view, &lt;code&gt;/dev/null&lt;/code&gt; is a device. A device just like a physical piece of hardware: a mouse, or a network card. Of course, &lt;code&gt;/dev/null&lt;/code&gt; is not actually a physical device, it's a pseudo device if you will. But the point is that the kernel treats it as a device - it uses the same vocabulary of concepts when dealing with &lt;code&gt;/dev/null&lt;/code&gt; as it does dealing with hardware devices.&lt;/p&gt;
&lt;p&gt;So if we have a device - and this is not a trick question - what do we need to have to able to use it? A device driver, exactly. So for the kernel &lt;code&gt;/dev/null&lt;/code&gt; is a device and its behavior is defined by its device driver. That driver lives in &lt;code&gt;drivers/char/mem.c&lt;/code&gt;. Let's have a look!&lt;/p&gt;
&lt;p&gt;Near the bottom of the file we find an array definition:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;memdev&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;umode_t&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fops&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;fmode_t&lt;/span&gt; &lt;span class="n"&gt;fmode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;devlist&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DEVMEM_MINOR&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;mem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;null&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;null_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;port_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;zero&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zero_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;full&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;full_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;random&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;random_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;urandom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;urandom_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmsg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmsg_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;We don't need to understand all the details here, but just look at the names being defined: &lt;code&gt;mem&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;zero&lt;/code&gt;, &lt;code&gt;random&lt;/code&gt;, &lt;code&gt;urandom&lt;/code&gt;. Where have we seen these names before? We've seen them endless times as &lt;code&gt;/dev/mem&lt;/code&gt;, &lt;code&gt;/dev/null&lt;/code&gt;, &lt;code&gt;/dev/zero&lt;/code&gt;, &lt;code&gt;/dev/random&lt;/code&gt;, &lt;code&gt;/dev/urandom&lt;/code&gt;. And it's in this file that they are actually defined.&lt;/p&gt;
&lt;p&gt;If we focus on the line that defines &lt;code&gt;null&lt;/code&gt; we can see that it mentions something called &lt;code&gt;null_fops&lt;/code&gt;. This is a struct that defines the behavior of &lt;code&gt;/dev/null&lt;/code&gt;. And the struct looks like this:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="n"&gt;null_fops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llseek&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null_lseek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splice_write&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splice_write_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;The values being used to populate this struct are function pointers. So when &lt;code&gt;/dev/null&lt;/code&gt; is being written to the function that is responsible for this is &lt;code&gt;write_null&lt;/code&gt;. And when &lt;code&gt;/dev/null&lt;/code&gt; is being read from (it's not often we read from &lt;code&gt;/dev/null&lt;/code&gt;) the function responsible for that is &lt;code&gt;read_null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alright, we are just about to find out what happens when you write to &lt;code&gt;/dev/null&lt;/code&gt;. The moment you have been waiting for. Are you ready for this? Here we go:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;write_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;__user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loff_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;write_null&lt;/code&gt; gets two arguments that are of interest to us: the bytes that we sent to &lt;code&gt;/dev/null&lt;/code&gt; - represented by &lt;code&gt;buf&lt;/code&gt;, and the size of that buffer - represented by &lt;code&gt;count&lt;/code&gt;. And what does &lt;code&gt;write_null&lt;/code&gt; do with these bytes? Nothing, nothing at all! All it does is return &lt;code&gt;count&lt;/code&gt; to confirm that "we've received your bytes, sir". And that's it.&lt;/p&gt;
&lt;p&gt;Writing to &lt;code&gt;/dev/null&lt;/code&gt; is literally calling a function that ignores its argument. As simple as that. It doesn't look like that because &lt;code&gt;/dev/null&lt;/code&gt; appears to us as a file, and the write causes a switch from user mode into kernel mode, and the bytes we send pass through a whole bunch of functions inside the kernel, but at the very end they are sent to the device driver that implements &lt;code&gt;/dev/null&lt;/code&gt; and that driver does... nothing! How do you implement doing nothing? You write a function that takes an argument and doesn't use it. Genius!&lt;/p&gt;
&lt;p&gt;And considering how often we use &lt;code&gt;/dev/null&lt;/code&gt; to discard bytes we don't want to write to a (real) file and we don't want to appear in the terminal, it's actually an incredibly valuable implementation of nothing! It's the most useful nothing on the computer!&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Wed, 28 Apr 2021 00:50:33 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2021/4/28/what-happens-when-you-pipe-stuff-devnull/</guid><category>kernel</category><content:encoded>


            &lt;div class="post-935 post hentry" id="post-935"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;April 28th, 2021&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c935.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;This question is one of those old chestnuts that have been around for ages. What happens when you send output to &lt;code&gt;/dev/null&lt;/code&gt;? It's singular because the bytes just seem to disappear, like into a black hole. No other file on the computer works like that. The question has taken on something of a philosophical dimension in the debates among programmers. It's almost like asking: &lt;em&gt;how do you take a piece of matter and compress it down into nothing - how is that possible?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, as of about a week ago I know the answer. And soon you will, too.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/dev/null&lt;/code&gt; appears as a file on the filesystem, but it's not really a file. Instead, it's something more like a border crossing. On one side - our side - &lt;code&gt;/dev/null&lt;/code&gt; is a file that we can open and write bytes into. But from the kernel's point of view, &lt;code&gt;/dev/null&lt;/code&gt; is a device. A device just like a physical piece of hardware: a mouse, or a network card. Of course, &lt;code&gt;/dev/null&lt;/code&gt; is not actually a physical device, it's a pseudo device if you will. But the point is that the kernel treats it as a device - it uses the same vocabulary of concepts when dealing with &lt;code&gt;/dev/null&lt;/code&gt; as it does dealing with hardware devices.&lt;/p&gt;
&lt;p&gt;So if we have a device - and this is not a trick question - what do we need to have to able to use it? A device driver, exactly. So for the kernel &lt;code&gt;/dev/null&lt;/code&gt; is a device and its behavior is defined by its device driver. That driver lives in &lt;code&gt;drivers/char/mem.c&lt;/code&gt;. Let's have a look!&lt;/p&gt;
&lt;p&gt;Near the bottom of the file we find an array definition:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;memdev&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;umode_t&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fops&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="n"&gt;fmode_t&lt;/span&gt; &lt;span class="n"&gt;fmode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;devlist&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DEVMEM_MINOR&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;mem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;mem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmem_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FMODE_UNSIGNED_OFFSET&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;null&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;null_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;port&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;port_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;zero&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zero_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;full&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;full_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;random&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;random_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;urandom&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0666&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;urandom_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
	&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;kmsg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kmsg_fops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;We don't need to understand all the details here, but just look at the names being defined: &lt;code&gt;mem&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;zero&lt;/code&gt;, &lt;code&gt;random&lt;/code&gt;, &lt;code&gt;urandom&lt;/code&gt;. Where have we seen these names before? We've seen them endless times as &lt;code&gt;/dev/mem&lt;/code&gt;, &lt;code&gt;/dev/null&lt;/code&gt;, &lt;code&gt;/dev/zero&lt;/code&gt;, &lt;code&gt;/dev/random&lt;/code&gt;, &lt;code&gt;/dev/urandom&lt;/code&gt;. And it's in this file that they are actually defined.&lt;/p&gt;
&lt;p&gt;If we focus on the line that defines &lt;code&gt;null&lt;/code&gt; we can see that it mentions something called &lt;code&gt;null_fops&lt;/code&gt;. This is a struct that defines the behavior of &lt;code&gt;/dev/null&lt;/code&gt;. And the struct looks like this:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file_operations&lt;/span&gt; &lt;span class="n"&gt;null_fops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;llseek&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null_lseek&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;		&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_iter&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;write_iter_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
	&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;splice_write&lt;/span&gt;	&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;splice_write_null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;The values being used to populate this struct are function pointers. So when &lt;code&gt;/dev/null&lt;/code&gt; is being written to the function that is responsible for this is &lt;code&gt;write_null&lt;/code&gt;. And when &lt;code&gt;/dev/null&lt;/code&gt; is being read from (it's not often we read from &lt;code&gt;/dev/null&lt;/code&gt;) the function responsible for that is &lt;code&gt;read_null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Alright, we are just about to find out what happens when you write to &lt;code&gt;/dev/null&lt;/code&gt;. The moment you have been waiting for. Are you ready for this? Here we go:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;write_null&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;__user&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loff_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ppos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
	&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;write_null&lt;/code&gt; gets two arguments that are of interest to us: the bytes that we sent to &lt;code&gt;/dev/null&lt;/code&gt; - represented by &lt;code&gt;buf&lt;/code&gt;, and the size of that buffer - represented by &lt;code&gt;count&lt;/code&gt;. And what does &lt;code&gt;write_null&lt;/code&gt; do with these bytes? Nothing, nothing at all! All it does is return &lt;code&gt;count&lt;/code&gt; to confirm that "we've received your bytes, sir". And that's it.&lt;/p&gt;
&lt;p&gt;Writing to &lt;code&gt;/dev/null&lt;/code&gt; is literally calling a function that ignores its argument. As simple as that. It doesn't look like that because &lt;code&gt;/dev/null&lt;/code&gt; appears to us as a file, and the write causes a switch from user mode into kernel mode, and the bytes we send pass through a whole bunch of functions inside the kernel, but at the very end they are sent to the device driver that implements &lt;code&gt;/dev/null&lt;/code&gt; and that driver does... nothing! How do you implement doing nothing? You write a function that takes an argument and doesn't use it. Genius!&lt;/p&gt;
&lt;p&gt;And considering how often we use &lt;code&gt;/dev/null&lt;/code&gt; to discard bytes we don't want to write to a (real) file and we don't want to appear in the terminal, it's actually an incredibly valuable implementation of nothing! It's the most useful nothing on the computer!&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c935.png" media="image"><media:title type="html">C935</media:title></media:content></item><item><title>htop: cpu and memory usage stats</title><link>http://www.matusiak.eu/numerodix/blog/2021/4/13/htop-cpu-and-memory-usage-stats/</link><description>


            &lt;div class="post-934 post hentry" id="post-934"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;April 13th, 2021&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c934.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;code&gt;htop&lt;/code&gt; is an enhancement over regular &lt;code&gt;top&lt;/code&gt; and it's a very popular tool. But did you ever ask yourself how it actually works? In this article we'll be looking at where &lt;code&gt;htop&lt;/code&gt; gets cpu and memory utilization information from. Given that &lt;code&gt;htop&lt;/code&gt; runs on many different platforms, we'll be discussing just the Linux version of the story.&lt;/p&gt;
&lt;h2&gt;Cpu utilization per cpu&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; displays cpu utilization for each cpu. This is one the most key things we use &lt;code&gt;htop&lt;/code&gt; for, in order to gauge the current load on the system.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-cpus.png "/&gt;&lt;/p&gt;
&lt;p&gt;The information comes from &lt;code&gt;/proc/stat&lt;/code&gt; (documented &lt;a href="https://www.kernel.org/doc/html/latest/filesystems/proc.html#miscellaneous-kernel-statistics-in-proc-stat"&gt;here&lt;/a&gt;). This file contains a few different counters, but what's of interest to us right here are just the cpu lines which look like this:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;cpu  5183484 9992 1575742 162186539 903310 0 27048 0 0 0
cpu0 1355329 2304 389040 40426679 299055 0 6431 0 0 0
cpu1 1234845 2602 423662 40594393 187209 0 16487 0 0 0
cpu2 1347723 2837 413561 40442958 239035 0 4085 0 0 0
cpu3 1245586 2246 349478 40722507 178009 0 44 0 0 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;So what are these numbers? Well, each number represents the amount of &lt;em&gt;time&lt;/em&gt; spent in a particular state, by that cpu. This is true for each line that begins with cpuN. So cpu0 (which in &lt;code&gt;htop&lt;/code&gt; is displayed as cpu #1) spent:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1355329 units of time in user mode (ie. running user processes)&lt;/li&gt;
&lt;li&gt;2304 units of time in nice mode (ie. running user processes with a nice setting)&lt;/li&gt;
&lt;li&gt;389040 units of time in system mode (ie. running kernel processes)&lt;/li&gt;
&lt;li&gt;40426679 units of time in idle mode (ie. not doing anything)&lt;/li&gt;
&lt;li&gt;299055 units of time in iowait (ie. waiting for io to become ready)&lt;/li&gt;
&lt;li&gt;0 units of time servicing interrupts&lt;/li&gt;
&lt;li&gt;6431 units of time servicing soft interrupts&lt;/li&gt;
&lt;li&gt;0 units of time where the VM guest was waiting for the host CPU (if we're running in a VM)&lt;/li&gt;
&lt;li&gt;0 units of time where we're running a VM guest&lt;/li&gt;
&lt;li&gt;0 units of time where the VM guest is running with a nice setting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first line in the file is simply an aggregate of all the per-cpu lines.&lt;/p&gt;
&lt;p&gt;This is effectively the granularity that the kernel gives us about what the cpu spent time doing. The unit is something called &lt;code&gt;USER_HZ&lt;/code&gt;, which is 100 on this system. So if we spent 1,355,329 units in user mode, that means 1355329 / 100 = 13,553 seconds (3.76 hours) spent running user processes since the system booted. By contrast, we spent 4.67 &lt;em&gt;days&lt;/em&gt; in idle time, so this is clearly not a system under sustained load.&lt;/p&gt;
&lt;p&gt;So how does &lt;code&gt;htop&lt;/code&gt; use this? Each time it updates the ui it reads the contents of &lt;code&gt;/proc/stat&lt;/code&gt;. Here are two subsequent readings one second apart, which show just the values for cpu0:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# time=0s&lt;/span&gt;
cpu0 1366294 2305 392684 40566185 300222 0 6590 0 0 0
&lt;span class="c"&gt;# time=1s&lt;/span&gt;
cpu0 1366296 2305 392684 40566283 300222 0 6590 0 0 0

&lt;span class="c"&gt;# compute the delta between the readings&lt;/span&gt;
cpu0 2 0 0 98 0 0 0 0 0 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;We can see that between the first and the second reading we spent 2 units in user mode and 98 units in idle mode. If we add up all of the numbers (2 + 98 = 100) we can see that the cpu spent 2 / 100 = 2% of its time running user processes, which means cpu utilization for cpu0 would be displayed as 2%.&lt;/p&gt;
&lt;h2&gt;Cpu utilization per process&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-proclist.png "/&gt;&lt;/p&gt;
&lt;p&gt;Cpu utilization per process is actually measured in a very similar way. This time the file being read is &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stat&lt;/code&gt; (documented &lt;a href="https://man7.org/linux/man-pages/man5/proc.5.html"&gt;here&lt;/a&gt;) which contains a whole bunch of counters about the process in question. Here it is for the X server:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;939 &lt;span class="o"&gt;(&lt;/span&gt;Xorg&lt;span class="o"&gt;)&lt;/span&gt; S 904 939 939 1025 939 4194560 233020 15663 1847 225 297398 280532 25 14 20 0 10 0 4719 789872640 10552 18446744073709551615 93843303677952 93843305320677 140727447720048 0 0 0 0 4096 1098933999 0 0 0 17 3 0 0 3235 0 0 93843305821872 93843305878768 93843309584384 140727447727751 140727447727899 140727447727899 140727447728101 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Fields 14 and 15 are the ones we are looking for here, because they represent respectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;utime, or the amount of time this process has been scheduled in user mode&lt;/li&gt;
&lt;li&gt;stime, or the amount of time this process has been scheduled in kernel mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These numbers are measured in the same unit we've seen before, namely &lt;code&gt;USER_HZ&lt;/code&gt;. &lt;code&gt;htop&lt;/code&gt; will thus calculate the cpu utilization per process as: &lt;code&gt;((utime + stime) - (utime_prev + stime_prev)) / USER_HZ&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; will calculate this for every running process each time it updates.&lt;/p&gt;
&lt;h2&gt;Memory utilization on the system&lt;/h2&gt;
&lt;p&gt;htop displays memory utilization in terms of physical memory and swap space.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-memswap.png "/&gt;&lt;/p&gt;
&lt;p&gt;This information is read from &lt;code&gt;/proc/meminfo&lt;/code&gt; (documented &lt;a href="https://www.kernel.org/doc/html/latest/filesystems/proc.html#meminfo"&gt;here&lt;/a&gt;) which looks like this (here showing just the lines that &lt;code&gt;htop&lt;/code&gt; cares about):&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;MemTotal:        3723752 kB
MemFree:          180308 kB
MemAvailable:     558240 kB
Buffers:           66816 kB
Cached:           782608 kB
SReclaimable:      87904 kB
SwapTotal:       1003516 kB
SwapCached:        13348 kB
SwapFree:         317256 kB
Shmem:            313436 kB
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Unlike the cpu stats, these are not counters that accumulate over time, they are point in time snapshots. Calculating the current memory utilization comes down to &lt;code&gt;MemTotal&lt;/code&gt; - &lt;code&gt;MemFree&lt;/code&gt;. Likewise, calculating swap usage means &lt;code&gt;SwapTotal&lt;/code&gt; - &lt;code&gt;SwapFree&lt;/code&gt; - &lt;code&gt;SwapCached&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; uses the other components of memory use (buffers, cached, shared mem) to color parts of the progress bar accordingly.&lt;/p&gt;
&lt;h2&gt;Memory utilization per process&lt;/h2&gt;
&lt;p&gt;Memory utilization per process is shown as four numbers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;virtual memory, ie. how much memory the process has allocated (but not necessarily used yet)&lt;/li&gt;
&lt;li&gt;resident memory, ie. how much memory the process currently uses&lt;/li&gt;
&lt;li&gt;shared memory, ie. how much of its resident memory is composed of shared libraries that other processes are using&lt;/li&gt;
&lt;li&gt;memory utilization %, ie. how much of physical memory this process is using. This is based on the resident memory number.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-proclist.png "/&gt;&lt;/p&gt;
&lt;p&gt;This information is read from the file &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/statm&lt;/code&gt; (documented &lt;a href="https://man7.org/linux/man-pages/man5/proc.5.html"&gt;here&lt;/a&gt;). The file looks like this:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;196790 9938 4488 402 0 28226 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;This is the X server process once again, and the numbers mean:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;virtual memory size&lt;/li&gt;
&lt;li&gt;resident memory size&lt;/li&gt;
&lt;li&gt;shared memory size&lt;/li&gt;
&lt;li&gt;size of the program code (binary code)&lt;/li&gt;
&lt;li&gt;unused&lt;/li&gt;
&lt;li&gt;size of the data + stack of the program&lt;/li&gt;
&lt;li&gt;unused&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These numbers are in terms of the page size, which on this system is 4096. So to calculate the resident memory for Xorg &lt;code&gt;htop&lt;/code&gt; does &lt;code&gt;9938 * 4096 = 38mb&lt;/code&gt;. To calculate the percentage of system memory this process uses &lt;code&gt;htop&lt;/code&gt; does &lt;code&gt;(9938 * 4096) / (3723752 * 1024) = 1.1%&lt;/code&gt; using the &lt;code&gt;MemTotal&lt;/code&gt; number from before.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As we have seen in this practical example the kernel provides super useful information through a file based interface. These are not really files per se, because it's just in-memory state inside the kernel made available through the file system. So there is minimal overhead associated with opening/reading/closing these files. And this interface makes it very accessible to both sophisticated programs like &lt;code&gt;htop&lt;/code&gt; as well as simple scripts to access, because there is no need to link against system libraries. Arguably, this API makes the information more discoverable because any user on the system can &lt;code&gt;cat&lt;/code&gt; files on the &lt;code&gt;/proc&lt;/code&gt; file system to see what they contain.&lt;/p&gt;
&lt;p&gt;The downside is that these are files in text format which have to be parsed. If the format of the file changes over time the parsing logic may break, and a program like &lt;code&gt;htop&lt;/code&gt; has to account for the fact that newer kernel versions may add additional fields. In Linux there is also an evolution in progress where the &lt;code&gt;/proc&lt;/code&gt; file system remains, but more and more information is exposed through the &lt;code&gt;/sys&lt;/code&gt; file system.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Tue, 13 Apr 2021 01:55:33 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2021/4/13/htop-cpu-and-memory-usage-stats/</guid><category>code</category><content:encoded>


            &lt;div class="post-934 post hentry" id="post-934"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;April 13th, 2021&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c934.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;code&gt;htop&lt;/code&gt; is an enhancement over regular &lt;code&gt;top&lt;/code&gt; and it's a very popular tool. But did you ever ask yourself how it actually works? In this article we'll be looking at where &lt;code&gt;htop&lt;/code&gt; gets cpu and memory utilization information from. Given that &lt;code&gt;htop&lt;/code&gt; runs on many different platforms, we'll be discussing just the Linux version of the story.&lt;/p&gt;
&lt;h2&gt;Cpu utilization per cpu&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; displays cpu utilization for each cpu. This is one the most key things we use &lt;code&gt;htop&lt;/code&gt; for, in order to gauge the current load on the system.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-cpus.png "/&gt;&lt;/p&gt;
&lt;p&gt;The information comes from &lt;code&gt;/proc/stat&lt;/code&gt; (documented &lt;a href="https://www.kernel.org/doc/html/latest/filesystems/proc.html#miscellaneous-kernel-statistics-in-proc-stat"&gt;here&lt;/a&gt;). This file contains a few different counters, but what's of interest to us right here are just the cpu lines which look like this:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;cpu  5183484 9992 1575742 162186539 903310 0 27048 0 0 0
cpu0 1355329 2304 389040 40426679 299055 0 6431 0 0 0
cpu1 1234845 2602 423662 40594393 187209 0 16487 0 0 0
cpu2 1347723 2837 413561 40442958 239035 0 4085 0 0 0
cpu3 1245586 2246 349478 40722507 178009 0 44 0 0 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;So what are these numbers? Well, each number represents the amount of &lt;em&gt;time&lt;/em&gt; spent in a particular state, by that cpu. This is true for each line that begins with cpuN. So cpu0 (which in &lt;code&gt;htop&lt;/code&gt; is displayed as cpu #1) spent:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;1355329 units of time in user mode (ie. running user processes)&lt;/li&gt;
&lt;li&gt;2304 units of time in nice mode (ie. running user processes with a nice setting)&lt;/li&gt;
&lt;li&gt;389040 units of time in system mode (ie. running kernel processes)&lt;/li&gt;
&lt;li&gt;40426679 units of time in idle mode (ie. not doing anything)&lt;/li&gt;
&lt;li&gt;299055 units of time in iowait (ie. waiting for io to become ready)&lt;/li&gt;
&lt;li&gt;0 units of time servicing interrupts&lt;/li&gt;
&lt;li&gt;6431 units of time servicing soft interrupts&lt;/li&gt;
&lt;li&gt;0 units of time where the VM guest was waiting for the host CPU (if we're running in a VM)&lt;/li&gt;
&lt;li&gt;0 units of time where we're running a VM guest&lt;/li&gt;
&lt;li&gt;0 units of time where the VM guest is running with a nice setting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first line in the file is simply an aggregate of all the per-cpu lines.&lt;/p&gt;
&lt;p&gt;This is effectively the granularity that the kernel gives us about what the cpu spent time doing. The unit is something called &lt;code&gt;USER_HZ&lt;/code&gt;, which is 100 on this system. So if we spent 1,355,329 units in user mode, that means 1355329 / 100 = 13,553 seconds (3.76 hours) spent running user processes since the system booted. By contrast, we spent 4.67 &lt;em&gt;days&lt;/em&gt; in idle time, so this is clearly not a system under sustained load.&lt;/p&gt;
&lt;p&gt;So how does &lt;code&gt;htop&lt;/code&gt; use this? Each time it updates the ui it reads the contents of &lt;code&gt;/proc/stat&lt;/code&gt;. Here are two subsequent readings one second apart, which show just the values for cpu0:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# time=0s&lt;/span&gt;
cpu0 1366294 2305 392684 40566185 300222 0 6590 0 0 0
&lt;span class="c"&gt;# time=1s&lt;/span&gt;
cpu0 1366296 2305 392684 40566283 300222 0 6590 0 0 0

&lt;span class="c"&gt;# compute the delta between the readings&lt;/span&gt;
cpu0 2 0 0 98 0 0 0 0 0 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;We can see that between the first and the second reading we spent 2 units in user mode and 98 units in idle mode. If we add up all of the numbers (2 + 98 = 100) we can see that the cpu spent 2 / 100 = 2% of its time running user processes, which means cpu utilization for cpu0 would be displayed as 2%.&lt;/p&gt;
&lt;h2&gt;Cpu utilization per process&lt;/h2&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-proclist.png "/&gt;&lt;/p&gt;
&lt;p&gt;Cpu utilization per process is actually measured in a very similar way. This time the file being read is &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stat&lt;/code&gt; (documented &lt;a href="https://man7.org/linux/man-pages/man5/proc.5.html"&gt;here&lt;/a&gt;) which contains a whole bunch of counters about the process in question. Here it is for the X server:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;939 &lt;span class="o"&gt;(&lt;/span&gt;Xorg&lt;span class="o"&gt;)&lt;/span&gt; S 904 939 939 1025 939 4194560 233020 15663 1847 225 297398 280532 25 14 20 0 10 0 4719 789872640 10552 18446744073709551615 93843303677952 93843305320677 140727447720048 0 0 0 0 4096 1098933999 0 0 0 17 3 0 0 3235 0 0 93843305821872 93843305878768 93843309584384 140727447727751 140727447727899 140727447727899 140727447728101 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Fields 14 and 15 are the ones we are looking for here, because they represent respectively:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;utime, or the amount of time this process has been scheduled in user mode&lt;/li&gt;
&lt;li&gt;stime, or the amount of time this process has been scheduled in kernel mode&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These numbers are measured in the same unit we've seen before, namely &lt;code&gt;USER_HZ&lt;/code&gt;. &lt;code&gt;htop&lt;/code&gt; will thus calculate the cpu utilization per process as: &lt;code&gt;((utime + stime) - (utime_prev + stime_prev)) / USER_HZ&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; will calculate this for every running process each time it updates.&lt;/p&gt;
&lt;h2&gt;Memory utilization on the system&lt;/h2&gt;
&lt;p&gt;htop displays memory utilization in terms of physical memory and swap space.&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-memswap.png "/&gt;&lt;/p&gt;
&lt;p&gt;This information is read from &lt;code&gt;/proc/meminfo&lt;/code&gt; (documented &lt;a href="https://www.kernel.org/doc/html/latest/filesystems/proc.html#meminfo"&gt;here&lt;/a&gt;) which looks like this (here showing just the lines that &lt;code&gt;htop&lt;/code&gt; cares about):&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;MemTotal:        3723752 kB
MemFree:          180308 kB
MemAvailable:     558240 kB
Buffers:           66816 kB
Cached:           782608 kB
SReclaimable:      87904 kB
SwapTotal:       1003516 kB
SwapCached:        13348 kB
SwapFree:         317256 kB
Shmem:            313436 kB
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;Unlike the cpu stats, these are not counters that accumulate over time, they are point in time snapshots. Calculating the current memory utilization comes down to &lt;code&gt;MemTotal&lt;/code&gt; - &lt;code&gt;MemFree&lt;/code&gt;. Likewise, calculating swap usage means &lt;code&gt;SwapTotal&lt;/code&gt; - &lt;code&gt;SwapFree&lt;/code&gt; - &lt;code&gt;SwapCached&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;htop&lt;/code&gt; uses the other components of memory use (buffers, cached, shared mem) to color parts of the progress bar accordingly.&lt;/p&gt;
&lt;h2&gt;Memory utilization per process&lt;/h2&gt;
&lt;p&gt;Memory utilization per process is shown as four numbers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;virtual memory, ie. how much memory the process has allocated (but not necessarily used yet)&lt;/li&gt;
&lt;li&gt;resident memory, ie. how much memory the process currently uses&lt;/li&gt;
&lt;li&gt;shared memory, ie. how much of its resident memory is composed of shared libraries that other processes are using&lt;/li&gt;
&lt;li&gt;memory utilization %, ie. how much of physical memory this process is using. This is based on the resident memory number.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/htop-proclist.png "/&gt;&lt;/p&gt;
&lt;p&gt;This information is read from the file &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/statm&lt;/code&gt; (documented &lt;a href="https://man7.org/linux/man-pages/man5/proc.5.html"&gt;here&lt;/a&gt;). The file looks like this:&lt;/p&gt;
&lt;p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;196790 9938 4488 402 0 28226 0
&lt;/pre&gt;&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;This is the X server process once again, and the numbers mean:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;virtual memory size&lt;/li&gt;
&lt;li&gt;resident memory size&lt;/li&gt;
&lt;li&gt;shared memory size&lt;/li&gt;
&lt;li&gt;size of the program code (binary code)&lt;/li&gt;
&lt;li&gt;unused&lt;/li&gt;
&lt;li&gt;size of the data + stack of the program&lt;/li&gt;
&lt;li&gt;unused&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These numbers are in terms of the page size, which on this system is 4096. So to calculate the resident memory for Xorg &lt;code&gt;htop&lt;/code&gt; does &lt;code&gt;9938 * 4096 = 38mb&lt;/code&gt;. To calculate the percentage of system memory this process uses &lt;code&gt;htop&lt;/code&gt; does &lt;code&gt;(9938 * 4096) / (3723752 * 1024) = 1.1%&lt;/code&gt; using the &lt;code&gt;MemTotal&lt;/code&gt; number from before.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As we have seen in this practical example the kernel provides super useful information through a file based interface. These are not really files per se, because it's just in-memory state inside the kernel made available through the file system. So there is minimal overhead associated with opening/reading/closing these files. And this interface makes it very accessible to both sophisticated programs like &lt;code&gt;htop&lt;/code&gt; as well as simple scripts to access, because there is no need to link against system libraries. Arguably, this API makes the information more discoverable because any user on the system can &lt;code&gt;cat&lt;/code&gt; files on the &lt;code&gt;/proc&lt;/code&gt; file system to see what they contain.&lt;/p&gt;
&lt;p&gt;The downside is that these are files in text format which have to be parsed. If the format of the file changes over time the parsing logic may break, and a program like &lt;code&gt;htop&lt;/code&gt; has to account for the fact that newer kernel versions may add additional fields. In Linux there is also an evolution in progress where the &lt;code&gt;/proc&lt;/code&gt; file system remains, but more and more information is exposed through the &lt;code&gt;/sys&lt;/code&gt; file system.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c934.png" media="image"><media:title type="html">C934</media:title></media:content><media:content url="http://www.matusiak.eu/media/uploads/htop-cpus.png " media="image"><media:title type="html">Htop cpus</media:title></media:content><media:content url="http://www.matusiak.eu/media/uploads/htop-proclist.png " media="image"><media:title type="html">Htop proclist</media:title></media:content><media:content url="http://www.matusiak.eu/media/uploads/htop-memswap.png " media="image"><media:title type="html">Htop memswap</media:title></media:content><media:content url="http://www.matusiak.eu/media/uploads/htop-proclist.png " media="image"><media:title type="html">Htop proclist</media:title></media:content></item><item><title>Un poème pour Didier</title><link>http://www.matusiak.eu/numerodix/blog/2018/7/22/un-poeme-pour-didier/</link><description>


            &lt;div class="post-933 post hentry" id="post-933"&gt;
                
                &lt;img title="francês" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/france.png"&gt; &lt;small&gt;July 22nd, 2018&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c933.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;Une fois, Aimé, avec son capitaine, Didier, a tout gagné.&lt;/p&gt;
&lt;p&gt;Ensuite Didier, vingt ans après, son objectif à bien fixé.&lt;/p&gt;
&lt;p&gt;Parmi tous les joueurs, une équipe il a dû sélectionné.&lt;/p&gt;
&lt;p&gt;Il a pas tardé, que tout le monde lui est venu la contesté.&lt;/p&gt;
&lt;p&gt;Patiemment, tous les adversaires il les a éliminé.&lt;/p&gt;
&lt;p&gt;Même les sublimes croates, ils ont le mieux essayé.&lt;/p&gt;
&lt;p&gt;À la fin, quand même, c'est Didier qui a gagné.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Sun, 22 Jul 2018 00:21:55 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2018/7/22/un-poeme-pour-didier/</guid><category>misc</category><content:encoded>


            &lt;div class="post-933 post hentry" id="post-933"&gt;
                
                &lt;img title="francês" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/france.png"&gt; &lt;small&gt;July 22nd, 2018&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c933.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;Une fois, Aimé, avec son capitaine, Didier, a tout gagné.&lt;/p&gt;
&lt;p&gt;Ensuite Didier, vingt ans après, son objectif à bien fixé.&lt;/p&gt;
&lt;p&gt;Parmi tous les joueurs, une équipe il a dû sélectionné.&lt;/p&gt;
&lt;p&gt;Il a pas tardé, que tout le monde lui est venu la contesté.&lt;/p&gt;
&lt;p&gt;Patiemment, tous les adversaires il les a éliminé.&lt;/p&gt;
&lt;p&gt;Même les sublimes croates, ils ont le mieux essayé.&lt;/p&gt;
&lt;p&gt;À la fin, quand même, c'est Didier qui a gagné.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/france.png" media="image"><media:title type="html">France</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c933.png" media="image"><media:title type="html">C933</media:title></media:content></item><item><title>Backup/reinstall checkist</title><link>http://www.matusiak.eu/numerodix/blog/2018/3/14/backup-checkist/</link><description>


            &lt;div class="post-932 post hentry" id="post-932"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;March 14th, 2018&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c932.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;strong&gt;Backup checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* Top level dirs in ~&lt;/p&gt;
&lt;p&gt;* Dot files/dirs in ~&lt;/p&gt;
&lt;p&gt;* dpkg -l&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prepare install media&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;dd if=image.iso of=/dev/sdX bs=4M status=progress oflag=sync &amp;amp;&amp;amp; sync&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Boot from install media&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Switch BIOS to use SATA in AHCI mode, not RAID mode. Otherwise the drive may not be detected.&lt;/p&gt;
&lt;p&gt;To see block devices: lsblk&lt;/p&gt;
&lt;p&gt;To see details of hardware: lspci -vvv &lt;em&gt;or&lt;/em&gt; lshw&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reinstall checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* /etc/sudoers&lt;/p&gt;
&lt;p&gt;* apt: curl emacs-gtk evince gimp git gitk htop iotop ipython3 kdiff3 mpv net-tools network-manager-openconnect openssh-server python3-pip ttf-bitstream-vera ttf-mscorefonts-installer vim-gtk vlc yakuake&lt;/p&gt;
&lt;p&gt;* pip: nametrans reps&lt;/p&gt;
&lt;p&gt;* rustup: ripgrep&lt;/p&gt;
&lt;p&gt;* manual: chrome dropbox skype vscode zoom&lt;/p&gt;
&lt;p&gt;* ~/.xmodmaprc (use xev to discover mouse button numbers)&lt;/p&gt;
&lt;p&gt;* common_local.sh&lt;/p&gt;
&lt;p&gt;* re pull&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Config checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* focus follows mouse, 0ms delay&lt;/p&gt;
&lt;p&gt;* kde: desktop search off&lt;/p&gt;
&lt;p&gt;* kde: startup with empty session&lt;/p&gt;
&lt;p&gt;* kde: taskbar do not group items&lt;/p&gt;
&lt;p&gt;* konsole: set font size &amp;amp; scrollback buffer for profile, set profile as default&lt;/p&gt;
&lt;p&gt;* browsers: smooth scrolling off (chrome: chrome://flags/#smooth-scrolling)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* office vpn&lt;/p&gt;
&lt;div id="_mcePaste" style="position: absolute; left: -10000px; top: 212px; width: 1px; height: 1px; overflow: hidden;"&gt;&lt;span style="font-family:monospace"&gt;ttf-&lt;span style="font-weight: bold; color: #ff5454;"&gt;bitstrea&lt;/span&gt;m-vera&lt;br/&gt;
&lt;/span&gt;&lt;/div&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Wed, 14 Mar 2018 08:50:55 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2018/3/14/backup-checkist/</guid><category>technology</category><content:encoded>


            &lt;div class="post-932 post hentry" id="post-932"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;March 14th, 2018&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c932.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;strong&gt;Backup checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* Top level dirs in ~&lt;/p&gt;
&lt;p&gt;* Dot files/dirs in ~&lt;/p&gt;
&lt;p&gt;* dpkg -l&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prepare install media&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;dd if=image.iso of=/dev/sdX bs=4M status=progress oflag=sync &amp;amp;&amp;amp; sync&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Boot from install media&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Switch BIOS to use SATA in AHCI mode, not RAID mode. Otherwise the drive may not be detected.&lt;/p&gt;
&lt;p&gt;To see block devices: lsblk&lt;/p&gt;
&lt;p&gt;To see details of hardware: lspci -vvv &lt;em&gt;or&lt;/em&gt; lshw&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reinstall checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* /etc/sudoers&lt;/p&gt;
&lt;p&gt;* apt: curl emacs-gtk evince gimp git gitk htop iotop ipython3 kdiff3 mpv net-tools network-manager-openconnect openssh-server python3-pip ttf-bitstream-vera ttf-mscorefonts-installer vim-gtk vlc yakuake&lt;/p&gt;
&lt;p&gt;* pip: nametrans reps&lt;/p&gt;
&lt;p&gt;* rustup: ripgrep&lt;/p&gt;
&lt;p&gt;* manual: chrome dropbox skype vscode zoom&lt;/p&gt;
&lt;p&gt;* ~/.xmodmaprc (use xev to discover mouse button numbers)&lt;/p&gt;
&lt;p&gt;* common_local.sh&lt;/p&gt;
&lt;p&gt;* re pull&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Config checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* focus follows mouse, 0ms delay&lt;/p&gt;
&lt;p&gt;* kde: desktop search off&lt;/p&gt;
&lt;p&gt;* kde: startup with empty session&lt;/p&gt;
&lt;p&gt;* kde: taskbar do not group items&lt;/p&gt;
&lt;p&gt;* konsole: set font size &amp;amp; scrollback buffer for profile, set profile as default&lt;/p&gt;
&lt;p&gt;* browsers: smooth scrolling off (chrome: chrome://flags/#smooth-scrolling)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Test checklist&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;* office vpn&lt;/p&gt;
&lt;div id="_mcePaste" style="position: absolute; left: -10000px; top: 212px; width: 1px; height: 1px; overflow: hidden;"&gt;&lt;span style="font-family:monospace"&gt;ttf-&lt;span style="font-weight: bold; color: #ff5454;"&gt;bitstrea&lt;/span&gt;m-vera&lt;br/&gt;
&lt;/span&gt;&lt;/div&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c932.png" media="image"><media:title type="html">C932</media:title></media:content></item><item><title>django girls den haag 2016 welcome speech</title><link>http://www.matusiak.eu/numerodix/blog/2016/3/5/django-girls-den-haag-2016-welcome-speech/</link><description>


            &lt;div class="post-931 post hentry" id="post-931"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;March 5th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c931.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;Given on March 5, 2016 at Django Girls Den Haag 2016 in Den Haag.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Welcome, everyone!&lt;/p&gt;
&lt;p&gt;We are thrilled that you're all here. Some of you have come far to be here today with us and we really appreciate it. We have people from all over the Netherlands!&lt;/p&gt;
&lt;p&gt;I also wish to thank our sponsors. Without the sponsors this event just wouldn't be possible. Thank you: Amazon, Elastic, KPMG and GingerPayments!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Today is all about learning. You're about to learn programming, which is a completely new skill for most of you. It's going to be exciting. And some of it will be difficult. Learning *is* about pushing your boundaries, and it takes effort to learn anything.&lt;/p&gt;
&lt;p&gt;I know it will seem as though your coaches know everything. Later today you might be asking yourself: "how am I supposed to master all this? There is so much new information here!" You may feel overwhelmed. But I promise you that every programmer in this room, myself included, has been through that. It's completely normal, and you're on the right track. So don't feel bad about that!&lt;/p&gt;
&lt;p&gt;I want you to make mistakes today. Making mistakes is a good thing - whenever you make a mistake you learn something.&lt;/p&gt;
&lt;p&gt;And don't hesitate to ask questions. If you get an answer that you don't fully understand, keep asking! Don't settle for answers you don't understand.&lt;/p&gt;
&lt;p&gt;Finally, don't work so hard that you forget to take a break and get to know the people around you!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;I will now introduce the organizing team. Raise your hand when you hear your name.&lt;/p&gt;
&lt;p&gt;So I'm Martin, you've been getting my emails. We also have Chris. Robbie. Alexandra. And Tom.&lt;/p&gt;
&lt;p&gt;So we are the organizers and you might think this means we know what we're doing. But no. We're just a bunch of software developers. We've never tried to organize an event for 100 people before.&lt;/p&gt;
&lt;p&gt;Speaking for myself I had many moments of self doubt. How are we going to find a space big enough to host the workshop? How are we going to find enough volunteers to be coaches? How are we going to find all of you?&lt;/p&gt;
&lt;p&gt;We made a lot of mistakes. And we learned from them.&lt;/p&gt;
&lt;p&gt;We did it together as a team. It took effort, but it was also a pleasure.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;I hope all of you have met your coach by now. We have 26 coaches with us today. They are nice enough to spend their Saturday to make Django Girls possible, isn't that awesome? They've *also* come from all over the country.&lt;/p&gt;
&lt;p&gt;Please raise your hand when you hear your name.&lt;/p&gt;
&lt;p&gt;Could we have a round of applause for the coaches?&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Django Girls is a global initiative. It all started two years ago at a technical conference in Berlin. It was a big international conference with people from all over Europe. Now you should know that IT conferences are very male dominated. Two of the participants of that conference, the founders of Django Girls - Ola and Ola, had a simple idea: what if we organize a workshop for beginners - and for women! So they organized the very first Django Girls in 2014.&lt;/p&gt;
&lt;p&gt;Since then it has spread to 57 countries. There have been over 100  events already. This is the sixth one in the Netherlands.&lt;/p&gt;
&lt;p&gt;More than 3,500 women have participated! Many have gone on to become coaches. And you remember that very first Django Girls workshop? 80% of the participants there have organized their own Django Girls events since then in their country.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Now for some practical information.&lt;/p&gt;
&lt;p&gt;Today's workshop lasts from 9 to 5pm. You can find the schedule for today on the posters.&lt;/p&gt;
&lt;p&gt;The bathrooms are right around the corner, out that door and to the right.&lt;/p&gt;
&lt;p&gt;We have coffee, tea and snacks available now. We have a limited number of cups, so please try to reuse your cup!&lt;/p&gt;
&lt;p&gt;We have lunch coming in later on. It will be served in the lobby.&lt;/p&gt;
&lt;p&gt;We have a mystery event in the afternoon.&lt;/p&gt;
&lt;p&gt;We're a bit unsure of the wifi capacity with so many people using it all at once. So try to be gentle with the wifi connection. In case of problems it's possible to do big parts of the tutorial offline. Your coaches also have a copy of all the files on usb sticks you need today so you don't have to download them.&lt;/p&gt;
&lt;p&gt;Last but not least we have a code of conduct. The code of conduct is in place to ensure that everyone can feel safe at our event. You can find the full text on one of the posters. If you see anyone breaking the code of conduct, please talk to one the organizers!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/djangogirls-denhaag-2016-slide.png "/&gt;&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Sat, 05 Mar 2016 21:26:56 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2016/3/5/django-girls-den-haag-2016-welcome-speech/</guid><category>django girls</category><category>public speaking</category><content:encoded>


            &lt;div class="post-931 post hentry" id="post-931"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;March 5th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c931.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;Given on March 5, 2016 at Django Girls Den Haag 2016 in Den Haag.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Welcome, everyone!&lt;/p&gt;
&lt;p&gt;We are thrilled that you're all here. Some of you have come far to be here today with us and we really appreciate it. We have people from all over the Netherlands!&lt;/p&gt;
&lt;p&gt;I also wish to thank our sponsors. Without the sponsors this event just wouldn't be possible. Thank you: Amazon, Elastic, KPMG and GingerPayments!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Today is all about learning. You're about to learn programming, which is a completely new skill for most of you. It's going to be exciting. And some of it will be difficult. Learning *is* about pushing your boundaries, and it takes effort to learn anything.&lt;/p&gt;
&lt;p&gt;I know it will seem as though your coaches know everything. Later today you might be asking yourself: "how am I supposed to master all this? There is so much new information here!" You may feel overwhelmed. But I promise you that every programmer in this room, myself included, has been through that. It's completely normal, and you're on the right track. So don't feel bad about that!&lt;/p&gt;
&lt;p&gt;I want you to make mistakes today. Making mistakes is a good thing - whenever you make a mistake you learn something.&lt;/p&gt;
&lt;p&gt;And don't hesitate to ask questions. If you get an answer that you don't fully understand, keep asking! Don't settle for answers you don't understand.&lt;/p&gt;
&lt;p&gt;Finally, don't work so hard that you forget to take a break and get to know the people around you!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;I will now introduce the organizing team. Raise your hand when you hear your name.&lt;/p&gt;
&lt;p&gt;So I'm Martin, you've been getting my emails. We also have Chris. Robbie. Alexandra. And Tom.&lt;/p&gt;
&lt;p&gt;So we are the organizers and you might think this means we know what we're doing. But no. We're just a bunch of software developers. We've never tried to organize an event for 100 people before.&lt;/p&gt;
&lt;p&gt;Speaking for myself I had many moments of self doubt. How are we going to find a space big enough to host the workshop? How are we going to find enough volunteers to be coaches? How are we going to find all of you?&lt;/p&gt;
&lt;p&gt;We made a lot of mistakes. And we learned from them.&lt;/p&gt;
&lt;p&gt;We did it together as a team. It took effort, but it was also a pleasure.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;I hope all of you have met your coach by now. We have 26 coaches with us today. They are nice enough to spend their Saturday to make Django Girls possible, isn't that awesome? They've *also* come from all over the country.&lt;/p&gt;
&lt;p&gt;Please raise your hand when you hear your name.&lt;/p&gt;
&lt;p&gt;Could we have a round of applause for the coaches?&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Django Girls is a global initiative. It all started two years ago at a technical conference in Berlin. It was a big international conference with people from all over Europe. Now you should know that IT conferences are very male dominated. Two of the participants of that conference, the founders of Django Girls - Ola and Ola, had a simple idea: what if we organize a workshop for beginners - and for women! So they organized the very first Django Girls in 2014.&lt;/p&gt;
&lt;p&gt;Since then it has spread to 57 countries. There have been over 100  events already. This is the sixth one in the Netherlands.&lt;/p&gt;
&lt;p&gt;More than 3,500 women have participated! Many have gone on to become coaches. And you remember that very first Django Girls workshop? 80% of the participants there have organized their own Django Girls events since then in their country.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Now for some practical information.&lt;/p&gt;
&lt;p&gt;Today's workshop lasts from 9 to 5pm. You can find the schedule for today on the posters.&lt;/p&gt;
&lt;p&gt;The bathrooms are right around the corner, out that door and to the right.&lt;/p&gt;
&lt;p&gt;We have coffee, tea and snacks available now. We have a limited number of cups, so please try to reuse your cup!&lt;/p&gt;
&lt;p&gt;We have lunch coming in later on. It will be served in the lobby.&lt;/p&gt;
&lt;p&gt;We have a mystery event in the afternoon.&lt;/p&gt;
&lt;p&gt;We're a bit unsure of the wifi capacity with so many people using it all at once. So try to be gentle with the wifi connection. In case of problems it's possible to do big parts of the tutorial offline. Your coaches also have a copy of all the files on usb sticks you need today so you don't have to download them.&lt;/p&gt;
&lt;p&gt;Last but not least we have a code of conduct. The code of conduct is in place to ensure that everyone can feel safe at our event. You can find the full text on one of the posters. If you see anyone breaking the code of conduct, please talk to one the organizers!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="http://www.matusiak.eu/media/uploads/djangogirls-denhaag-2016-slide.png "/&gt;&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c931.png" media="image"><media:title type="html">C931</media:title></media:content><media:content url="http://www.matusiak.eu/media/uploads/djangogirls-denhaag-2016-slide.png " media="image"><media:title type="html">Djangogirls denhaag 2016 slide</media:title></media:content></item><item><title>what django girls is</title><link>http://www.matusiak.eu/numerodix/blog/2016/2/24/what-django-girls-is/</link><description>


            &lt;div class="post-930 post hentry" id="post-930"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;February 24th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c930.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;Given on Feb 23, 2016 at the Dutch Django Meetup in Amsterdam.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today I want to tell you about a part of the Django community that you may not even know about.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;This is how I think most of us see the Python community. A comfortable couch. Nice people. Right? Just a nice place to be.&lt;/p&gt;
&lt;p&gt;It's easy to make an analogy with software. Almost every developer has had the experience of working on a codebase that they inherited from someone else. The dreaded *legacy project*. And it wasn't the most fun project to work on. Spaghetti code, no tests, no documentation, really hard to make changes without breaking something.&lt;/p&gt;
&lt;p&gt;So after working on this day in and day out after a while you start to get a little sick of it. I start thinking to myself &lt;em&gt;"I've had it with this code. It expend so much energy on this and I have so little to show for it. Jeez, give me a codebase that's in good shape for a change. One that is modular, and has clean code. With good test coverage. If I had that I could *really* make it fly!"&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I want to submit to you that the Python community is that nice codebase. It's when your code is in good shape and is easy to work on, that it's a great starting point to make it even better. To take the next step.&lt;/p&gt;
&lt;p&gt;I'm sure you've heard this expression before: Came for the language, stayed for the community. People come to Python for the language, or for the libraries, or for the frameworks (like Django). Right? Just because they need to get some work done. And then they realize: hey there are conferences, there are meetups, and there are great people to hang out with. So they stay with Python not necessarily because it's the best programming language in the world, but rather because the community is a great place to be. It makes them feel at home.&lt;/p&gt;
&lt;p&gt;So I'm saying: let's take the next step. Let's make it even more welcoming, even more inclusive!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Let me tell you about what we do. Since you're programmers I will explain this as a program. Django Girls is a one day programming workshop for women. Our mission is to bring in women who are new to IT and get them hooked on programming. Now the workshop is the box you see in the middle.&lt;/p&gt;
&lt;p&gt;Then as input we take non-programmers. Most people who attend Django Girls have never written a program before. During the workshop they build a blog, from scratch. So they come in, never written a program before, and they go home, they've built a blog. Amazing, right? They do this following a tutorial which is very beginner friendly, so it explains everything they need to know.&lt;/p&gt;
&lt;p&gt;Also as input we take developers. These are the programming coaches. They don't have to be professional developers, just have enough experience with programming to help someone else through the tutorial.&lt;/p&gt;
&lt;p&gt;As output, we get programmers. They are beginners, of course, but they are programmers. We've given them the first step on a path that could potentially lead them to this room. Some percentage of Django Girls participants land junior developer jobs a few months down the road. But not everyone wants to be a developer, and that's fine. Some people are academics, and they want to learn how to automate parts of their work. Some work in marketing, and work with developers and want to understand what their colleagues do. And some people are just curious about programming and want to try it. We encourage all different demographics.&lt;/p&gt;
&lt;p&gt;And also output, we get the same developers, and you may think all they did was volunteer a day of their time and that's it. But they've just spent a whole day coaching people in programming. If you're already a mentor to people at your job, that's excellent! But if you're not, coach at Django Girls for a day and you get really good practice that will come in very useful in your career, believe me.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;So Django Girls is coming to Den Haag Saturday next week. We're going to be on the top floor of this office building. If you're familiar with Den Haag it's right next to the station Hollands Spoor.&lt;/p&gt;
&lt;p&gt;We received applications to participate from more than 100 women. We're also lucky enough to have found more than 30 coaches to help us.&lt;/p&gt;
&lt;p&gt;Unfortunately we only have space to host 60 participants, so we had to turn down a lot of people.&lt;/p&gt;
&lt;p&gt;But the level of interest has been really impressive. We have people coming from cities all over the country, like Groningen and Leuwwarden, Nijmegen and Deventer. We have people coming from Belgium, where Django Girls hasn't taken root yet.&lt;/p&gt;
&lt;p&gt;And then there's the 5 of us, the organizers. A few of us went to a Django Girls event as coaches and we loved it. We decided we wanted to organize one of these ourselves, in our city. Now we're just a bunch of software developers, we've never organized an event like this before. But we somehow pulled it off.&lt;/p&gt;
&lt;p&gt;If we can do it, you can do it. Think about it.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Now, Django Girls has been organized before in the Netherlands. There is a group of organizers in Groningen who are the pioneers in our country - and they're planning another even this year. It's also been organized in Amsterdam before. And then there's our event, which is the upcoming one.&lt;/p&gt;
&lt;p&gt;But like I said there is a lot of interest from people out there for a workshop like this. I would love to see more cities on this list in the future. So you could organize one. And you can be a coach! Most organizers have trouble finding enough coaches, and if they had more coaches they could accept more participants!&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;You can find &lt;a href="http://www.slideshare.net/MartinMatusiak/dutch-django-meetup-feb-2016"&gt;the slides on Slideshare&lt;/a&gt;.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Wed, 24 Feb 2016 18:45:51 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2016/2/24/what-django-girls-is/</guid><category>django girls</category><category>public speaking</category><content:encoded>


            &lt;div class="post-930 post hentry" id="post-930"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;February 24th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c930.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;Given on Feb 23, 2016 at the Dutch Django Meetup in Amsterdam.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today I want to tell you about a part of the Django community that you may not even know about.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;This is how I think most of us see the Python community. A comfortable couch. Nice people. Right? Just a nice place to be.&lt;/p&gt;
&lt;p&gt;It's easy to make an analogy with software. Almost every developer has had the experience of working on a codebase that they inherited from someone else. The dreaded *legacy project*. And it wasn't the most fun project to work on. Spaghetti code, no tests, no documentation, really hard to make changes without breaking something.&lt;/p&gt;
&lt;p&gt;So after working on this day in and day out after a while you start to get a little sick of it. I start thinking to myself &lt;em&gt;"I've had it with this code. It expend so much energy on this and I have so little to show for it. Jeez, give me a codebase that's in good shape for a change. One that is modular, and has clean code. With good test coverage. If I had that I could *really* make it fly!"&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I want to submit to you that the Python community is that nice codebase. It's when your code is in good shape and is easy to work on, that it's a great starting point to make it even better. To take the next step.&lt;/p&gt;
&lt;p&gt;I'm sure you've heard this expression before: Came for the language, stayed for the community. People come to Python for the language, or for the libraries, or for the frameworks (like Django). Right? Just because they need to get some work done. And then they realize: hey there are conferences, there are meetups, and there are great people to hang out with. So they stay with Python not necessarily because it's the best programming language in the world, but rather because the community is a great place to be. It makes them feel at home.&lt;/p&gt;
&lt;p&gt;So I'm saying: let's take the next step. Let's make it even more welcoming, even more inclusive!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Let me tell you about what we do. Since you're programmers I will explain this as a program. Django Girls is a one day programming workshop for women. Our mission is to bring in women who are new to IT and get them hooked on programming. Now the workshop is the box you see in the middle.&lt;/p&gt;
&lt;p&gt;Then as input we take non-programmers. Most people who attend Django Girls have never written a program before. During the workshop they build a blog, from scratch. So they come in, never written a program before, and they go home, they've built a blog. Amazing, right? They do this following a tutorial which is very beginner friendly, so it explains everything they need to know.&lt;/p&gt;
&lt;p&gt;Also as input we take developers. These are the programming coaches. They don't have to be professional developers, just have enough experience with programming to help someone else through the tutorial.&lt;/p&gt;
&lt;p&gt;As output, we get programmers. They are beginners, of course, but they are programmers. We've given them the first step on a path that could potentially lead them to this room. Some percentage of Django Girls participants land junior developer jobs a few months down the road. But not everyone wants to be a developer, and that's fine. Some people are academics, and they want to learn how to automate parts of their work. Some work in marketing, and work with developers and want to understand what their colleagues do. And some people are just curious about programming and want to try it. We encourage all different demographics.&lt;/p&gt;
&lt;p&gt;And also output, we get the same developers, and you may think all they did was volunteer a day of their time and that's it. But they've just spent a whole day coaching people in programming. If you're already a mentor to people at your job, that's excellent! But if you're not, coach at Django Girls for a day and you get really good practice that will come in very useful in your career, believe me.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;So Django Girls is coming to Den Haag Saturday next week. We're going to be on the top floor of this office building. If you're familiar with Den Haag it's right next to the station Hollands Spoor.&lt;/p&gt;
&lt;p&gt;We received applications to participate from more than 100 women. We're also lucky enough to have found more than 30 coaches to help us.&lt;/p&gt;
&lt;p&gt;Unfortunately we only have space to host 60 participants, so we had to turn down a lot of people.&lt;/p&gt;
&lt;p&gt;But the level of interest has been really impressive. We have people coming from cities all over the country, like Groningen and Leuwwarden, Nijmegen and Deventer. We have people coming from Belgium, where Django Girls hasn't taken root yet.&lt;/p&gt;
&lt;p&gt;And then there's the 5 of us, the organizers. A few of us went to a Django Girls event as coaches and we loved it. We decided we wanted to organize one of these ourselves, in our city. Now we're just a bunch of software developers, we've never organized an event like this before. But we somehow pulled it off.&lt;/p&gt;
&lt;p&gt;If we can do it, you can do it. Think about it.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;Now, Django Girls has been organized before in the Netherlands. There is a group of organizers in Groningen who are the pioneers in our country - and they're planning another even this year. It's also been organized in Amsterdam before. And then there's our event, which is the upcoming one.&lt;/p&gt;
&lt;p&gt;But like I said there is a lot of interest from people out there for a workshop like this. I would love to see more cities on this list in the future. So you could organize one. And you can be a coach! Most organizers have trouble finding enough coaches, and if they had more coaches they could accept more participants!&lt;/p&gt;
&lt;p&gt;Thank you!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;You can find &lt;a href="http://www.slideshare.net/MartinMatusiak/dutch-django-meetup-feb-2016"&gt;the slides on Slideshare&lt;/a&gt;.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c930.png" media="image"><media:title type="html">C930</media:title></media:content></item><item><title>why you should coach at django girls</title><link>http://www.matusiak.eu/numerodix/blog/2016/2/22/why-you-should-coach-django-girls/</link><description>


            &lt;div class="post-929 post hentry" id="post-929"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;February 22nd, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c929.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;Given on Dec 10, 2015 at PyLadies Amsterdam.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Dear PyLadies,&lt;/p&gt;
&lt;p&gt;My name is Martin and I'm one of the organizers of Django Girls The Hague. Which will take place next year in the beginning of March.&lt;/p&gt;
&lt;p&gt;Django Girls is a non-profit organization that aims to give women a really positive first experience with programming. I'm not going to explain why we think this is  important, because I think if you're a member of PyLadies you already know that.&lt;/p&gt;
&lt;p&gt;I will explain how we do it. We invite a room full of women to participate. We seat a group of 3 women around a table. And we give them a programming coach. What they will be doing is building a web application from scratch. Using a tutorial special made for Django Girls. Now, the programming coach is there to help them, to explain things, and to give moral support.&lt;/p&gt;
&lt;p&gt;Now, the coaches are integral to the event. We as organizers can provide a nice room in a nice location, a good tutorial, and food etc, but the coach is the human factor.&lt;/p&gt;
&lt;p&gt;We are currently trying to find these coaches. That's why I'm here today. I would really like to encourage you to sign up to be a coach.&lt;/p&gt;
&lt;p&gt;I've been a coach at two Django Girls events in the past. And in fact tomorrow morning I'm flying to Italy to be a coach at Django Girls in Rome on Saturday. It's a really fun thing to do.&lt;/p&gt;
&lt;p&gt;The people who come to Django Girls aren't the kind of people who say alright, so what is this programming thing all about? If it doesn't take more than 5 minutes I'm willing to give it a try and then I'll be on my way. These are people who decide to spend 8-9 hours learning something new, that they've never done before. I mean can you imagine? It takes little courage to do that. So they're really interested and motivated to learn programming. And as a coach you see programming happen for the first time, through their eyes. It's really exciting. It's a really fun way to spend a day.&lt;/p&gt;
&lt;p&gt;In terms of what it takes to be a coach. I want to make this very clear: You don't have to an expert on Python or Django. I would recommend that you work through the tutorial that we use yourself. Ask yourself if you understand everything. Ask yourself if you think you can help someone complete it. If so then you can be a coach. Ultimately if you encounter a problem at the workshop we will have some more experienced coaches to help you.&lt;/p&gt;
&lt;p&gt;So if you think this sounds awesome and you want to help us make this possible then sign up to be a coach. You can sign up on our website, just google for Django Girls and find our chapter for The Hague, Den Haag. We also have a twitter feed where you can follow our updates.&lt;/p&gt;
&lt;p&gt;We would love to have you there! Thank you very much!!&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Mon, 22 Feb 2016 19:31:14 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2016/2/22/why-you-should-coach-django-girls/</guid><category>django girls</category><category>public speaking</category><content:encoded>


            &lt;div class="post-929 post hentry" id="post-929"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;February 22nd, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c929.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;&lt;em&gt;Given on Dec 10, 2015 at PyLadies Amsterdam.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Dear PyLadies,&lt;/p&gt;
&lt;p&gt;My name is Martin and I'm one of the organizers of Django Girls The Hague. Which will take place next year in the beginning of March.&lt;/p&gt;
&lt;p&gt;Django Girls is a non-profit organization that aims to give women a really positive first experience with programming. I'm not going to explain why we think this is  important, because I think if you're a member of PyLadies you already know that.&lt;/p&gt;
&lt;p&gt;I will explain how we do it. We invite a room full of women to participate. We seat a group of 3 women around a table. And we give them a programming coach. What they will be doing is building a web application from scratch. Using a tutorial special made for Django Girls. Now, the programming coach is there to help them, to explain things, and to give moral support.&lt;/p&gt;
&lt;p&gt;Now, the coaches are integral to the event. We as organizers can provide a nice room in a nice location, a good tutorial, and food etc, but the coach is the human factor.&lt;/p&gt;
&lt;p&gt;We are currently trying to find these coaches. That's why I'm here today. I would really like to encourage you to sign up to be a coach.&lt;/p&gt;
&lt;p&gt;I've been a coach at two Django Girls events in the past. And in fact tomorrow morning I'm flying to Italy to be a coach at Django Girls in Rome on Saturday. It's a really fun thing to do.&lt;/p&gt;
&lt;p&gt;The people who come to Django Girls aren't the kind of people who say alright, so what is this programming thing all about? If it doesn't take more than 5 minutes I'm willing to give it a try and then I'll be on my way. These are people who decide to spend 8-9 hours learning something new, that they've never done before. I mean can you imagine? It takes little courage to do that. So they're really interested and motivated to learn programming. And as a coach you see programming happen for the first time, through their eyes. It's really exciting. It's a really fun way to spend a day.&lt;/p&gt;
&lt;p&gt;In terms of what it takes to be a coach. I want to make this very clear: You don't have to an expert on Python or Django. I would recommend that you work through the tutorial that we use yourself. Ask yourself if you understand everything. Ask yourself if you think you can help someone complete it. If so then you can be a coach. Ultimately if you encounter a problem at the workshop we will have some more experienced coaches to help you.&lt;/p&gt;
&lt;p&gt;So if you think this sounds awesome and you want to help us make this possible then sign up to be a coach. You can sign up on our website, just google for Django Girls and find our chapter for The Hague, Den Haag. We also have a twitter feed where you can follow our updates.&lt;/p&gt;
&lt;p&gt;We would love to have you there! Thank you very much!!&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c929.png" media="image"><media:title type="html">C929</media:title></media:content></item><item><title>what would you do with 6 months?</title><link>http://www.matusiak.eu/numerodix/blog/2016/1/24/what-would-you-do-6-months/</link><description>


            &lt;div class="post-924 post hentry" id="post-924"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;January 24th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c924.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;In the first months of 2015 I realized that I was burned out. Work was fun, but it had expanded so much that it had taken over my entire life. Fergus O'Connell gives this definition of burnout: &lt;em&gt;you're at work, you're thinking about work, you're bringing work home with you, or you're cancelling other things so you can work&lt;/em&gt;. Open and shut case, Johnson.&lt;/p&gt;
&lt;p&gt;I decided it was time to change, everything. It was my very own "&lt;em&gt;everything stops!&lt;/em&gt;" moment. I would leave my job in June and take a six month break from work. From all work to no work. The cover story was "sabbatical", but the working title was "life improvement project".&lt;/p&gt;
&lt;p&gt;And it has been the most liberating time of my life. There was much planning and project management involved - I'll spare you that. Here are the milestones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Health&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lost weight.&lt;/li&gt;
&lt;li&gt;Experimented with the paleo diet.&lt;/li&gt;
&lt;li&gt;Saw a physical therapist.&lt;/li&gt;
&lt;li&gt;Saw a psychologist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sports&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swam in the pool.&lt;/li&gt;
&lt;li&gt;Biked intercity road trips.&lt;/li&gt;
&lt;li&gt;Practiced yoga.&lt;/li&gt;
&lt;li&gt;Practiced strength training.&lt;/li&gt;
&lt;li&gt;Went running. Ran a 10km distance. Ran a 5km race.&lt;/li&gt;
&lt;li&gt;Practiced interval training.&lt;/li&gt;
&lt;li&gt;Played football.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Social&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Saw friends.&lt;/li&gt;
&lt;li&gt;Attended a Devnology weekend.&lt;/li&gt;
&lt;li&gt;Gave pitches for Django Girls to recruit coaches and participants.&lt;/li&gt;
&lt;li&gt;Took an improv class.&lt;/li&gt;
&lt;li&gt;Took part in a theater workshop.&lt;/li&gt;
&lt;li&gt;Hosted a friend for a long weekend.&lt;/li&gt;
&lt;li&gt;Practiced speed dating.&lt;/li&gt;
&lt;li&gt;Went on normal speed dates.&lt;/li&gt;
&lt;li&gt;Attended my best friend's wedding.&lt;/li&gt;
&lt;li&gt;Frequented 24 different social groups.&lt;/li&gt;
&lt;li&gt;Attended 36 social events in total.&lt;/li&gt;
&lt;li&gt;Met more new people than I've ever done before in 6 months.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Travel&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To Dublin for a job interview.&lt;/li&gt;
&lt;li&gt;To Friesland for Devnology weekend.&lt;/li&gt;
&lt;li&gt;To Groningen for Django Girls.&lt;/li&gt;
&lt;li&gt;To Bordeaux for Django Girls.&lt;/li&gt;
&lt;li&gt;To Rome for Django Girls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Language study&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Had Skype sessions with Dutch tutors.&lt;/li&gt;
&lt;li&gt;Completed a Portuguese course.&lt;/li&gt;
&lt;li&gt;Attended language café meetups.&lt;/li&gt;
&lt;li&gt;Read books in Portuguese.&lt;/li&gt;
&lt;li&gt;Made polyglot-ish Youtube videos.&lt;/li&gt;
&lt;li&gt;Wrote polyglot-ish blog entries.&lt;/li&gt;
&lt;li&gt;Coached in French at Django Girls.&lt;/li&gt;
&lt;li&gt;Coached in Italian at Django Girls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technology&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Studied x86 assembly.&lt;/li&gt;
&lt;li&gt;Read about computer architecture.&lt;/li&gt;
&lt;li&gt;Learned some Prolog.&lt;/li&gt;
&lt;li&gt;Wrote a memcached clone in Rust.&lt;/li&gt;
&lt;li&gt;Read computer science papers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Community work / Volunteering&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coached at three Django Girls events.&lt;/li&gt;
&lt;li&gt;Taught a basic computer course at a community center.&lt;/li&gt;
&lt;li&gt;Worked on organizing Django Girls Den Haag.&lt;/li&gt;
&lt;li&gt;Submitted a talk proposal to PyCon Italia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Career / Work&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reached out for career advice to my network.&lt;/li&gt;
&lt;li&gt;Spoke to a lot of recruiters.&lt;/li&gt;
&lt;li&gt;Interviewed with a lot of different companies, local and remote. Turned down many offers.&lt;/li&gt;
&lt;li&gt;Applied for positions I wasn't qualified for. Was turned down.&lt;/li&gt;
&lt;li&gt;Finally found the kind of companies that I was after. Accepted an offer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these were a first. Over time there has been a conscious trend from "&lt;em&gt;things I do at home alone (in my pyjamas)&lt;/em&gt;" to "&lt;em&gt;things I do with others&lt;/em&gt;". I started from a core of health and fitness and moved on to more and more social challenges.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Sun, 24 Jan 2016 11:49:07 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2016/1/24/what-would-you-do-6-months/</guid><category>personal development</category><content:encoded>


            &lt;div class="post-924 post hentry" id="post-924"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;January 24th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c924.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;In the first months of 2015 I realized that I was burned out. Work was fun, but it had expanded so much that it had taken over my entire life. Fergus O'Connell gives this definition of burnout: &lt;em&gt;you're at work, you're thinking about work, you're bringing work home with you, or you're cancelling other things so you can work&lt;/em&gt;. Open and shut case, Johnson.&lt;/p&gt;
&lt;p&gt;I decided it was time to change, everything. It was my very own "&lt;em&gt;everything stops!&lt;/em&gt;" moment. I would leave my job in June and take a six month break from work. From all work to no work. The cover story was "sabbatical", but the working title was "life improvement project".&lt;/p&gt;
&lt;p&gt;And it has been the most liberating time of my life. There was much planning and project management involved - I'll spare you that. Here are the milestones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Health&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lost weight.&lt;/li&gt;
&lt;li&gt;Experimented with the paleo diet.&lt;/li&gt;
&lt;li&gt;Saw a physical therapist.&lt;/li&gt;
&lt;li&gt;Saw a psychologist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Sports&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Swam in the pool.&lt;/li&gt;
&lt;li&gt;Biked intercity road trips.&lt;/li&gt;
&lt;li&gt;Practiced yoga.&lt;/li&gt;
&lt;li&gt;Practiced strength training.&lt;/li&gt;
&lt;li&gt;Went running. Ran a 10km distance. Ran a 5km race.&lt;/li&gt;
&lt;li&gt;Practiced interval training.&lt;/li&gt;
&lt;li&gt;Played football.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Social&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Saw friends.&lt;/li&gt;
&lt;li&gt;Attended a Devnology weekend.&lt;/li&gt;
&lt;li&gt;Gave pitches for Django Girls to recruit coaches and participants.&lt;/li&gt;
&lt;li&gt;Took an improv class.&lt;/li&gt;
&lt;li&gt;Took part in a theater workshop.&lt;/li&gt;
&lt;li&gt;Hosted a friend for a long weekend.&lt;/li&gt;
&lt;li&gt;Practiced speed dating.&lt;/li&gt;
&lt;li&gt;Went on normal speed dates.&lt;/li&gt;
&lt;li&gt;Attended my best friend's wedding.&lt;/li&gt;
&lt;li&gt;Frequented 24 different social groups.&lt;/li&gt;
&lt;li&gt;Attended 36 social events in total.&lt;/li&gt;
&lt;li&gt;Met more new people than I've ever done before in 6 months.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Travel&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To Dublin for a job interview.&lt;/li&gt;
&lt;li&gt;To Friesland for Devnology weekend.&lt;/li&gt;
&lt;li&gt;To Groningen for Django Girls.&lt;/li&gt;
&lt;li&gt;To Bordeaux for Django Girls.&lt;/li&gt;
&lt;li&gt;To Rome for Django Girls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Language study&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Had Skype sessions with Dutch tutors.&lt;/li&gt;
&lt;li&gt;Completed a Portuguese course.&lt;/li&gt;
&lt;li&gt;Attended language café meetups.&lt;/li&gt;
&lt;li&gt;Read books in Portuguese.&lt;/li&gt;
&lt;li&gt;Made polyglot-ish Youtube videos.&lt;/li&gt;
&lt;li&gt;Wrote polyglot-ish blog entries.&lt;/li&gt;
&lt;li&gt;Coached in French at Django Girls.&lt;/li&gt;
&lt;li&gt;Coached in Italian at Django Girls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technology&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Studied x86 assembly.&lt;/li&gt;
&lt;li&gt;Read about computer architecture.&lt;/li&gt;
&lt;li&gt;Learned some Prolog.&lt;/li&gt;
&lt;li&gt;Wrote a memcached clone in Rust.&lt;/li&gt;
&lt;li&gt;Read computer science papers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Community work / Volunteering&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coached at three Django Girls events.&lt;/li&gt;
&lt;li&gt;Taught a basic computer course at a community center.&lt;/li&gt;
&lt;li&gt;Worked on organizing Django Girls Den Haag.&lt;/li&gt;
&lt;li&gt;Submitted a talk proposal to PyCon Italia.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Career / Work&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reached out for career advice to my network.&lt;/li&gt;
&lt;li&gt;Spoke to a lot of recruiters.&lt;/li&gt;
&lt;li&gt;Interviewed with a lot of different companies, local and remote. Turned down many offers.&lt;/li&gt;
&lt;li&gt;Applied for positions I wasn't qualified for. Was turned down.&lt;/li&gt;
&lt;li&gt;Finally found the kind of companies that I was after. Accepted an offer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many of these were a first. Over time there has been a conscious trend from "&lt;em&gt;things I do at home alone (in my pyjamas)&lt;/em&gt;" to "&lt;em&gt;things I do with others&lt;/em&gt;". I started from a core of health and fitness and moved on to more and more social challenges.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c924.png" media="image"><media:title type="html">C924</media:title></media:content></item><item><title>two weeks of rust</title><link>http://www.matusiak.eu/numerodix/blog/2016/1/10/two-weeks-rust/</link><description>


            &lt;div class="post-927 post hentry" id="post-927"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;January 10th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c927.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;Disclaimer: &lt;em&gt;I'm digging Rust. I lost my hunger for programming from doing too many sad commercial projects. And now it's back. You rock, Rust!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I spent about two weeks over the Christmas/New Year break hacking on &lt;a href="https://github.com/numerodix/emcache"&gt;emcache&lt;/a&gt;, a memcached clone in Rust. Why a memcached clone? Because it's a simple protocol that I understand and is not too much work to implement. It turns out I was in for a really fun time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPSIDES&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The build system and the package manager&lt;/strong&gt; is one of the best parts of Rust. How often do you hear that about a language? In Python I try to avoid even having dependencies if I can, and only use the standard library. I don't want my users to have to deal with virtualenv and pip if they don't have to (especially if they're not pythonistas). In Rust you "cargo build". One step, all your dependencies are fetched, built, and your application with it. No special cases, no build scripts, no surprising behavior *whatsoever*. That's it. You "cargo test". And you "cargo build --release" which makes your program 2x faster (did I mention that llvm is pretty cool?)&lt;/p&gt;
&lt;p&gt;Rust *feels* &lt;strong&gt;ergonomic&lt;/strong&gt;. That's the best word I can think of. With every other statically compiled language I've ever used too much of my focus was being constantly diverted from what I was trying to accomplish to annoying little busy work the compiler kept bugging me about. For me Rust is the first statically typed language I enjoy using. Indeed, &lt;strong&gt;ergonomics is a feature&lt;/strong&gt; in Rust - RFCs talk about it a lot. And that's important, since no matter how cool your ideas for language features are you want to make sure people can use them without having to jump through a lot of hoops.&lt;/p&gt;
&lt;p&gt;Rust aims to be &lt;strong&gt;concise&lt;/strong&gt;. Function is &lt;em&gt;fn&lt;/em&gt;, public is &lt;em&gt;pub&lt;/em&gt;, vector is &lt;em&gt;vec&lt;/em&gt;, you can figure it out. You can never win a discussion about conciseness because something will always be too long for someone while being too short for someone else. Do you want &lt;em&gt;u64&lt;/em&gt; or do you want &lt;em&gt;WholeNumberWithoutPlusOrMinusSignThatFitsIn64Bits&lt;/em&gt;? The point is Rust is concise and typeable, it doesn't require so much code that you need an IDE to help you type some of it.&lt;/p&gt;
&lt;p&gt;Furthermore, it feels very &lt;strong&gt;composable&lt;/strong&gt;. As in: the things you make seem to fit together well. That's a rare quality in languages, and almost never happens to me on a first project in a new language. The design of emcache is actually nicely &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/doc/Architecture.md"&gt;decoupled&lt;/a&gt;, and it just got that way on the first try. All of the components are fully unit tested, even the transport that reads/writes bytes to/from a socket. All I had to do for that is implement a TestStream that implements the traits &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/testlib/test_stream.rs#L90"&gt;Read&lt;/a&gt; and &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/testlib/test_stream.rs#L100"&gt;Write&lt;/a&gt; (basically one method each) and swap it in for a TcpStream. How come? Because the components provided by the stdlib *do* compose that well.&lt;/p&gt;
&lt;p&gt;But there is no &lt;strong&gt;object system&lt;/strong&gt;! Well, structs and impls basically give you something close enough that you can do OO modeling anyway. It turns out you can even do a certain amount of dynamic dispatch with trait objects, but that's something I read up on after the fact. The one thing that is incredibly strict in Rust, though, is &lt;strong&gt;ownership&lt;/strong&gt;, so when you design your objects (let's just call them them that, I don't know what else to call them) you need to decide right away whether an object that stores another object will own or borrow that object. If you borrow you need to use lifetimes and it gets a bit complicated.&lt;/p&gt;
&lt;p&gt;Parallelism in emcache is achieved using threads and &lt;strong&gt;channels&lt;/strong&gt;. Think one very fast storage and multiple slow transports. Channels are async, which is exactly what I want in this scenario. Like in Scala, when you send a value over a channel you don't actually "send" anything, it's one big shared memory space and you just transfer ownership of an immutable value in memory while invalidating the pointer on the "sending" side (which probably can be optimized away completely). In practice, channels require a little &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/orchestrator/typedefs.rs#L10"&gt;typedefing&lt;/a&gt; overhead so you can keep things clear, especially when you're sending channels over channels. Otherwise I tend to get lost in what goes where. (If you've done Erlang/OTP you know that whole dance of a tuple in a tuple in a tuple, like that Inception movie.) But this case stands out as atypical in a language where boilerplate is rarely needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Macros&lt;/strong&gt;. I bet you expected these to be on the list. To be honest, I don't have strong feelings about Rust's macros. I don't think of them as a unit of design (Rust is not a lisp), that's what traits are for. Macros are more like an escape hatch for &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/driver.rs#L35"&gt;unpleasant situations&lt;/a&gt;. They are powerful and mostly nice, but they have some weird effects too in terms of module/crate visibility and how they make compiler error messages look (slightly more confusing I find).&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;learning resources&lt;/strong&gt; have become very good. &lt;a href="https://doc.rust-lang.org/book/"&gt;The Rust book&lt;/a&gt; is very well written, but I found it a tough read at first. Start with &lt;a href="http://rustbyexample.com/"&gt;Rust by example&lt;/a&gt;, it's great. Then do some hacking and come back to "the book", it makes total sense to me now.&lt;/p&gt;
&lt;p&gt;No segfaults, no uninitialized memory, no coercion bugs, no data races, no null pointers, no header files, no makefiles, no autoconf, no cmake, no gdb. What if all the problems of c/c++ were fixed with one swing of a magic wand? The future is here, people.&lt;/p&gt;
&lt;p&gt;Finally, Rust *feels* &lt;strong&gt;productive&lt;/strong&gt;. In every statically compiled language I feel I would go way faster in Python. In Rust I'm not so sure. It's concise, it's typeable and it's composable. It doesn't force me to make irrelevant nit picky decisions that I will later have to spend tons of time refactoring to recover from. And productivity is a sure way to happiness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DOWNSIDES&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;standard library&lt;/strong&gt; is rather small, and you will need to go elsewhere even for certain pretty simple things like random numbers or a buffered stream. The good news is that Rust's &lt;a href="https://crates.io/"&gt;crates ecosystem&lt;/a&gt; has already grown quite large and there seem to be crates for many of these things, some even being incubated to join the standard library later on.&lt;/p&gt;
&lt;p&gt;While trying to be concise, Rust is still &lt;strong&gt;a bit wordy and syntax heavy&lt;/strong&gt; with all the pointer types and explicit casts that you see in typical &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/driver.rs#L162"&gt;code&lt;/a&gt;. So it's not *that easy* to read, but I feel once you grasp the concepts it does begin to feel very logical. I sure wouldn't mind my &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/tests.rs#L728"&gt;tests&lt;/a&gt; looking a bit &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/pyemc/test_integration.py#L408"&gt;simpler&lt;/a&gt; - maybe it's just my lack of Rust foo still.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;borrow checker&lt;/strong&gt; is tough, everyone's saying this. I keep running into cases where I need to load a value, do a check on it, and then make a decision to modify or not. Problem is the load requires a borrow, and then another borrow is used in the check, which is enough to break the rules. So far I haven't come across a case I absolutely couldn't work around with scopes and shuffling code around, but I wouldn't call it fun - nor is the &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/driver.rs#L345"&gt;resulting code&lt;/a&gt; very nice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Closures&lt;/strong&gt; are difficult. In your run-of-the-mill language I would say "put these lines in a closure, I'll run them later and don't worry your pretty little head about it". Not so in Rust because of move semantics and borrowing. I was trying to solve this problem: how do I &lt;a href="https://github.com/numerodix/emcache/blob/da7b6ca93f9bb7248ea47a7e2850a9ca8af86eac/src/metrics/recorder.rs#L31"&gt;wrap&lt;/a&gt; (in a minimally intrusive way) an arbitrary set of statements so that I can &lt;a href="https://github.com/numerodix/emcache/blob/da7b6ca93f9bb7248ea47a7e2850a9ca8af86eac/src/orchestrator/transport_task.rs#L78"&gt;time&lt;/a&gt; their execution (in Python this would be a context manager)? This would be code that might mutate self, refers to local vars (which could be used again after the closure), returns a value and so on. It appears tricky to solve in the general case, still haven't cracked it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;*mut T&lt;/strong&gt; is tricky. I was trying to build my own LRU map (before I knew there was a crate for it), and given Rust's lifetime rules you can't do circular references in normal safe Rust. One thing *has to* outlive another in Rust's lifetime model. So I started hacking together a linked list using *mut T (as you would) and I realized things weren't pointing to where I thought they were &lt;a href="https://github.com/numerodix/emcache/blob/f2f9369d7b96713d524a13ab812c0312daf70b11/src/storage/linked_list.rs#L123"&gt;at all&lt;/a&gt;. I still don't know what happened.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;builder pattern&lt;/strong&gt;. This is an ugly corner of Rust. Yeah, I get that things like varargs and keyword arguments have a runtime overhead. But the builder pattern, which is to say writing a completely separate struct just for the sake of constructing another struct, is pure boilerplate, it's so un-Rust. Maybe we can derive these someday?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code coverage&lt;/strong&gt;. There will probably be a native solution for this at some point. For now people use a workaround with &lt;a href="https://users.rust-lang.org/t/tutorial-how-to-collect-test-coverages-for-rust-project/650"&gt;kcov&lt;/a&gt;, which just &lt;a href="https://gist.github.com/numerodix/ed4335b4fd08dbd2fd6b"&gt;didn't work at all&lt;/a&gt; on my code. Maybe it's because I'm on nightly? &lt;a href="https://twitter.com/hauleth/status/686532939761451008"&gt;Fixed&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;So there you have it. Rust is a fun language to use, and it feels like an incredibly well designed language. Language design is really hard, and sometimes you succeed.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</description><pubDate>Sun, 10 Jan 2016 11:53:40 +0000</pubDate><guid>http://www.matusiak.eu/numerodix/blog/2016/1/10/two-weeks-rust/</guid><category>code</category><content:encoded>


            &lt;div class="post-927 post hentry" id="post-927"&gt;
                
                &lt;img title="inglés" class="post_lang_flag" src="http://www.matusiak.eu/static/languages/england.png"&gt; &lt;small&gt;January 10th, 2016&lt;/small&gt;

                
                                 
                &lt;img src="http://www.matusiak.eu/numerodix/blog/c927.png" style="display: none;"&gt;
            
 
                    &lt;div class="entry"&gt;
                        &lt;p&gt;Disclaimer: &lt;em&gt;I'm digging Rust. I lost my hunger for programming from doing too many sad commercial projects. And now it's back. You rock, Rust!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I spent about two weeks over the Christmas/New Year break hacking on &lt;a href="https://github.com/numerodix/emcache"&gt;emcache&lt;/a&gt;, a memcached clone in Rust. Why a memcached clone? Because it's a simple protocol that I understand and is not too much work to implement. It turns out I was in for a really fun time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;UPSIDES&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The build system and the package manager&lt;/strong&gt; is one of the best parts of Rust. How often do you hear that about a language? In Python I try to avoid even having dependencies if I can, and only use the standard library. I don't want my users to have to deal with virtualenv and pip if they don't have to (especially if they're not pythonistas). In Rust you "cargo build". One step, all your dependencies are fetched, built, and your application with it. No special cases, no build scripts, no surprising behavior *whatsoever*. That's it. You "cargo test". And you "cargo build --release" which makes your program 2x faster (did I mention that llvm is pretty cool?)&lt;/p&gt;
&lt;p&gt;Rust *feels* &lt;strong&gt;ergonomic&lt;/strong&gt;. That's the best word I can think of. With every other statically compiled language I've ever used too much of my focus was being constantly diverted from what I was trying to accomplish to annoying little busy work the compiler kept bugging me about. For me Rust is the first statically typed language I enjoy using. Indeed, &lt;strong&gt;ergonomics is a feature&lt;/strong&gt; in Rust - RFCs talk about it a lot. And that's important, since no matter how cool your ideas for language features are you want to make sure people can use them without having to jump through a lot of hoops.&lt;/p&gt;
&lt;p&gt;Rust aims to be &lt;strong&gt;concise&lt;/strong&gt;. Function is &lt;em&gt;fn&lt;/em&gt;, public is &lt;em&gt;pub&lt;/em&gt;, vector is &lt;em&gt;vec&lt;/em&gt;, you can figure it out. You can never win a discussion about conciseness because something will always be too long for someone while being too short for someone else. Do you want &lt;em&gt;u64&lt;/em&gt; or do you want &lt;em&gt;WholeNumberWithoutPlusOrMinusSignThatFitsIn64Bits&lt;/em&gt;? The point is Rust is concise and typeable, it doesn't require so much code that you need an IDE to help you type some of it.&lt;/p&gt;
&lt;p&gt;Furthermore, it feels very &lt;strong&gt;composable&lt;/strong&gt;. As in: the things you make seem to fit together well. That's a rare quality in languages, and almost never happens to me on a first project in a new language. The design of emcache is actually nicely &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/doc/Architecture.md"&gt;decoupled&lt;/a&gt;, and it just got that way on the first try. All of the components are fully unit tested, even the transport that reads/writes bytes to/from a socket. All I had to do for that is implement a TestStream that implements the traits &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/testlib/test_stream.rs#L90"&gt;Read&lt;/a&gt; and &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/testlib/test_stream.rs#L100"&gt;Write&lt;/a&gt; (basically one method each) and swap it in for a TcpStream. How come? Because the components provided by the stdlib *do* compose that well.&lt;/p&gt;
&lt;p&gt;But there is no &lt;strong&gt;object system&lt;/strong&gt;! Well, structs and impls basically give you something close enough that you can do OO modeling anyway. It turns out you can even do a certain amount of dynamic dispatch with trait objects, but that's something I read up on after the fact. The one thing that is incredibly strict in Rust, though, is &lt;strong&gt;ownership&lt;/strong&gt;, so when you design your objects (let's just call them them that, I don't know what else to call them) you need to decide right away whether an object that stores another object will own or borrow that object. If you borrow you need to use lifetimes and it gets a bit complicated.&lt;/p&gt;
&lt;p&gt;Parallelism in emcache is achieved using threads and &lt;strong&gt;channels&lt;/strong&gt;. Think one very fast storage and multiple slow transports. Channels are async, which is exactly what I want in this scenario. Like in Scala, when you send a value over a channel you don't actually "send" anything, it's one big shared memory space and you just transfer ownership of an immutable value in memory while invalidating the pointer on the "sending" side (which probably can be optimized away completely). In practice, channels require a little &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/orchestrator/typedefs.rs#L10"&gt;typedefing&lt;/a&gt; overhead so you can keep things clear, especially when you're sending channels over channels. Otherwise I tend to get lost in what goes where. (If you've done Erlang/OTP you know that whole dance of a tuple in a tuple in a tuple, like that Inception movie.) But this case stands out as atypical in a language where boilerplate is rarely needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Macros&lt;/strong&gt;. I bet you expected these to be on the list. To be honest, I don't have strong feelings about Rust's macros. I don't think of them as a unit of design (Rust is not a lisp), that's what traits are for. Macros are more like an escape hatch for &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/driver.rs#L35"&gt;unpleasant situations&lt;/a&gt;. They are powerful and mostly nice, but they have some weird effects too in terms of module/crate visibility and how they make compiler error messages look (slightly more confusing I find).&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;learning resources&lt;/strong&gt; have become very good. &lt;a href="https://doc.rust-lang.org/book/"&gt;The Rust book&lt;/a&gt; is very well written, but I found it a tough read at first. Start with &lt;a href="http://rustbyexample.com/"&gt;Rust by example&lt;/a&gt;, it's great. Then do some hacking and come back to "the book", it makes total sense to me now.&lt;/p&gt;
&lt;p&gt;No segfaults, no uninitialized memory, no coercion bugs, no data races, no null pointers, no header files, no makefiles, no autoconf, no cmake, no gdb. What if all the problems of c/c++ were fixed with one swing of a magic wand? The future is here, people.&lt;/p&gt;
&lt;p&gt;Finally, Rust *feels* &lt;strong&gt;productive&lt;/strong&gt;. In every statically compiled language I feel I would go way faster in Python. In Rust I'm not so sure. It's concise, it's typeable and it's composable. It doesn't force me to make irrelevant nit picky decisions that I will later have to spend tons of time refactoring to recover from. And productivity is a sure way to happiness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DOWNSIDES&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;standard library&lt;/strong&gt; is rather small, and you will need to go elsewhere even for certain pretty simple things like random numbers or a buffered stream. The good news is that Rust's &lt;a href="https://crates.io/"&gt;crates ecosystem&lt;/a&gt; has already grown quite large and there seem to be crates for many of these things, some even being incubated to join the standard library later on.&lt;/p&gt;
&lt;p&gt;While trying to be concise, Rust is still &lt;strong&gt;a bit wordy and syntax heavy&lt;/strong&gt; with all the pointer types and explicit casts that you see in typical &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/driver.rs#L162"&gt;code&lt;/a&gt;. So it's not *that easy* to read, but I feel once you grasp the concepts it does begin to feel very logical. I sure wouldn't mind my &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/tests.rs#L728"&gt;tests&lt;/a&gt; looking a bit &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/pyemc/test_integration.py#L408"&gt;simpler&lt;/a&gt; - maybe it's just my lack of Rust foo still.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;borrow checker&lt;/strong&gt; is tough, everyone's saying this. I keep running into cases where I need to load a value, do a check on it, and then make a decision to modify or not. Problem is the load requires a borrow, and then another borrow is used in the check, which is enough to break the rules. So far I haven't come across a case I absolutely couldn't work around with scopes and shuffling code around, but I wouldn't call it fun - nor is the &lt;a href="https://github.com/numerodix/emcache/blob/dd8d72d5c27781345a8288f85d2da3f45e4398d3/src/protocol/driver.rs#L345"&gt;resulting code&lt;/a&gt; very nice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Closures&lt;/strong&gt; are difficult. In your run-of-the-mill language I would say "put these lines in a closure, I'll run them later and don't worry your pretty little head about it". Not so in Rust because of move semantics and borrowing. I was trying to solve this problem: how do I &lt;a href="https://github.com/numerodix/emcache/blob/da7b6ca93f9bb7248ea47a7e2850a9ca8af86eac/src/metrics/recorder.rs#L31"&gt;wrap&lt;/a&gt; (in a minimally intrusive way) an arbitrary set of statements so that I can &lt;a href="https://github.com/numerodix/emcache/blob/da7b6ca93f9bb7248ea47a7e2850a9ca8af86eac/src/orchestrator/transport_task.rs#L78"&gt;time&lt;/a&gt; their execution (in Python this would be a context manager)? This would be code that might mutate self, refers to local vars (which could be used again after the closure), returns a value and so on. It appears tricky to solve in the general case, still haven't cracked it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;*mut T&lt;/strong&gt; is tricky. I was trying to build my own LRU map (before I knew there was a crate for it), and given Rust's lifetime rules you can't do circular references in normal safe Rust. One thing *has to* outlive another in Rust's lifetime model. So I started hacking together a linked list using *mut T (as you would) and I realized things weren't pointing to where I thought they were &lt;a href="https://github.com/numerodix/emcache/blob/f2f9369d7b96713d524a13ab812c0312daf70b11/src/storage/linked_list.rs#L123"&gt;at all&lt;/a&gt;. I still don't know what happened.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;builder pattern&lt;/strong&gt;. This is an ugly corner of Rust. Yeah, I get that things like varargs and keyword arguments have a runtime overhead. But the builder pattern, which is to say writing a completely separate struct just for the sake of constructing another struct, is pure boilerplate, it's so un-Rust. Maybe we can derive these someday?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Code coverage&lt;/strong&gt;. There will probably be a native solution for this at some point. For now people use a workaround with &lt;a href="https://users.rust-lang.org/t/tutorial-how-to-collect-test-coverages-for-rust-project/650"&gt;kcov&lt;/a&gt;, which just &lt;a href="https://gist.github.com/numerodix/ed4335b4fd08dbd2fd6b"&gt;didn't work at all&lt;/a&gt; on my code. Maybe it's because I'm on nightly? &lt;a href="https://twitter.com/hauleth/status/686532939761451008"&gt;Fixed&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;So there you have it. Rust is a fun language to use, and it feels like an incredibly well designed language. Language design is really hard, and sometimes you succeed.&lt;/p&gt;

                    &lt;/div&gt;
                

                
            &lt;/div&gt;


            
</content:encoded><media:content url="http://www.matusiak.eu/static/languages/england.png" media="image"><media:title type="html">England</media:title></media:content><media:content url="http://www.matusiak.eu/numerodix/blog/c927.png" media="image"><media:title type="html">C927</media:title></media:content></item></channel></rss>