AnyEvent driver for Prima

ambrus ambrus at math.bme.hu
Tue Dec 13 14:47:21 CET 2016


Hello Dmitry Karasik, Corion, and Schmorp.

Corion is making an AnyEvent driver for Prima.  In this email, I'll 
first try to recap what's happened, because the communication about this 
was fragmented to multiple forums.  I'll then ask some questions to 
Dmitry about Prima that are connected to this, and also questions to 
schmorp about AnyEvent.


== Recap ==

Prima is a GUI toolkit with a perl interface, homepage 
"http://www.prima.eu.org/" and available from CPAN.  Corion was trying 
to use Prima and do some HTTP requests from the same perl interpreter on 
win32.  This needs some event loop integration, so I pushed Corion into 
using AnyEvent for that.

So Corion is working on an AnyEvent driver for Prima.  This is in an 
early stage, visible at "https://github.com/Corion/AnyEvent-Impl-Prima". 
  When he fixes it and tests it properly, he will release it, and then 
schmorp might move it into the AnyEvent CPAN distribution.

In the AnyEvent docs, schmorp tells the basic idea of what an AnyEvent 
driver needs to do, and he has told a bit more about this case.  An 
AnyEvent driver is a module that can override certain methods of the 
AnyEvent module.

The two most important methods to override are io, which implements a 
file descriptor watcher, and timer, which implements a timer watcher.  
Prima provides watchers suitable for these, exposed in Prima::File and 
Prima::Timer, so Corion already has implementations of these methods.  
The implementation are not perfect, but there's no big problems that 
can't be fixed easily.  In particular, the io method should accept 
either a perl IO handle or a unix file descriptor number as the fd 
parameter.  Corion's implementation doesn't yet do that, but this can be 
fixed, and the AnyEvent::_dupfh undocumented function might help.

Ideally there should also be an idle method, which creates a watcher 
such that whenever the event loop would sleep waiting for new events to 
happen, the callback of the watcher is called instead of sleeping.  
Prima doesn't expose this function, and it seems that a proper 
implementation isn't possible without modifying at least the unix event 
loop of Prima.  This isn't urgent though, because Corion's application 
of a HTTP client won't be using this watcher at all.

The driver does not need to override the signal and child watchers, 
because AnyEvent already provides implementations for those.  The 
default implementations should work fine.  The implementation could fail 
if some other code tries to wait for child processes already, 
interfering with AnyEvent, but Prima doesn't seem to ever do that.  The 
driver also doesn't need to override condvar watchers, because the 
default implementation always works, and is only ever overrided for 
performance.

The module should also override the _poll method.  This method is 
expected to call into the main loop of the event loop, to sleep until 
some events are triggered, handle at least one event, and then return.  
It isn't strictly necessary to implement this, because the driver can 
still be used in Prima programs fine without, but it helps a lot when 
testing the driver.  Prima doesn't seem to expose a suitable function 
for this: it only has the yield method of Prima::Application, which 
doesn't sleep if no events are available, and the go method, which 
doesn't return until the application exits.


== Questions to Dmitry ==

I'd like some clarifications because I'm not sure I understand how the 
Prima API works.

The AnyEvent API expects that watchers can be cancelled by getting the 
perl watcher object garbage collected.  After the caller frees the last 
reference to the watcher, the callbacks should no longer get invoked.  
The event loop thus shouldn't keep references to the watcher or 
callbacks when the perl watcher object is destroyed.  (Also, obviously, 
the DESTROY method of the perl watcher object shouldn't revive the 
object.)  I'd like to know if the Prima::File and Prima::Timer behave 
this way already.  In particular, if multiple events are queued, and 
then the callback for one of the events destroys the watcher for the 
second event, will Prima discard the second event?  If it doesn't, 
that's no problem, we can handle destroying the perl object specifically 
in the driver, but the driver doesn't currently do that.

The Prima::Timer watcher is always in periodic repeating mode.  If the 
timeout is small, is it possible that the timeout fires twice before the 
event loop gets a chance to execute the callback the first time?  
Corion's implementation of the timer calls the stop method of the timer 
from the callback, but I'd like to know if that's enough to make sure 
that the callback can't be called again.


== Questions to schmorp ==

Prima::Utils->post is a function that corresponds to AnyEvent::postpone. 
  It arranges that the event loop calls a callback later, without having 
to bother to set up a watcher object.  Can a driver override this 
function by just defining postpone in the driver package?  Should the 
driver override it?

In the API of AnyEvent, when a watcher is destroyed, is the DESTROY 
method allowed to call the callback right then?  EV certainly doesn't do 
that, but I'm asking about AnyEvent in general.


-- Ambrus




More information about the anyevent mailing list