How to wrap a network I/O library? (i.e. how to teach libuv to yield)

from:

I can vaguely understand the scheme, but concretely, what should I do, assuming I have these functions wrapped:

function _read!(ptr, fobj, nb, seekloc)
    @ccall lib.ReadAt(ptr::Ptr{UInt8}, 
                      fobj.gofile_id::Cstring, nb::Clong, seekloc::Clong)::Cvoid
end

function Base.read(fobj::XRDStream, nb::Integer)
    buffer = Vector{UInt8}(undef, nb)
    GC.@preserve buffer _read!(buffer, fobj, nb, fobj.seekloc)
    fobj.seekloc += nb
    return buffer
end

how to modify the Base.read() such that it yields to other tasks when waiting for the ccall to finish?