Accelerating Haskell Application Development

A Google Summer of Code 2012 Project

A first attempt at file notifications for Windows

on May 30, 2012

For the last few days I’ve focused my attention on getting Windows file notifications working. Of course, this journey began with getting Haskell working on Windows, which I found surprisingly painless. I believe I only had one location that didn’t get added to my %PATH% variable that broke cabal-install actions, and otherwise the Haskell Platform downloaded and worked like a charm.

In the purely Haskell portion of Win32-notify (not to be confused with pure Haskell functions) I followed INotify’s design pattern to spawn two threads for each “directory watch”; one thread uses a foreign blocking I/O call to retrieve events as fast as possible and put them in a Haskell channel. The other thread reads from the channel and dispatches the associated handler. One nice thing about the Windows API is that it supports listening on an entire sub-tree of the directory structure so I didn’t have to implement recursive directory tracking myself like I did with INotify on Linux.

In working with the rather long-in-the-tooth Win32-notify package I’ve tried to avoid touching any code that uses the foreign function interface. I’ve succeeded, for the most part, so far.

I say for the most part because I added the interruptible qualifier to the foreign import after observing that my little test program would hang while quitting until one more file system event was received. The source of the problem was this: foreign imported functions (even safe foreign imports with -threaded enabled in GHC) aren’t interrupted from completing a blocking I/O call when a ThreadKilled exception is thrown at their thread. As a result, the thread recursively listening for events needed to finish its most recent I/O call before the thread would die.

I say for now because it appears that the current usage of the Windows file system API supports a modified event, but no write-close (or similar) event. This means that, for example, if I save a file in Emacs I get two modified events instead of one, which could be a problem if I kick of a compilation of a source file every time it is modified. I’m sure I’ll eventually be forced to address this issue, but I am happy to put off reading Windows API documentation for as long as possible.

Next up will be hooking into the existing Mac file watcher library. I’ve linked the github repositories where you can find my work below.