// 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();
        }
      }
    }