def _wait_fd(conn, read=True):
    '''Wait for an event on file descriptor ``fd``.

    :param conn: file descriptor
    :param read: wait for a read event if ``True``, otherwise a wait
        for write event.

    This function must be invoked from a coroutine with parent, therefore
    invoking it from the main greenlet will raise an exception.
    '''
    current = getcurrent()
    parent = current.parent
    assert parent, '"_wait_fd" must be called by greenlet with a parent'
    try:
        fileno = conn.fileno()
    except AttributeError:
        fileno = conn
    future = Future()
    # When the event on fd occurs switch back to the current greenlet
    if read:
        future._loop.add_reader(fileno, _done_wait_fd, fileno, future, read)
    else:
        future._loop.add_writer(fileno, _done_wait_fd, fileno, future, read)
    # switch back to parent greenlet
    parent.switch(future)
    # Back on the child greenlet. Raise error if there is one
    future.result()
Wait for an event on file descriptor ``fd``.

    :param conn: file descriptor
    :param read: wait for a read event if ``True``, otherwise a wait
        for write event.

    This function must be invoked from a coroutine with parent, therefore
    invoking it from the main greenlet will raise an exception.