code: func (ec *EpollConsole) Read(p []byte) (n int, err error) {
  	var read int
  	ec.readc.L.Lock()
  	defer ec.readc.L.Unlock()
  	for {
  		read, err = ec.Console.Read(p[n:])
  		n += read
  		if err != nil {
  			var hangup bool
  			if perr, ok := err.(*os.PathError); ok {
  				hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
  			} else {
  				hangup = (err == unix.EAGAIN || err == unix.EIO)
  			}
  			// if the other end disappear, assume this is temporary and wait for the
  			// signal to continue again. Unless we didnt read anything and the
  			// console is already marked as closed then we should exit
  			if hangup && !(n == 0 && len(p) > 0 && ec.closed) {
  				ec.readc.Wait()
  				continue
  			}
  		}
  		break
  	}
  	// if we didnt read anything then return io.EOF to end gracefully
  	if n == 0 && len(p) > 0 && err == nil {
  		err = io.EOF
  	}
  	// signal for others that we finished the read
  	ec.readc.Signal()
  	return n, err
  }
docs: // Read reads up to len(p) bytes into p. It returns the number of bytes read
  // (0 <= n <= len(p)) and any error encountered.
  //
  // If the console's read returns EAGAIN or EIO, we assume that it's a
  // temporary error because the other side went away and wait for the signal
  // generated by epoll event to continue.