public BSDPathWatchService() { try { String propertyValue = System.getProperty( "name.pachler.io.file.BSDPathWatchService.pollingIntervalMillis", Long.toString(DEFAULT_POLLING_INTERVAL_MILLIS)); pollingIntervalMillis = Long.parseLong(propertyValue); } catch (Throwable t) { // ignore, pllingIntervalMillis will still have its default value. } open(); }
private WatchKey pollImpl(long timeout) throws InterruptedException, ClosedWatchServiceException { long lastStart = System.currentTimeMillis(); do { // if there is a timeout specified, count down timeout if (timeout != -1) { long currentTime = System.currentTimeMillis(); long lastDuration = currentTime - lastStart; timeout -= lastDuration; if (timeout < 0) timeout = 0; lastStart = currentTime; } kevent[] eventlist = new kevent[32]; // FIXME: this should be chosen depending on whether we need to // poll or not. long selectTimeout = timeout; if ((timeout == -1 || timeout > pollingIntervalMillis) && numKeysRequiringPolling > 0) selectTimeout = pollingIntervalMillis; int nread = 0; synchronized (changeLock) { // if we have pending watches, we're done and return the first one. if (pendingWatchKeys.size() > 0) return pendingWatchKeys.remove(); // check if watch key has been closed if (kqueuefd == -1) throw new ClosedWatchServiceException(); int[] readfds = {closePipeReadFd, kqueuefd}; int selectResult = select(readfds, null, null, selectTimeout); if (selectResult == -1) { // check for interruption if (BSD.errno() == BSD.EINTR) throw new InterruptedException(); // otherwise, this is another error that shouldn't occur // here. String message = BSD.strerror(BSD.errno()); try { close(); } finally { // the message string here is just for debugging throw new ClosedWatchServiceException(); } } if (readfds[0] == closePipeReadFd) { // we have been requested to release the changeLock continue; } // we know now that kevent() will not block, because select() told us so... if (readfds[1] == kqueuefd) nread = kevent(kqueuefd, null, eventlist, null); if (nread == -1) { if (nread == EINTR) throw new InterruptedException(); try { close(); } finally { // catch exception and throw ClosedWatchServiceException instead throw new ClosedWatchServiceException(); } } if (nread > 0) { // go through all kevent structures and update keys for (int i = 0; i < nread; ++i) { kevent e = eventlist[i]; int dirfd = (int) e.get_ident(); int fflags = e.get_fflags(); PollingPathWatchKey key = keys.get(dirfd); // in some cases, the key might not be there any more because // it was invalidated (and therefore cancelled) in response to // a previous kevent if (key == null) continue; boolean eventsAdded; // check if watch key has become invalid if ((fflags & NOTE_REVOKE) != 0) eventsAdded = cancelImpl(key, true); else { try { // poll key's directory eventsAdded = key.poll(); } catch (FileNotFoundException ex) { eventsAdded = cancelImpl(key, true); } } if (eventsAdded) queueKey(key); } } else if (numKeysRequiringPolling > 0) { // if we timed out and we have keys that need to be polled Set<Entry<Integer, PollingPathWatchKey>> entrySet = keys.entrySet(); Iterator<Entry<Integer, PollingPathWatchKey>> iterator = entrySet.iterator(); while (iterator.hasNext()) { Entry<Integer, PollingPathWatchKey> entry = iterator.next(); PollingPathWatchKey key = entry.getValue(); // only poll keys that have the modification flag set - // CREATE/DELETE are flagged in kevent if ((key.getFlags() & FLAG_FILTER_ENTRY_MODIFY) == 0) continue; boolean eventsAdded; try { eventsAdded = key.poll(); } catch (FileNotFoundException ex) { eventsAdded = cancelImpl(key, false); iterator.remove(); } if (eventsAdded) queueKey(key); } } // now check for pending watch keys again if (pendingWatchKeys.size() > 0) return pendingWatchKeys.remove(); } // synchronized(changeLock) } while (timeout > 0 || timeout == -1); return null; }