// process events (list of FILE_NOTIFY_INFORMATION structures) private void processEvents(WindowsWatchKey key, int size) { long address = key.buffer().address(); int nextOffset; do { int action = UNSAFE.getInt(address + OFFSETOF_ACTION); // map action to event WatchEvent.Kind<?> kind = translateActionToEvent(action); if (key.events().contains(kind)) { // copy the name int nameLengthInBytes = UNSAFE.getInt(address + OFFSETOF_FILENAMELENGTH); if ((nameLengthInBytes % 2) != 0) { throw new AssertionError("FileNameLength is not a multiple of 2"); } char[] nameAsArray = new char[nameLengthInBytes / 2]; UNSAFE.copyMemory( null, address + OFFSETOF_FILENAME, nameAsArray, Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes); // create FileName and queue event WindowsPath name = WindowsPath.createFromNormalizedPath(fs, new String(nameAsArray)); key.signalEvent(kind, name); } // next event nextOffset = UNSAFE.getInt(address + OFFSETOF_NEXTENTRYOFFSET); address += (long) nextOffset; } while (nextOffset != 0); }
/** Poller main loop */ @Override public void run() { for (; ; ) { CompletionStatus info; try { info = GetQueuedCompletionStatus(port); } catch (WindowsException x) { // this should not happen x.printStackTrace(); return; } // wakeup if (info.completionKey() == WAKEUP_COMPLETION_KEY) { boolean shutdown = processRequests(); if (shutdown) { return; } continue; } // map completionKey to get WatchKey WindowsWatchKey key = ck2key.get((int) info.completionKey()); if (key == null) { // We get here when a registration is changed. In that case // the directory is closed which causes an event with the // old completion key. continue; } boolean criticalError = false; int errorCode = info.error(); int messageSize = info.bytesTransferred(); if (errorCode == ERROR_NOTIFY_ENUM_DIR) { // buffer overflow key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) { // ReadDirectoryChangesW failed criticalError = true; } else { // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case // [messageSize] is zero in the most of cases. if (messageSize > 0) { // process non-empty events. processEvents(key, messageSize); } else if (errorCode == 0) { // insufficient buffer size // not described, but can happen. key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } // start read for next batch of changes try { ReadDirectoryChangesW( key.handle(), key.buffer().address(), CHANGES_BUFFER_SIZE, key.watchSubtree(), ALL_FILE_NOTIFY_EVENTS, key.countAddress(), key.overlappedAddress()); } catch (WindowsException x) { // no choice but to cancel key criticalError = true; } } if (criticalError) { implCancelKey(key); key.signal(); } } }