Developing modules for the Linux Kernel has previously been a difficult discipline to even get started in, but as time has passed it’s become a more approachable and accessible topic. In today’s post, I’m going to go through
How to setup your build environment
Writing the code for a simple module
Building your module
Adding and removing your module from the Kernel
There are a lot of different sources on the internet that have this information and the best reference that I can suggest is on the LDP which is here.
We’ve got a bit to cover, so let’s get started. One last thing though, I’m running Arch Linux to write this tutorial however everything that I’m writing about here should be directly translatable into your distribution of choice.
Setting up your build environment
You need to put your system into a state where you’re able to build kernel modules, and you’ll do this with the linux-headers package from your distribution’s package manager.
sudo pacman -S linux-headers
Once this has installed, you’ll find a build environment has been made under /lib/modules/ on your system. You’ll also have all of the development files required to include in your modules.
The code
First up, just a couple of requirements. We’re going to print a kernel message using printk when the module is initialised and we’ll print another when the module has been unloaded. Pretty unimaginative but it’ll be great for the sake of demonstration.
Here’s the code:
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>MODULE_LICENSE("GPL");MODULE_AUTHOR("Michael Tuttle");MODULE_DESCRIPTION("A useless module for demonstration purposes");/** Initialises our module into the kernel */staticint__initmessage_init(void){printk(KERN_INFO"Module has been loaded");return0;}/** Unloads our module from the kernel */staticvoid__exitmessage_exit(void){printk(KERN_INFO"Module has been unloaded");}module_init(message_init);module_exit(message_exit);
That’s it for the code. It’s pretty easy to follow. You can see that message_init is what will be called when our module is loaded and message_exit when unloaded. Traditionally these were called init_module and cleanup_module respectively but these names are allowed to change due to the use of the __init, module_init, __exit and module_exit macros.
printk is what we’ll use to send some text into the kernel messages. You retrieve these with the dmesg shell command.
Building your module
The Makefile for this module is actually quite simple, but requires a little explanation.
obj-m += msg.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Quite simple in the end, but cryptic if you haven’t come across some of it before. The obj-m directive tells the make system that we want a kernel module. obj-d can be used here when we’re making a driver.
The make targets are executed against the build environment we installed above. -C tells make to issue its instructions in the folder given.
After compiling your module, you’re ready to see it in action.
Adding and Removing your module
To get your kernel to start using your module, you issue insmod against the .ko file that has been built for you.
$ sudo insmod msg.ko
The kernel now should have loaded your module and you should be able to confirm that it’s loaded by checking dmesg:
$ dmesg
. . .
. . .
. . .
[ 3320.686668] Module has been loaded
Of course there’s an easier way to check that it’s loaded. You can see a list of all the loaded modules in your kernel by issuing lsmod.
$ lsmod
Module Size Used by
msg 825 0
........ .
The first half has gone to plan. To unload this module, we now use rmmod.
$ sudo rmmod msg.ko
Now that the module has been removed, we should see the leaving message in the output of dmesg.
$ dmesg
. . .
. . .
. . .
[ 3641.668948] Module has been unloaded
You can do little bits and pieces in your Haskell code to take it from an imperative looking style to being more concise and monadic in your approach. In today’s post, I’m going to run through a small sample of functions that should help this process greatly.
One final thought is that it’s not so much the use of these functions that’s important; it’s more the change in thought process to put you in a position where these functions become effective is where the true power lies.
»=
The >>= function (pronounced “bind”) sequences operations together by passing the result of what’s on the left hand side, to the right hand side. >>= looks like this:
(>>=)::Monadm=>ma->(a->ma)->mb
>>= is asking for:
a which is a value wrapped in a monad
(a -> m a) which is a function accepting a value and returning a wrapped value
An example of this in action looks like this:
-- | Returns a string in context of a monadns::Monadm=>m[Char]ns=return$"Hello"-- | Prints a string to the consoleputStrLn::String->IO()-- Using bindns>>=putStrLn
What’s going on in the above snippet is that >>= has unwrapped the string returned by ns from its IO monad so that it’s just a string. >>= has then applied this raw value to putStrLn.
=«
The =<< function performs the same role as >>= only it has its parameters flipped.
putStrLn=<<ns
liftM
liftM allows you to promote a function to a monad. Here’s what it looks like
liftM::Monadm=>(a1->r)->ma1->mr
(a1 -> r) is what will get lifted into the monad, so we can keep our code that does work free of any monad awareness.
Where I have found that this is useful is when you have a set of functions that don’t operate on wrapped values, and you’d like to sequence them monadically.
My initial attempts to do this look like this:
-- | Collects all of the successfully read contents of-- of the read files into an array of targetsallContents::[String]->IO[Target]allContentspaths=dors<-safeReadFilesletcs=mapparseSentinelFile(catMaybesrs)return$concat$rightscswheresafeReadFiles=mapMsafeReadFilepaths
This reads like a big blob of imperative glug! So, I thought that all of these pieces could be sequenced together and chained with >>=. Here’s what I got:
Well, at least the code is sequenced - but all of those returns sure are annoying. Here’s where liftM comes in. With liftM, we can compose all of those functions without needing to know anything about the monad that it’s executing in. Here’s what I’ve ended up with:
liftM has allowed us to express our function chain using . as function composition. liftM then handles all of the monadness for us!
»
The >> function performs he same sequencing as what >>= does, only the first action specified is discarded. >> looks like this:
(>>)::Monadm=>ma->mb->mb
This particular function comes in handy where you’re interested in not passing along a result from certain links in your sequencing chain, like this:
putStrLn"Hello. What is your name? ">>getLine>>=putStr>>putStrLn"! That's a great name"
From this particular sequence, you can see that
The action emitted from the first putStrLn is dropped
The action emitted from getLine is passed onto putStr
The action emitted from putStr is dropped
The last action terminates the sequence
sequence
sequence will evaluate all of the actions passed to it from left to right and return out the results of these actions. It’s defined like this
sequence::Monadm=>[ma]->m[a]
What this allows you to do is something like this
sequence[putStr"What's your name? ">>getLine,putStr"What's your age? ">>getLine,putStr"What's your favourite colour? ">>getLine]
This will then give you back an array of the IO actions emitted from each array index.
sequence_ will perform the same task as what sequence does, only it’ll throw away the result.
mapM
mapM will allow you to perform a monadic action over a list of normal (or unwrapped) values. It looks like this
mapM::Monadm=>(a->mb)->[a]->m[b]
mapM wants:
A function that takes an unwrapped value a as its first parameter and returns a wrapped value m b
A list of unwrapped values [a]
It will then give you back a list of wrapped outputs m [b]. So, this allows you to do something like this
-- our list of unwrapped valuesletquestions=["What's your name? ","What's your age? "]-- print out each question and ask for a responsemapM(\q->putStrq>>getLine)questions
Also notice that in the lambda above (\q -> putStr q >> getLine), we’ve used the >> function from above as we don’t care for the action emitted from printing a string to the console.
mapM_ will perform the same task as what mapM does, only it’ll throw the result away.
filterM
filterM will filter a list based on a Bool wrapped in an action. Here’s how filterM is defined
filterM::Monadm=>(a->mBool)->[a]->m[a]
filterM will execute an action (a -> m Bool) that wants an a as its input and returns you a wrapped m Bool which will determine which a’s in the passed list [a] end up in the resulting wrapped list m [a]. Mouthful, I know. Here’s an example
filterM(\_->randomIO>>=return.even)[1..50]
The lambda here (\_ -> randomIO >>= return . even) actually ignores the input parameter by using \_. It’s using randomIO to grab a number out of the hat which is then bound to (return . even), which will return a wrapped Bool of if the number supplied by randomIO is even or not.
There’s heaps more that you can do. Just check out the Control.Monad namespace of the base library for some more. That’s it for today though!
Turning on spell check in vim is easy, you just enter the following command at the prompt:
:set spell spelllang=en_au
Of course you substitute in the language code that suits you. So, when you’re tired of all of the highlighting, you can easily turn it off like so:
:set nospell
I use vim for both general text editing (say, like the Markdown document for instance) as well as for code editing. I really don’t want spell checking on for code editing, so I’ve added the following block to my .vimrc to turn it on for Markdown documents only:
autocmd FileType mkd set spell spelllang=en_au
Finally, if you’ve got a word that you’ve spelt incorrectly and you’re stuck on fixing it - put your cursor over the word and hit z=. You’ll get a list of suggestions to help you!
I’ve just recently installed XMonad on my laptop and am just ironing out some issues that have popped up from time to time. Today, I’d noticed that XMonad had stopped responding to my mod key requests, however the focused application (in my case firefox) was still responding.
After doing some searching around the web, I’ve come across this article which has set me straight. It seems that a pipe that XMonad writes to is full - it just needs to be cleared.
First off, you’ll need to get yourelf to a terminal. If you’re unable to do that (like I was), I went to another virtual terminal all together by using alt+ctrl+f1.
In my case, it’s 1406. You need to take a look at this pid’s file descriptors:
$ ls-l /proc/1406/fd
total 0
lr-x------ 1 michael michael 64 Jun 18 14:10 0 -> /dev/null
lrwx------ 1 michael michael 64 Jun 18 14:10 1 -> socket:[17946]
lrwx------ 1 michael michael 64 Jun 18 14:10 2 -> socket:[17946]
l-wx------ 1 michael michael 64 Jun 18 14:10 3 -> /var/log/slim.log
lrwx------ 1 michael michael 64 Jun 18 14:10 4 -> socket:[18899]
l-wx------ 1 michael michael 64 Jun 18 14:10 5 -> pipe:[18898]
So, in my case here #5 which is the pipe - needs to be cleared. You can do so really quickly just by catting it to screen.
$ cat /proc/1406/fd
XMonad should now be back in the land of the living.
Finally, this should never be a problem just as long as your xmonad.hs is configured with a logHook that will pipe the contents of this stream out.