docs: @Override
      public long processSyncReadRequest(long numBytes, int timeout) throws IOException {
          long bytesRead = 0L;
          if (numBytes != 0L) {
              if (this.blockWait == null) {
                  this.blockWait = new SimpleSync();
              }
  
              this.blockingIOError = null;
  
              // before we read, signal that we want to do the read ourselves
              // and not the worker threads.
              this.blockedThread = true;
  
              VirtualConnection vc = readInternal(numBytes, null, false, timeout);
  
              while (vc == null) {
                  // block until we are told to read
                  this.blockWait.simpleWait();
  
                  if (this.blockingIOError == null) {
                      vc = ((NioTCPChannel) getTCPConnLink().getTCPChannel()).getWorkQueueManager().processWork(this, 1);
                  } else {
                      break;
                  }
              }
              this.blockedThread = false;
  
              if (this.blockingIOError != null) {
                  throw this.blockingIOError;
              }
              // return the number of bytes read
              bytesRead = getIOCompleteAmount();
          } else {
              // read immediately and return
              setJITAllocateAction(false);
  
              if ((getJITAllocateSize() > 0) && (getBuffers() == null)) {
                  // User wants us to allocate the buffer
                  if (getConfig().getAllocateBuffersDirect()) {
                      setBuffer(ChannelFrameworkFactory.getBufferManager().allocateDirect(getJITAllocateSize()));
                  } else {
                      setBuffer(ChannelFrameworkFactory.getBufferManager().allocate(getJITAllocateSize()));
                  }
                  setJITAllocateAction(true);
              }
              WsByteBuffer wsBuffArray[] = getBuffers();
              NioSocketIOChannel channel = (NioSocketIOChannel) getTCPConnLink().getSocketIOChannel();
              if (wsBuffArray.length == 1) {
                  bytesRead = channel.read(wsBuffArray[0].getWrappedByteBufferNonSafe());
              } else {
                  bytesRead = channel.read(getByteBufferArray());
              }
  
              if (bytesRead < 0) {
                  if (getJITAllocateAction()) {
                      getBuffer().release();
                      setBuffer(null);
                      setJITAllocateAction(false);
                  }
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) {
                      Tr.event(this, tc, "Sync read throwing IOException");
                  }
  
                  // Add local and remote address information
                  String s = "Read failed.  End of data reached.";
                  try {
                      SocketAddress iaLocal = getTCPConnLink().getSocketIOChannel().getSocket().getLocalSocketAddress();
                      SocketAddress iaRemote = getTCPConnLink().getSocketIOChannel().getSocket().getRemoteSocketAddress();
                      s = s + " local=" + iaLocal + " remote=" + iaRemote;
                  } catch (Exception x) {
                      // do not alter the message if the socket got nuked while we tried to look at it
                  }
                  throw new IOException(s);
              }
          }
          return bytesRead;
      }