@Override public synchronized void close() throws IOException { // request change lock byte[] b = new byte[1]; write(closePipeWriteFd, new byte[] {0}, 1); synchronized (changeLock) { // close all file descriptors BSD.close(kqueuefd); kqueuefd = -1; int nread = read(closePipeReadFd, b, 1); assert (nread == 1); BSD.close(closePipeReadFd); BSD.close(closePipeWriteFd); } }
@Override public synchronized PathWatchKey register(Path path, Kind<?>[] kinds, Modifier[] modifiers) throws IOException { PathImpl pathImpl = checkAndCastToPathImpl(path); int flags = makeFlagMask(kinds, modifiers); // check that user only provided supported flags and modifiers int supportedFlags = (FLAG_FILTER_ENTRY_CREATE | FLAG_FILTER_ENTRY_DELETE | FLAG_FILTER_ENTRY_MODIFY | FLAG_FILTER_KEY_INVALID); if ((flags & ~supportedFlags) != 0) throw new UnsupportedOperationException( "The given watch event kind or modifier is not supported by this WatchService"); String pathname = pathImpl.getFile().getAbsolutePath(); PollingPathWatchKey key = null; // request changeLock BSD.write(closePipeWriteFd, new byte[1], 1); synchronized (changeLock) { if (kqueuefd == -1) throw new ClosedWatchServiceException(); { Integer dirfdInteger = dirs.get(pathname); if (dirfdInteger != null) key = keys.get(dirfdInteger); } if (key == null) { // no directory file fd registered - we'll need to open // one now // create file descriptor and watch event first boolean success = false; int dirfd = -1; try { dirfd = BSD.open(pathname, BSD.O_RDONLY, 0); if (dirfd == -1) throw new IOException( "error registering the path with the native OS: " + strerror(errno())); kevent e = new kevent(); e.set_ident(dirfd); e.set_filter(EVFILT_VNODE); e.set_flags((short) (EV_ADD | EV_CLEAR)); e.set_fflags(NOTE_WRITE | NOTE_DELETE | NOTE_REVOKE); int result = kevent(kqueuefd, new kevent[] {e}, null, null); // do we need more specific error handling here? if (result != 0) throw new IOException( "error registering the path with the native OS: " + strerror(errno())); // create watch key and add it to the key and dirs maps key = new PollingPathWatchKey(this, path, 0); keys.put(dirfd, key); dirs.put(pathname, dirfd); } finally { // if something went wrong, close descriptors if (key == null) { if (dirfd != -1) { // if the descriptor has been added to the kqueue, // it will be removed automatically when the descriptor // closes. BSD.close(dirfd); } } } } if (key != null && key.getFlags() != flags) { // check if modification flag has changed; moddiff will // be +1 if the ENTRY_MODIFIED flag was added, -1 if // it was removed (and 0 if it didn't change) int moddiff = 0; moddiff += (flags & FLAG_FILTER_ENTRY_MODIFY) != 0 ? +1 : 0; moddiff += (key.getFlags() & FLAG_FILTER_ENTRY_MODIFY) != 0 ? -1 : 0; numKeysRequiringPolling += moddiff; key.setFlags(flags); } // retract request for change lock BSD.read(closePipeReadFd, new byte[1], 1); } // first poll to capture initial state key.poll(); return key; }