1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-23 00:00:06 +01:00
libwebsockets/lib/event-libs
Andy Green 1a93e73402 fakewsi: replace with smaller substructure
Currently we always reserve a fakewsi per pt so events that don't have a related actual
wsi, like vhost-protocol-init or vhost cert init via protocol callback can make callbacks
that look reasonable to user protocol handler code expecting a valid wsi every time.

This patch splits out stuff that user callbacks often unconditionally expect to be in
a wsi, like context pointer, vhost pointer etc into a substructure, which is composed
into struct lws at the top of it.  Internal references (struct lws is opaque, so there
are only internal references) are all updated to go via the substructre, the compiler
should make that a NOP.

Helpers are added when fakewsi is used and referenced.

If not PLAT_FREERTOS, we continue to provide a full fakewsi in the pt as before,
although the helpers improve consistency by zeroing down the substructure.  There is
a huge amount of user code out there over the last 10 years that did not always have
the minimal examples to follow, some of it does some unexpected things.

If it is PLAT_FREERTOS, that is a newer thing in lws and users have the benefit of
being able to follow the minimal examples' approach.  For PLAT_FREERTOS we don't
reserve the fakewsi in the pt any more, saving around 800 bytes.  The helpers then
create a struct lws_a (the substructure) on the stack, zero it down (but it is only
like 4 pointers) and prepare it with whatever we know like the context.

Then we cast it to a struct lws * and use it in the user protocol handler call.
In this case, the remainder of the struct lws is undefined.  However the amount of
old protocol handlers that might touch things outside of the substructure in
PLAT_FREERTOS is very limited compared to legacy lws user code and the saving is
significant on constrained devices.

User handlers should not be touching everything in a wsi every time anyway, there
are several cases where there is no valid wsi to do the call with.  Dereference of
things outside the substructure should only happen when the callback reason shows
there is a valid wsi bound to the activity (as in all the minimal examples).
2020-07-20 06:28:52 +01:00
..
glib fakewsi: replace with smaller substructure 2020-07-20 06:28:52 +01:00
libev fakewsi: replace with smaller substructure 2020-07-20 06:28:52 +01:00
libevent fakewsi: replace with smaller substructure 2020-07-20 06:28:52 +01:00
libuv fakewsi: replace with smaller substructure 2020-07-20 06:28:52 +01:00
poll cmakelist: Augean Stables refactor 2020-05-27 08:40:12 +01:00
CMakeLists.txt cmakelist: Augean Stables refactor 2020-05-27 08:40:12 +01:00
private-lib-event-libs.h event-lib-glib 2020-02-21 17:32:41 +00:00
README.md private.h: rename to contain dir 2019-08-15 10:49:52 +01:00

Information for new event lib implementers

Introduction

By default lws has built-in support for POSIX poll() as the event loop.

However either to get access to epoll() or other platform specific better poll waits, or to integrate with existing applications already using a specific event loop, it can be desirable for lws to use another external event library, like libuv, libevent or libev.

Code placement

The code specific to the event library should live in ./lib/event-libs/**lib name**

Allowing control over enabling event libs

All event libs should add a cmake define LWS_WITH_**lib name** and make its build dependent on it in CMakeLists.txt. Export the cmakedefine in ./cmake/lws_config.h.in as well so user builds can understand if the event lib is available in the lws build it is trying to bind to.

If the event lib is disabled in cmake, nothing in its directory is built or referenced.

Event loop ops struct

The event lib support is defined by struct lws_event_loop_ops in lib/event-libs/private-lib-event-libs.h, each event lib support instantiates one of these and fills in the appropriate ops callbacks to perform its job. By convention that lives in ./lib/event-libs/**lib name**/**lib_name**.c.

Private event lib declarations

Truly private declarations for the event lib can go in the event-libs directory as you like. However when the declarations must be accessible to other things in lws build, eg, the event lib support adds members to struct lws when enabled, they should be in the event lib support directory in a file private-lib-event-libs-myeventlib.h.

Search for "bring in event libs private declarations" in `./lib/core/private-lib-core.h and add your private event lib support file there following the style used for the other event libs, eg,

#if defined(LWS_WITH_LIBUV)
 #include "event-libs/libuv/private-lib-event-libs-libuv.h"
#endif

If the event lib support is disabled at cmake, nothing from its private.h should be used anywhere.

Integrating event lib assets to lws

If your event lib needs special storage in lws objects, that's no problem. But to keep things sane, there are some rules.

  • declare a "container struct" in your private.h for everything, eg, the libuv event lib support need to add its own assets in the perthread struct, it declares in its private.h
struct lws_pt_eventlibs_libuv {
	uv_loop_t *io_loop;
	uv_signal_t signals[8];
	uv_timer_t timeout_watcher;
	uv_timer_t hrtimer;
	uv_idle_t idle;
};
  • add your event lib content in one place in the related lws struct, protected by #if defined(LWS_WITH_**lib name**), eg, again for LWS_WITH_LIBUV
struct lws_context_per_thread {

...

#if defined(LWS_WITH_LIBUV)
	struct lws_pt_eventlibs_libuv uv;
#endif

...

Adding to lws available event libs list

Edit the NULL-terminated array available_event_libs at the top of ./lib/context.c to include a pointer to your new event lib support's ops struct, following the style already there.

const struct lws_event_loop_ops *available_event_libs[] = {
#if defined(LWS_WITH_POLL)
	&event_loop_ops_poll,
#endif
#if defined(LWS_WITH_LIBUV)
	&event_loop_ops_uv,
#endif
...

This is used to provide a list of avilable configured backends.

Enabling event lib adoption

You need to add a LWS_SERVER_OPTION... flag as necessary in ./lib/libwebsockets.h enum lws_context_options, and follow the existing code in lws_create_context() to convert the flag into binding your ops struct to the context.

Implementation of the event lib bindings

Study eg libuv implementation, using the available ops in the struct lws_event_loop_ops as a guide.

Destruction

Ending the event loop is generally a bit tricky, because if the event loop is internal to the lws context, you cannot destroy it while the event loop is running.

Don't add special exports... we tried that, it's a huge mess. The same user code should be able work with any of the event loops including poll.

The solution we found was hide the different processing necessary for the different cases in lws_destroy_context(). To help with that there are ops available at two different places in the context destroy processing.