[Libwebsockets] Example of custom event loop integration?
andy at warmcat.com
Sun May 30 07:35:53 CEST 2021
On 5/30/21 1:21 AM, Felipe Gasper wrote:
Hi Felipe -
> I’m considering writing a Perl binding to libwebsockets. For this to work I need to be able to integrate libwebsockets into whatever event loop the Perl application runs. (There are many loops, and three widely-used abstraction interfaces over them.)
> I found the HTTP-server foreign event lib integration example: https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c
> This example, though, appears only to use event libraries that libwebsockets natively supports. Does libwebsockets include an interface like libcurl’s multi_socket interface (cf. https://curl.se/libcurl/c/libcurl-multi.html)? That seems to be what `struct lws_event_loop_ops` and `struct lws_plugin_evlib` represent … are there any examples of giving these structs to libwebsockets at runtime?
On the one hand, passing a struct lws_event_loop_ops * in at context
creation time is easy to add. But I am not sure I understand the
problem you are describing well enough...
Typically a library or process / subprocess "pick an event loop", if I
understand it part of the system deciding to use an abstraction layer
(or three :-) ) between it and the actual loop, doesn't change that
there's a specific loop library running the show underneath, nor affect
compatibility then with joining the real loop below the abstraction if
you support it natively. So native support for a range of event libs
remains the best choice AFAIK.
As you saw with the foreign example, lws already lets you pick the loop
at runtime, not just buildtime, and already builds the plugins
separately from the library, meaning all necessary apis are already
public and available for integration if the app wants to produce a
custom lws_event_loop_ops. (It's like that so linux distros can package
one build of lws that will work correctly with code, packaged or not,
that use any of the loops. Packaged code can express a dependency on
lws and the sub-package containing the loop plugin that it needs.)
There are indeed many loop libraries out there but it's a finite number
and we already support the major ones, and some minor ones that were
contributed. We support joining and leaving a foreign loop cleanly
without disrupting it or leaking... in particular we support that with
libuv, which is much harder than the others because handle destruction
is async, via the event loop, it means all kinds of close and destroy
internally in lws had to be made async / via refcounts to work with it
only letting us actually destroy things later.
For custom loops in the application, there is a gnarly hack from a
decade ago it sounds like you found, the EXTERNAL_POLL support, I really
don't recommend using this. Modern lws offers hi res scheduling
services (for, eg, UDP retry) that are used internally and encouraged
for user code, since it radically improves portability, that are coming
from modulating the wait via event lib timers or timeout computation.
EXTERNAL_POLL's concept was much dumber, just bringing a zero-wait
service call inside an existing custom event loop, it cannot make a
satisfying result for both latency and cpu load. It also has a
dependency on protocols which is user code business, and not
available for the kind of generic integration you are looking at.
More information about the Libwebsockets