[libevfibers] Re: interfacing with external resource callbacks

  • From: Phil Carns <carns@xxxxxxxxxxx>
  • To: <libevfibers@xxxxxxxxxxxxx>
  • Date: Thu, 28 May 2015 17:27:08 -0400

On 05/28/2015 12:00 PM, Konstantin Olkhovskiy wrote:

Hello,

What I need to figure out first, though, is how hard it would be
to plug in an external resource/library. I see the
fbr_eio_custom() function in the existing API, but the library
that I have in mind already has its own asynchronous API which
itself uses callbacks for completion notification. There is no
blocking function for me to execute.

It should be really easy. Use fbr_cond_wait() within your fiber and
fbr_cond_signal() from your completion callback.


As a result, what I really want to do is add my own fbr_foo()
function that posts the external operation, and have the callback
for that external operation do an ev_async_send() to wake up the
event loop in evfibers and continue fiber execution. I'm not sure
if I described that properly, but hopefully it makes sense. I'm
looking at evfibers as a way to have external library operations
*appear* as if they are sequential blocking calls within a fiber.

What you described is perfectly correct and makes sense.
fbr_cond_* functions wrap an ev_async internally, but are not
thread safe. You can wrap the call to fbr_cond_wait() into
my_fbr_foo() or whatever you like it to be.


Hi Konstantin,

That's perfect. Is it safe to declare the condition variable (and corresponding mutex) on the stack of the fiber/function that calls fbr_cond_wait() as long as I make sure that it doesn't go out of scope before the resource callback issues the signal()?


My question is this: If I want to add my own fbr_foo() function as
described above, will I need to actually modify fiber.c to do it?
Or does an external user of libevfibers have access to enough
internal data structures to be able to interface with the event
loop (an inject completion events) from a separate library?


That would defeat the purpose of creating a fiber library. libevfibers is
just a client of libev event loop. You can use fibers, or you can use
the event loop, or both, depending on your needs.


Gotcha.

If you know that completion callback from your library is going to be
invoked from the other thread, then you will likely need to manually
wait for ev_async. Just start an ev_async watcher, and do call
ev_async_send() from your library's completion callback. Within a fiber,
which will be waiting for this even to arrive, you need to wait for this
watcher to trigger. libevfibers has some wrappers for I/O operations,
but unfortunately it does not have one for ev_async, so you can just
copy paste the boilerplate wrapper from e.g. fbr_sleep. All of the
fbr_ev_* functions which are used within fbr_sleep are public API and
are documented as such.


Ok. This is indeed the case. I would likely have a separate thread running (not directly involved in libevfiber) that drives progress for this resource, and it will be issuing the callbacks. Thanks for the pointer.

I'm comfortable with that, but just to clarify for my own understanding: the reason you wouldn't use the cond variable approach in this case is because of the possibility for the two threads to race in modifying the internal wait list for the fbr cond variable, right?

thanks!
-Phil

--
Regards,
Konstantin

Other related posts: