/** Executed when the I/O has completed */
    @Override
    @SuppressWarnings("unchecked")
    public void completed(int bytesTransferred, boolean canInvokeDirect) {
      if (bytesTransferred == 0) {
        bytesTransferred = -1; // EOF
      } else {
        updateBuffers(bytesTransferred);
      }

      // return direct buffer to cache if substituted
      releaseBuffers();

      // release waiters if not already released by timeout
      synchronized (result) {
        if (result.isDone()) return;
        enableReading();
        if (scatteringRead) {
          result.setResult((V) Long.valueOf(bytesTransferred));
        } else {
          result.setResult((V) Integer.valueOf(bytesTransferred));
        }
      }
      if (canInvokeDirect) {
        Invoker.invokeUnchecked(result);
      } else {
        Invoker.invoke(result);
      }
    }
    /** Invoked if timeout expires before it is cancelled */
    void timeout() {
      // synchronize on result as the I/O could complete/fail
      synchronized (result) {
        if (result.isDone()) return;

        // kill further writing before releasing waiters
        enableWriting(true);
        result.setFailure(new InterruptedByTimeoutException());
      }

      // invoke handler without any locks
      Invoker.invoke(result);
    }
    @Override
    public void failed(int error, IOException x) {
      // return direct buffer to cache if substituted
      releaseBuffers();

      // release waiters if not already released by timeout
      if (!isOpen()) x = new AsynchronousCloseException();

      synchronized (result) {
        if (result.isDone()) return;
        enableWriting();
        result.setFailure(x);
      }
      Invoker.invoke(result);
    }