PE Haskell after part 1
This is part 1 of a series of Program Evolution in Haskell blog describing the various stages of developing a small program called after
.
Because I am still learning about Haskell, this Program Evolution series will describe all the faults and fixes I had to do to get a "complete" Haskell program solution.
Program introduction
The program is called after
and it's a very small script I'm converting to Haskell. The Bash version of the code is
#!/bin/bash
CMDPATTERN="$@"
if [[ -z "$CMDPATTERN" ]]; then
echo "Need command pattern as first argument"
exit 1
fi
echo -n "Waiting for PID(S): " `pgrep --full "$CMDPATTERN"`
while [[ "`pgrep --count --full "$CMDPATTERN"`" -gt 1 ]]; do
sleep 5
done
You can use this utility to block till another process is done. For example, when you started a compilation and decide to start compilation after that compilation is done, you could have compile everything
running in one console and run after compile everything; compile this
in another console.
Initial commit
The initial commit contains a simplified version of the real program.
Instead of waiting for a command, we wait for a process id (PID) by monitoring /proc
.
We started by using hinotify to check for changes on the /proc
directory. If a process is removed or added, we could check if our process is still running.
Because hinotify will call a handler function from another thread, we lock on an MVar
. This is done in After.hs:
module After where
import System.INotify
import Control.Concurrent
justShowAndUnlock :: MVar String -> Event -> IO()
justShowAndUnlock mvar event = do
putStrLn (show event)
putMVar mvar "Yep, this is happening"
afterPid :: String -> IO ()
afterPid pid = do
inotifyHandle <- initINotify
unockedAfter <- newEmptyMVar
watchHandle <- addWatch inotifyHandle [DeleteSelf, MoveSelf, OnlyDir] ("/proc/" ++ pid) (justShowAndUnlock unockedAfter)
seen <- takeMVar unockedAfter
putStrLn seen
The takeMVar
call will block as long as justShowAndUnlock
is not called.
The problem however is, that it is never called. Turns out you can not use inotify to monitor /proc
.
From man 7 inotify
:
Inotify reports only events that a user-space program triggers through the filesystem API. As a result, it does not catch remote events that occur on network filesystems. (Applications must fall back to polling the filesystem to catch such events.) Furthermore, various pseudo- filesystems such as /proc, /sys, and /dev/pts are not monitorable with inotify.
DOH! In the next part we will look at using a polling thread as an alternative to using inotify.
Update 2014-08-24: part 2 has been published.