This is part 1 of a series of Program Evolution in Haskell blog describing the various stages of developing a small program called
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.
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.
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
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
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
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.