[Libwebsockets] Event-Loop API

Andy Green andy at warmcat.com
Mon Sep 24 18:30:16 CEST 2018

On 24/09/2018 23:15, Nicolas Cornu wrote:
> Hello,
> I'm trying to adapt libwebsockets to a new (barely unused) event-loop. I
> read this page:
> https://libwebsockets.org/git/libwebsockets/tree/lib/event-libs . I find
> it difficult for two reasons.

Well, at least you don't find it difficult because the event loop 
support - which by now supports libuv, libev, libevent and poll - is not 
neatly isolated into a nice "ops" callback struct.

That's new for v3.0 - before that libevent support was contributed by a 
Samsung dude without that advantage, the event loop stuff was spread all 
over the code.  So since he found that possible - he just sent the patch 
one day out of the blue - the situation is actually a lot easier for you.

> First, names of callbacks in lws_event_loop_ops are not clear
> (wsi_logical_close, init_pt, destroy_context2, ...).

If you look in the ops struct definition, there is a little more advice

struct lws_event_loop_ops {
	const char *name;
	/* event loop-specific context init during context creation */
	int (*init_context)(struct lws_context *context,
			    const struct lws_context_creation_info *info);
	/* called during lws_destroy_context */
	int (*destroy_context1)(struct lws_context *context);
	/* called during lws_destroy_context2 */
	int (*destroy_context2)(struct lws_context *context);
	/* init vhost listening wsi */
	int (*init_vhost_listen_wsi)(struct lws *wsi);
	/* init the event loop for a pt */
	int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
	/* called at end of first phase of close_free_wsi()  */
	int (*wsi_logical_close)(struct lws *wsi);
	/* return nonzero if client connect not allowed  */
	int (*check_client_connect_ok)(struct lws *wsi);
	/* close handle manually  */
	void (*close_handle_manually)(struct lws *wsi);
	/* event loop accept processing  */
	void (*accept)(struct lws *wsi);
	/* control wsi active events  */
	void (*io)(struct lws *wsi, int flags);
	/* run the event loop for a pt */
	void (*run_pt)(struct lws_context *context, int tsi);
	/* called before pt is destroyed */
	void (*destroy_pt)(struct lws_context *context, int tsi);
	/* called just before wsi is freed  */
	void (*destroy_wsi)(struct lws *wsi);

	unsigned int periodic_events_available:1;


> Second, the callback of already existing event loops are not only here
> to wrap event loop. For exemple, if we read init_context implementation
> it does something else than wrapping event loop.

... this stuff is a) setting up event-loop specific signal handler and 
b) preparing the event-loop specific watcher struct with a runtime 
pointer to the context, so it can operate in signal context without globals.

static int
elops_init_context_uv(struct lws_context *context,
		      const struct lws_context_creation_info *info)
	int n;

	context->eventlib_signal_cb = info->signal_cb;

	for (n = 0; n < context->count_threads; n++)
		context->pt[n].w_sigint.context = context;

	return 0;

> So, is it possible to do better documentation about them to explain what
> they should do?

Sure, anything's possible.  But it's not exactly #1 on my todo list atm.

If you have specific questions I will try to answer them, but the code 
calling the ops is all right there along with four example 
implementations.  You may find your event loop needs more ops, although 
libuv was probably the worst case for that already.

Note that libuv is quite different from the other event loops because it 
requires asynchronous handle close later via the event loop.  So this 
has a lot of knock-ons to make it work properly, like having to 
reference-count anything with a handle so we know the moment when it's 
able to stop the event loop on exit; getting that wrong is catastrophic 
for memory leaks and clean integration with foreign loops.  Assuming 
your event loop is more along the lines of libevent, which doesn't have 
this requirement, cut-and-pasting the libevent support doesn't look that 
unmanageable or inexplicable:


There are also three minimal examples that showcase various modes of 
using the event loop, that are easy to extend to more event loops


The "foreign" one is interesting because it proves lws can integrate 
cleanly with somebody else's existing event loop without perturbing it. 
Although again that was more of a challenge for libuv than anything else.


> Regards,
> Nicolas
> _______________________________________________
> Libwebsockets mailing list
> Libwebsockets at ml.libwebsockets.org
> https://libwebsockets.org/mailman/listinfo/libwebsockets

More information about the Libwebsockets mailing list