Tuesday, February 12, 2008

File system change monitoring on Mac OS X

I previously blogged about File system change monitoring on Windows and Linux. I have now implemented this feature on Mac OS X as well, using the new FSEventStream API in Leopard.

This API differs a bit from the ones found on Windows (ReadDirectoryChanges) and Linux (inotify) in three ways:
  • The main difference is that it is callback-based; instead of reading changes from a file descriptor, you register a callback which is invoked when directories change.
  • The second is that this callback runs as part of the event loop. This means that on Mac OS X, you can only file system change notification if you are running the UI. I might get around this restriction by always having a Core Foundation run loop going if either the UI is running or monitors are being used; for since monitors are mostly useful for developer and end-user tools, and not server-side software, this is not a high priority.
  • The third difference is that the change notifications are not as precise as the other platforms. They only tell you which directory changed, not which file, and furthermore there is no notification of what changed (file added, file removed, etc.)

Despite these differences I managed to implement a backend for the same io.monitors API without any difficulties. In particular, inverting the callback based approach and turning it into a stream of events was easy using continuations.

This is a milestone for Factor; file system change notification was one of my goals for Factor 1.0. Doug and I first discussed it at FactorCon summer 2007 and now its implemented. Sun is talking about adding this to Java 7 but we already have it.

Update: a number of people have pointed out that the core foundation run loop code is independent of the OS X WindowServer, and that it is possible to use run loops even in a command line application.

1 comment:

Anonymous said...

I think you're being a bit disingenuous with the event loop comment. You need to have a run loop running, which any thread can do. In fact, every NSThread has one by default, it's just that only the main thread starts its automatically.

At no point must you be accepting events from the window server, so there is no dependency on the GUI.