With these requirements in mind (and with the desire not to create a separate
monitoring thread per WatchService like on Windows), the solution was to
perform management on the inotify descriptor with the threads that call
into poll()/take() on a first comes first served basis:
The first thread calling into pollImpl() (called from poll()/take()) becomes
the master thread. It is the only thread at any given time that services
the inotify file descriptor by calling select() and read(). The thread
looses it's master thread status when it is done with calling select()
and read().
All other threads that call into pollImpl() simply call wait(). When the
master thread is done, it calls notify() to wake up the next thread, which
might then become the master thread.
Also note that select() waits on two file descriptors: Because select() does
not return when a file descriptor closes while it is waiting for it
(for reasons that elude me), a command pipe is used which receives commands
from other threads.
This is how close() is implemented: Instead of closing the inotify file descriptor
directly, it writes a command byte into the command pipe. If there is a
master thread, it wakes up, consumes the command byte and executes the
command (which is to close the inotify FD). If there is no master thread,
the thread calling close() closes the inotify file descriptor.
All this is necessary because a thread calling select() can't be interrupted,
and select() does not return when one of it's file descriptors is closed
while it is waiting for it
Methods inherited from class java.lang.Object |
clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
CMD_CLOSE
public static final byte CMD_CLOSE
- See Also:
- Constant Field Values
CMD_NOTIFY
public static final byte CMD_NOTIFY
- See Also:
- Constant Field Values
LinuxPathWatchService
public LinuxPathWatchService()
finalize
protected void finalize()
throws java.lang.Throwable
- Overrides:
finalize
in class java.lang.Object
- Throws:
java.lang.Throwable
take
public WatchKey take()
throws java.lang.InterruptedException
- Specified by:
take
in class WatchService
- Throws:
java.lang.InterruptedException
poll
public WatchKey poll()
throws java.lang.InterruptedException
- Specified by:
poll
in class WatchService
- Throws:
java.lang.InterruptedException
poll
public WatchKey poll(long timeout,
java.util.concurrent.TimeUnit unit)
throws java.lang.InterruptedException,
ClosedWatchServiceException
- Specified by:
poll
in class WatchService
- Throws:
java.lang.InterruptedException
ClosedWatchServiceException
close
public void close()
throws java.io.IOException
- Specified by:
close
in interface java.io.Closeable
- Specified by:
close
in class WatchService
- Throws:
java.io.IOException
register
public PathWatchKey register(Path path,
WatchEvent.Kind<?>[] kinds,
WatchEvent.Modifier[] modifiers)
throws java.io.IOException
- Specified by:
register
in class PathWatchService
- Throws:
java.io.IOException
reset
public boolean reset(PathWatchKey pathWatchKey)