diff --git a/.sai.json b/.sai.json index 214ba6b73..61cc19de2 100644 --- a/.sai.json +++ b/.sai.json @@ -12,7 +12,7 @@ "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G DEB\";cmake .. ${cmake} && make -j && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" }, "linux-fedora-32/x86_64-amd/gcc": { - "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" + "build": "rm -rf build destdir ; mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G RPM\";cmake .. ${cmake} && make -j && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" }, "linux-gentoo/x86_64-amd/gcc": { "build": "mkdir build destdir;cd build;export CCACHE_DISABLE=1;export SAI_CPACK=\"-G ZIP\";cmake .. ${cmake} && make -j && make -j DESTDIR=../destdir install && ctest -j4 --output-on-failure ${cpack}" diff --git a/CMakeLists-implied-options.txt b/CMakeLists-implied-options.txt index 01c9813e0..5f5455ec1 100644 --- a/CMakeLists-implied-options.txt +++ b/CMakeLists-implied-options.txt @@ -86,8 +86,8 @@ if(LWS_WITH_DISTRO_RECOMMENDED) set(LWS_WITH_GLIB 1) # glib set(LWS_WITH_LIBUV 1) # libuv set(LWS_WITH_LIBEV 1) # libev - # libev + libevent cannot coexist at build-time - set(LWS_WITH_LIBEVENT 0) + set(LWS_WITH_LIBEVENT 1) # libevent + set(LWS_WITH_EVLIB_PLUGINS 1) # event libraries created as plugins / individual packages set(LWS_WITHOUT_EXTENSIONS 0) # libz set(LWS_ROLE_DBUS 1) # dbus-related libs set(LWS_WITH_FTS 1) # selfcontained @@ -112,6 +112,17 @@ if(LWS_WITH_DISTRO_RECOMMENDED) set(LWS_WITH_DIR 1) # selfcontained endif() +# LWS_WITH_EVENT_LIBS is set if any event lib selected + +if (LWS_WITH_LIBEV OR + LWS_WITH_LIBUV OR + LWS_WITH_LIBEVENT OR + LWS_WITH_GLIB) + set(LWS_WITH_EVENT_LIBS 1) +else() + unset(LWS_WITH_EVENT_LIBS) +endif() + if (LWS_WITH_SECURE_STREAMS_PROXY_API) set(LWS_WITH_LWS_DSH 1) set(LWS_WITH_UNIX_SOCK 1) @@ -184,10 +195,14 @@ if (NOT LWS_ROLE_WS) set(LWS_WITHOUT_EXTENSIONS 1) endif() +unset(LWS_WITH_LIBUV_INTERNAL) + if (LWS_WITH_LWSWS) message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV") set(LWS_WITH_PLUGINS 1) set(LWS_WITH_LIBUV 1) + set(LWS_WITH_LIBUV_INTERNAL 1) + set(LWS_WITH_EVENT_LIBS 1) # implied by LIBUV_INTERNAL set(LWS_WITH_ACCESS_LOG 1) set(LWS_WITH_SERVER_STATUS 1) set(LWS_WITH_LEJP 1) @@ -249,6 +264,9 @@ endif() if (WIN32) set(LWS_MAX_SMP 1) +if (LWS_WITH_PLUGINS) +set(LWS_WITH_LIBUV_INTERNAL 1) +endif() endif() if (LWS_WITHOUT_SERVER) @@ -355,7 +373,7 @@ endif() # set(LWS_WITH_ABSTRACT 1) #endif() -if (LWS_WITH_LIBEV AND LWS_WITH_LIBEVENT) +if (NOT LWS_WITH_EVLIB_PLUGINS AND (LWS_WITH_LIBEV AND LWS_WITH_LIBEVENT)) message(FATAL_ERROR "Sorry libev and libevent conflict with each others' namespace, you can only have one or the other") endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index cd2d4b17d..5a3f45157 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,13 @@ option(LWS_WITH_LIBUV "Compile with support for libuv" OFF) option(LWS_WITH_LIBEVENT "Compile with support for libevent" OFF) option(LWS_WITH_GLIB "Compile with support for glib event loop" OFF) +if (UNIX) +# since v4.1, on unix platforms default is build any event libs as runtime plugins +option(LWS_WITH_EVLIB_PLUGINS "Compile event lib support into runtime-selected plugins" ON) +else() +# otherwise default to linking the event lib(s) to libwebsockets.so +option(LWS_WITH_EVLIB_PLUGINS "Compile event lib support into runtime-selected plugins" OFF) +endif() # # LWS Drivers # @@ -353,15 +360,19 @@ set(VERSION "${CPACK_PACKAGE_VERSION}") set(CPACK_RPM_PACKAGE_RELEASE_DIST ON) set(CPACK_RPM_FILE_NAME "RPM-DEFAULT") -set(CPACK_RPM_DEBUGINFO_PACKAGE ON) +# below makes path length problems in CI +set(CPACK_RPM_DEBUGINFO_PACKAGE OFF) # below makes some kind of chimera rpm with binaries and sources set(CPACK_RPM_PACKAGE_SOURCES OFF) set(CPACK_RPM_INSTALL_WITH_EXEC ON) +set(CPACK_RPM_COMPONENT_INSTALL ON) set(CPACK_DEBIAN_FILE_NAME "DEB-DEFAULT") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_DEBUGINFO_PACKAGE ON) set(CPACK_DEBIAN_PACKAGE_SOURCE ON) +set(CPACK_DEBIAN_COMPONENT_INSTALL ON) + set(LWS_LIBRARY_VERSION ${CPACK_PACKAGE_VERSION}) set(LWS_LIBRARY_VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR}) @@ -916,9 +927,9 @@ endif() export(PACKAGE libwebsockets) install(DIRECTORY include/libwebsockets - DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev_headers) + DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev) install(FILES ${PROJECT_BINARY_DIR}/include/libwebsockets.h ${PROJECT_BINARY_DIR}/include/lws_config.h - DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev_headers) + DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev) # Generate the config file for the installation tree. get_filename_component(LWS_ABSOLUTE_INSTALL_CMAKE_DIR ${LWS_INSTALL_CMAKE_DIR} ABSOLUTE) diff --git a/READMEs/README.event-libs.md b/READMEs/README.event-libs.md new file mode 100644 index 000000000..391d74ca9 --- /dev/null +++ b/READMEs/README.event-libs.md @@ -0,0 +1,80 @@ +# lws event library support + +## v4.0 and below + +Before v4.1, lws allowed selecting some event library support for inclusion +in the libwebsockets library + +Option|Feature +---|--- +`LWS_WITH_GLIB`|glib +`LWS_WITH_LIBEVENT`|libevent +`LWS_WITH_LIBUV`|libuv +`LWS_WITH_LIBEV`|libev + +The user code can select by `info->options` flags at runtime which event loop +it wants to use. + +The only restriction is that libev and libevent can't coexist, because their +header namespace conflicts. + +## v4.1 and above + +Lws continues to support the old way described above, but there's an additional +new cmake option that decides how they are built if any are selected, +`LWS_WITH_EVLIB_PLUGINS`. + +The old behaviour is set by `LWS_WITH_EVLIB_PLUGINS=0`, for UNIX platforms, this +is set to 1 by default. This causes the enabled event lib support to each be built into +its own dynamically linked plugin, and lws will bring in the requested support alone +at runtime after seeing the `info->options` flags requested by the user code. + +This has two main benefits, first the conflict around building libevent and libev +together is removed, they each build isolated in their own plugin; the libwebsockets +core library build doesn't import any of their headers (see below for exception). +And second, for distro packaging, the event lib support plugins can be separately +packaged, and apps take dependencies on the specific event lib plugin package, which +itself depends on the libwebsockets core library. This allows just the needed +dependencies for the packageset without forcing everything to bring everything in. + +Separately, lws itself has some optional dependencies on libuv, if you build lwsws +or on Windows you want plugins at all. CMake will detect these situations and +select to link the lws library itself to libuv if so as well, independent of whatever +is happening with the event lib support. + +## evlib plugin install + +The produced plugins are named + +event lib|plugin name +---|--- +glib|`libwebsockets-evlib_glib.so` +event|`libwebsockets-evlib_event.so` +uv|`libwebsockets-evlib_uv.so` +ev|`libwebsockets-evlib_ev.so` + +The evlib plugins are installed alongside libwebsockets.so/.a into the configured +library dir, it's often `/usr/local/lib/` by default on linux. + +Lws looks for them at runtime using the build-time-configured path. + +## Component packaging + +The canonical package name is `libwebsockets`, the recommended way to split the +packaging is put the expected libs and pkgconfig in `libwebsockets` or `libwebsockets-core`, +the latter is followed by the provided cmake, and produce an additional package per build +event library plugin, named, eg `libwebsockets-evlib_glib`, which has a dependency on +`libwebsockets[-core]`. + +Applications that use the default event loop can directly require `libwebsockets[-core]`, +and application packages that need specific event loop support can just require, eg, +`libwebsockets-evlib_glib`, which will bring that in and the core lws pieces in one step. +There is then no problem with multiple apps requiring different event libs, they will +bring in all the necessary pieces which will not conflict either as packages or at +runtime. + +## `LWS_WITH_DISTRO_RECOMMENDED` + +The cmake helper config `LWS_WITH_DISTRO_RECOMMENDED` is adapted to build all the +event libs with the event lib plugin support enabled. + diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 327adff02..ea03ac64a 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -7,6 +7,7 @@ #endif #define LWS_INSTALL_DATADIR "${CMAKE_INSTALL_PREFIX}/share" +#define LWS_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" #define LWS_LIBRARY_VERSION_MAJOR ${LWS_LIBRARY_VERSION_MAJOR} #define LWS_LIBRARY_VERSION_MINOR ${LWS_LIBRARY_VERSION_MINOR} #define LWS_LIBRARY_VERSION_PATCH_ELABORATED ${LWS_LIBRARY_VERSION_PATCH_ELABORATED} @@ -189,4 +190,7 @@ #cmakedefine LWS_WITH_ZIP_FOPS #cmakedefine USE_OLD_CYASSL #cmakedefine USE_WOLFSSL +#cmakedefine LWS_WITH_EVENT_LIBS +#cmakedefine LWS_WITH_EVLIB_PLUGINS +#cmakedefine LWS_WITH_LIBUV_INTERNAL diff --git a/include/libwebsockets.h b/include/libwebsockets.h index f93bff3d6..101b83071 100644 --- a/include/libwebsockets.h +++ b/include/libwebsockets.h @@ -190,21 +190,17 @@ typedef unsigned long long lws_intptr_t; #endif #endif -#if defined(LWS_WITH_LIBEV) -#include -#endif /* LWS_WITH_LIBEV */ -#ifdef LWS_WITH_LIBUV +#if defined(LWS_WITH_LIBUV_INTERNAL) #include + #ifdef LWS_HAVE_UV_VERSION_H #include #endif + #ifdef LWS_HAVE_NEW_UV_VERSION_H #include #endif -#endif /* LWS_WITH_LIBUV */ -#if defined(LWS_WITH_LIBEVENT) -#include -#endif /* LWS_WITH_LIBEVENT */ +#endif #if defined(LWS_WITH_TLS) @@ -610,6 +606,7 @@ struct lws; #endif +#include #include #include #include diff --git a/include/libwebsockets/lws-eventlib-exports.h b/include/libwebsockets/lws-eventlib-exports.h new file mode 100644 index 000000000..fedccc286 --- /dev/null +++ b/include/libwebsockets/lws-eventlib-exports.h @@ -0,0 +1,61 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 - 2020 Andy Green + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * These are exports needed by event lib plugins. + * + * You should consider these opaque for normal user code. + */ + +LWS_VISIBLE LWS_EXTERN void * +lws_realloc(void *ptr, size_t size, const char *reason); + +LWS_VISIBLE LWS_EXTERN void +lws_vhost_destroy1(struct lws_vhost *vh); + +LWS_VISIBLE LWS_EXTERN void +lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason, + const char *caller); + +struct lws_context_per_thread; +LWS_VISIBLE LWS_EXTERN void +lws_service_do_ripe_rxflow(struct lws_context_per_thread *pt); + +#if !defined(wsi_from_fd) && !defined(WIN32) && !defined(_WIN32) +struct lws_context; +LWS_VISIBLE LWS_EXTERN struct lws * +wsi_from_fd(const struct lws_context *context, int fd); +#endif + +LWS_VISIBLE LWS_EXTERN int +_lws_plat_service_forced_tsi(struct lws_context *context, int tsi); + +LWS_VISIBLE LWS_EXTERN void +lws_context_destroy2(struct lws_context *context); + +LWS_VISIBLE LWS_EXTERN void +lws_destroy_event_pipe(struct lws *wsi); + +LWS_VISIBLE LWS_EXTERN void +__lws_close_free_wsi_final(struct lws *wsi); + + diff --git a/include/libwebsockets/lws-protocols-plugins.h b/include/libwebsockets/lws-protocols-plugins.h index 4df9a2228..0c966667f 100644 --- a/include/libwebsockets/lws-protocols-plugins.h +++ b/include/libwebsockets/lws-protocols-plugins.h @@ -194,8 +194,6 @@ lws_pvo_get_str(void *in, const char *name, const char **result); LWS_VISIBLE LWS_EXTERN int lws_protocol_init(struct lws_context *context); -#ifdef LWS_WITH_PLUGINS - #define LWS_PLUGIN_API_MAGIC 190 /* @@ -244,7 +242,7 @@ struct lws_plugin { const lws_plugin_header_t *hdr; union { -#if defined(LWS_WITH_LIBUV) +#if defined(LWS_WITH_LIBUV) && defined(UV_ERRNO_MAP) #if (UV_VERSION_MAJOR > 0) uv_lib_t lib; /**< shared library pointer */ #endif @@ -253,6 +251,16 @@ struct lws_plugin { } u; }; +/* + * Event lib library plugin type (when LWS_WITH_EVLIB_PLUGINS) + * Public so new event libs can equally be supported outside lws itself + */ + +typedef struct lws_plugin_evlib { + lws_plugin_header_t hdr; + const struct lws_event_loop_ops *ops; +} lws_plugin_evlib_t; + typedef int (*each_plugin_cb_t)(struct lws_plugin *p, void *user); /** @@ -297,6 +305,5 @@ lws_plugins_init(struct lws_plugin **pplugin, const char * const *d, LWS_VISIBLE LWS_EXTERN int lws_plugins_destroy(struct lws_plugin **pplugin, each_plugin_cb_t each, void *each_user); -#endif ///@} diff --git a/include/libwebsockets/lws-service.h b/include/libwebsockets/lws-service.h index 4b969d70e..ed9331038 100644 --- a/include/libwebsockets/lws-service.h +++ b/include/libwebsockets/lws-service.h @@ -167,7 +167,8 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd); * APIs specific to libuv event loop itegration */ ///@{ -#ifdef LWS_WITH_LIBUV +#if defined(LWS_WITH_LIBUV) && defined(UV_ERRNO_MAP) + /* * Any direct libuv allocations in lws protocol handlers must participate in the * lws reference counting scheme. Two apis are provided: diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 8938cb01f..e410c231d 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -122,7 +122,6 @@ configure_file( add_subdir_include_dirs(core) add_subdir_include_dirs(misc) add_subdir_include_dirs(system) -add_subdir_include_dirs(event-libs) if (LWS_WITH_DRIVERS) add_subdir_include_dirs(drivers) @@ -144,6 +143,8 @@ if (LWS_WITH_SECURE_STREAMS) add_subdir_include_dirs(secure-streams) endif() +add_subdir_include_dirs(event-libs) + if (LWS_WITH_STATIC) if (LWS_STATIC_PIC) set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -249,12 +250,12 @@ endif() # Install libs and headers. install(TARGETS ${LWS_LIBRARIES} EXPORT LibwebsocketsTargets - LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries - ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT libraries - RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT libraries # Windows DLLs + LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT core + ARCHIVE DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" COMPONENT core + RUNTIME DESTINATION "${LWS_INSTALL_BIN_DIR}" COMPONENT core # Windows DLLs PUBLIC_HEADER DESTINATION "${LWS_INSTALL_INCLUDE_DIR}" COMPONENT dev) -set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries" PARENT_SCOPE) + #set(CPACK_COMPONENT_LIBRARIES_DISPLAY_NAME "Libraries" PARENT_SCOPE) set(CPACK_COMPONENT_DEV_DISPLAY_NAME "Development files" PARENT_SCOPE) diff --git a/lib/core-net/adopt.c b/lib/core-net/adopt.c index 6ea60a8bc..4e89fdc3b 100644 --- a/lib/core-net/adopt.c +++ b/lib/core-net/adopt.c @@ -49,6 +49,7 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi) { struct lws *new_wsi; int n = fixed_tsi; + size_t s = sizeof(struct lws); if (n < 0) n = lws_get_idlest_tsi(vhost->context); @@ -58,12 +59,20 @@ lws_create_new_server_wsi(struct lws_vhost *vhost, int fixed_tsi) return NULL; } - new_wsi = lws_zalloc(sizeof(struct lws), "new server wsi"); +#if defined(LWS_WITH_EVENT_LIBS) + s += vhost->context->event_loop_ops->evlib_size_wsi; +#endif + + new_wsi = lws_zalloc(s, "new server wsi"); if (new_wsi == NULL) { lwsl_err("Out of memory for new connection\n"); return NULL; } +#if defined(LWS_WITH_EVENT_LIBS) + new_wsi->evlib_wsi = (uint8_t *)new_wsi + sizeof(*new_wsi); +#endif + new_wsi->wsistate |= LWSIFR_SERVER; new_wsi->tsi = n; lwsl_debug("new wsi %p joining vhost %s, tsi %d\n", new_wsi, diff --git a/lib/core-net/connect.c b/lib/core-net/connect.c index 619240f7b..937290ebf 100644 --- a/lib/core-net/connect.c +++ b/lib/core-net/connect.c @@ -31,6 +31,7 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) const char *local = i->protocol; struct lws *wsi, *safe = NULL; const struct lws_protocols *p; + size_t s = sizeof(struct lws); const char *cisin[CIS_COUNT]; int tid = 0, n, m; size_t size; @@ -54,10 +55,18 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) /* PHASE 1: create a bare wsi */ - wsi = lws_zalloc(sizeof(struct lws), "client wsi"); +#if defined(LWS_WITH_EVENT_LIBS) + s += i->context->event_loop_ops->evlib_size_wsi; +#endif + + wsi = lws_zalloc(s, "client wsi"); if (wsi == NULL) goto bail; +#if defined(LWS_WITH_EVENT_LIBS) + wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi); +#endif + /* * Until we exit, we can report connection failure directly to the * caller without needing to call through to protocol CONNECTION_ERROR. diff --git a/lib/core-net/pollfd.c b/lib/core-net/pollfd.c index 9724f60aa..eaeda9420 100644 --- a/lib/core-net/pollfd.c +++ b/lib/core-net/pollfd.c @@ -27,8 +27,7 @@ int _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa) { -#if !defined(LWS_WITH_LIBUV) && !defined(LWS_WITH_LIBEV) && \ - !defined(LWS_WITH_LIBEVENT) && !defined(LWS_WITH_GLIB) +#if !defined(LWS_WITH_EVENT_LIBS) volatile struct lws_context_per_thread *vpt; #endif struct lws_context_per_thread *pt; @@ -72,8 +71,7 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa) assert(wsi->position_in_fds_table < (int)pt->fds_count); -#if !defined(LWS_WITH_LIBUV) && !defined(LWS_WITH_LIBEV) && \ - !defined(LWS_WITH_LIBEVENT) && !defined(LWS_WITH_GLIB) +#if !defined(LWS_WITH_EVENT_LIBS) /* * This only applies when we use the default poll() event loop. * diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index a23a44772..05ca1e700 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -428,22 +428,8 @@ struct lws_context_per_thread { #endif /* --- event library based members --- */ -#if defined(LWS_WITH_LIBEV) - struct lws_pt_eventlibs_libev ev; -#endif -#if defined(LWS_WITH_LIBUV) - struct lws_pt_eventlibs_libuv uv; -#endif -#if defined(LWS_WITH_LIBEVENT) - struct lws_pt_eventlibs_libevent event; -#endif -#if defined(LWS_WITH_GLIB) - struct lws_pt_eventlibs_glib glib; -#endif - -#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \ - defined(LWS_WITH_LIBEVENT) || defined(LWS_WITH_GLIB) - struct lws_signal_watcher w_sigint; +#if defined(LWS_WITH_EVENT_LIBS) + void *evlib_pt; /* overallocated */ #endif #if defined(LWS_WITH_DETAILED_LATENCY) @@ -530,8 +516,8 @@ struct lws_vhost { char socks_user[96]; char socks_password[96]; #endif -#if defined(LWS_WITH_LIBEV) - struct lws_io_watcher w_accept; +#if defined(LWS_WITH_EVENT_LIBS) + void *evlib_vh; /* overallocated */ #endif #if defined(LWS_WITH_SERVER_STATUS) struct lws_conn_stats conn_stats; @@ -719,12 +705,8 @@ struct lws { /* lifetime members */ -#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \ - defined(LWS_WITH_LIBEVENT) || defined(LWS_WITH_GLIB) - struct lws_io_watcher w_read; -#endif -#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBEVENT) - struct lws_io_watcher w_write; +#if defined(LWS_WITH_EVENT_LIBS) + void *evlib_wsi; /* overallocated */ #endif #if defined(LWS_WITH_DETAILED_LATENCY) @@ -1158,6 +1140,7 @@ lws_libuv_closehandle(struct lws *wsi); int lws_libuv_check_watcher_active(struct lws *wsi); +#if defined(LWS_WITH_EVLIB_PLUGINS) || defined(LWS_WITH_PLUGINS) const lws_plugin_header_t * lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, const char *sofilename, const char *_class, @@ -1165,6 +1148,7 @@ lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, int lws_plat_destroy_dl(struct lws_plugin *p); +#endif struct lws * lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd); diff --git a/lib/core-net/server.c b/lib/core-net/server.c index 6c1d52be4..e893ac1f2 100644 --- a/lib/core-net/server.c +++ b/lib/core-net/server.c @@ -175,9 +175,9 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len, struct lws_cgi * const *pcgi; #endif -#ifdef LWS_WITH_LIBUV - uv_uptime(&d); -#endif +//#ifdef LWS_WITH_LIBUV && +// uv_uptime(&d); +//#endif buf += lws_snprintf(buf, end - buf, "{ " "\"version\":\"%s\",\n" diff --git a/lib/core-net/service.c b/lib/core-net/service.c index 279020eb1..672d5081c 100644 --- a/lib/core-net/service.c +++ b/lib/core-net/service.c @@ -714,6 +714,8 @@ lws_service_fd_tsi(struct lws_context *context, struct lws_pollfd *pollfd, case LWS_HPI_RET_HANDLED: break; case LWS_HPI_RET_PLEASE_CLOSE_ME: + lwsl_notice("%s: %s pollin says please close me\n", __func__, + wsi->role_ops->name); close_and_handled: lwsl_debug("%p: Close and handled\n", wsi); lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, @@ -724,7 +726,7 @@ close_and_handled: * it waits for libuv service to complete the first async * close */ - if (context->event_loop_ops == &event_loop_ops_uv) + if (!strcmp(context->event_loop_ops->name, "libuv")) lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "close_and_handled uv repeat test"); #endif diff --git a/lib/core-net/vhost.c b/lib/core-net/vhost.c index e66eb2f4a..09cb979a3 100644 --- a/lib/core-net/vhost.c +++ b/lib/core-net/vhost.c @@ -46,22 +46,6 @@ const struct lws_role_ops *available_roles[] = { NULL }; -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 -#if defined(LWS_WITH_LIBEVENT) - &event_loop_ops_event, -#endif -#if defined(LWS_WITH_LIBEV) - &event_loop_ops_ev, -#endif - NULL -}; - #if defined(LWS_WITH_ABSTRACT) const struct lws_protocols *available_abstract_protocols[] = { #if defined(LWS_ROLE_RAW) @@ -471,8 +455,7 @@ struct lws_vhost * lws_create_vhost(struct lws_context *context, const struct lws_context_creation_info *info) { - struct lws_vhost *vh = lws_zalloc(sizeof(*vh), "create vhost"), - **vh1 = &context->vhost_list; + struct lws_vhost *vh, **vh1 = &context->vhost_list; const struct lws_http_mount *mounts; const struct lws_protocols *pcols = info->protocols; #ifdef LWS_WITH_PLUGINS @@ -490,9 +473,19 @@ lws_create_vhost(struct lws_context *context, #endif int n; + + vh = lws_zalloc(sizeof(*vh) +#if defined(LWS_WITH_EVENT_LIBS) + + context->event_loop_ops->evlib_size_vh +#endif + , __func__); if (!vh) return NULL; +#if defined(LWS_WITH_EVENT_LIBS) + vh->evlib_vh = (void *)&vh[1]; +#endif + #if LWS_MAX_SMP > 1 pthread_mutex_init(&vh->lock, NULL); #endif @@ -915,6 +908,7 @@ lws_cancel_service(struct lws_context *context) int lws_create_event_pipes(struct lws_context *context) { + size_t s = sizeof(struct lws); struct lws *wsi; int n; @@ -932,11 +926,18 @@ lws_create_event_pipes(struct lws_context *context) if (context->pt[n].pipe_wsi) return 0; - wsi = lws_zalloc(sizeof(*wsi), "event pipe wsi"); +#if defined(LWS_WITH_EVENT_LIBS) + s += context->event_loop_ops->evlib_size_wsi; +#endif + + wsi = lws_zalloc(s, "event pipe wsi"); if (!wsi) { lwsl_err("%s: Out of mem\n", __func__); return 1; } +#if defined(LWS_WITH_EVENT_LIBS) + wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi); +#endif wsi->a.context = context; lws_role_transition(wsi, 0, LRS_UNCONNECTED, &role_ops_pipe); wsi->a.protocol = NULL; diff --git a/lib/core-net/wsi.c b/lib/core-net/wsi.c index 9ad1d85a5..ba14b759c 100644 --- a/lib/core-net/wsi.c +++ b/lib/core-net/wsi.c @@ -850,8 +850,7 @@ _lws_generic_transaction_completed_active_conn(struct lws **_wsi, char take_vh_l * new guy and snuff out the old guy's magic spark at that level as well */ -#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || \ - defined(LWS_WITH_LIBEVENT) || defined(LWS_WITH_GLIB) +#if defined(LWS_WITH_EVENT_LIBS) if (wsi->a.context->event_loop_ops->destroy_wsi) wsi->a.context->event_loop_ops->destroy_wsi(wsi); if (wsi->a.context->event_loop_ops->sock_accept) diff --git a/lib/core/context.c b/lib/core/context.c index cebb07905..91d394cb4 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -331,6 +331,22 @@ static const char * const opts_str = #endif +#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) +static const struct lws_evlib_map { + uint64_t flag; + const char *name; +} map[] = { + { LWS_SERVER_OPTION_LIBUV, "evlib_uv" }, + { LWS_SERVER_OPTION_LIBEVENT, "evlib_event" }, + { LWS_SERVER_OPTION_GLIB, "evlib_glib" }, + { LWS_SERVER_OPTION_LIBEV, "evlib_ev" }, +}; +static const char * const dlist[] = { + LWS_INSTALL_LIBDIR, + NULL +}; +#endif + struct lws_context * lws_create_context(const struct lws_context_creation_info *info) { @@ -360,6 +376,10 @@ lws_create_context(const struct lws_context_creation_info *info) #endif size = sizeof(struct lws_context); int n, lpf = info->fd_limit_per_thread; + const lws_plugin_evlib_t *plev = NULL; +#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) + struct lws_plugin *evlib_plugin_list = NULL; +#endif if (lpf) { lpf+= 2; @@ -407,6 +427,102 @@ lws_create_context(const struct lws_context_creation_info *info) #if !defined(LWS_PLAT_FREERTOS) size += (count_threads * sizeof(struct lws)); #endif +#endif /* network */ + +#if defined(LWS_WITH_POLL) + { + extern const lws_plugin_evlib_t evlib_poll; + plev = &evlib_poll; + } +#endif + +#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) + + /* + * New style dynamically loaded event lib support + * + * We have to pick and load the event lib plugin before we allocate + * the context object, so we can overallocate it correctly + */ + + lwsl_info("%s: ev lib path %s\n", __func__, LWS_INSTALL_LIBDIR); + + for (n = 0; n < (int)LWS_ARRAY_SIZE(map); n++) { + if (!lws_check_opt(info->options, map[n].flag)) + continue; + + if (lws_plugins_init(&evlib_plugin_list, + dlist, "lws_evlib_plugin", + map[n].name, NULL, NULL)) { + lwsl_err("%s: failed to load %s\n", __func__, + map[n].name); + goto bail; + } + + if (!evlib_plugin_list) { + lwsl_err("%s: unable to load evlib plugin %s\n", + __func__, map[n].name); + + goto bail; + } + plev = (const lws_plugin_evlib_t *)evlib_plugin_list->hdr; + break; + } +#else +#if defined(LWS_WITH_EVENT_LIBS) + /* + * set the context event loops ops struct + * + * after this, all event_loop actions use the generic ops + */ + + /* + * oldstyle built-in event lib support + * + * We have composed them into the libwebsockets lib itself, we can + * just pick the ops we want and done + */ + +#if defined(LWS_WITH_LIBUV) + if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV)) { + extern const lws_plugin_evlib_t evlib_uv; + plev = &evlib_uv; + } +#endif + +#if defined(LWS_WITH_LIBEVENT) + if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEVENT)) { + extern const lws_plugin_evlib_t evlib_event; + plev = &evlib_event; + } +#endif + +#if defined(LWS_WITH_GLIB) + if (lws_check_opt(info->options, LWS_SERVER_OPTION_GLIB)) { + extern const lws_plugin_evlib_t evlib_glib; + plev = &evlib_glib; + } +#endif + +#if defined(LWS_WITH_LIBEV) + if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBEV)) { + extern const lws_plugin_evlib_t evlib_ev; + plev = &evlib_ev; + } +#endif + +#endif /* with event libs */ + +#endif /* not with ev plugins */ + + if (!plev) + goto fail_event_libs; + +#if defined(LWS_WITH_NETWORK) + size += plev->ops->evlib_size_ctx /* the ctx evlib priv */ + + (count_threads * plev->ops->evlib_size_pt) /* the pt evlib priv */; + + lwsl_info("Event loop: %s\n", plev->ops->name); #endif context = lws_zalloc(size, "context"); @@ -415,6 +531,18 @@ lws_create_context(const struct lws_context_creation_info *info) return NULL; } +#if defined(LWS_WITH_NETWORK) + context->event_loop_ops = plev->ops; +#endif +#if defined(LWS_WITH_EVENT_LIBS) + /* at the very end */ + context->evlib_ctx = (uint8_t *)context + size - + plev->ops->evlib_size_ctx; +#endif +#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) + context->evlib_plugin_list = evlib_plugin_list; +#endif + #if !defined(LWS_PLAT_FREERTOS) context->uid = info->uid; context->gid = info->gid; @@ -460,7 +588,7 @@ lws_create_context(const struct lws_context_creation_info *info) if (info->extensions) lwsl_warn("%s: LWS_WITHOUT_EXTENSIONS but extensions ptr set\n", __func__); #endif -#endif +#endif /* network */ #if defined(LWS_WITH_SECURE_STREAMS) #if !defined(LWS_WITH_SECURE_STREAMS_STATIC_POLICY_ONLY) @@ -603,52 +731,9 @@ lws_create_context(const struct lws_context_creation_info *info) } #if defined(LWS_WITH_NETWORK) - context->token_limits = info->token_limits; - - /* - * set the context event loops ops struct - * - * after this, all event_loop actions use the generic ops - */ - -#if defined(LWS_WITH_POLL) - context->event_loop_ops = &event_loop_ops_poll; #endif - if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)) -#if defined(LWS_WITH_LIBUV) - context->event_loop_ops = &event_loop_ops_uv; -#else - goto fail_event_libs; -#endif - - if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV)) -#if defined(LWS_WITH_LIBEV) - context->event_loop_ops = &event_loop_ops_ev; -#else - goto fail_event_libs; -#endif - - if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT)) -#if defined(LWS_WITH_LIBEVENT) - context->event_loop_ops = &event_loop_ops_event; -#else - goto fail_event_libs; -#endif - - if (lws_check_opt(context->options, LWS_SERVER_OPTION_GLIB)) -#if defined(LWS_WITH_GLIB) - context->event_loop_ops = &event_loop_ops_glib; -#else - goto fail_event_libs; -#endif - - if (!context->event_loop_ops) - goto fail_event_libs; - - lwsl_info("Using event loop: %s\n", context->event_loop_ops->name); -#endif #if defined(LWS_WITH_TLS) && defined(LWS_WITH_NETWORK) time(&context->tls.last_cert_check_s); @@ -728,7 +813,7 @@ lws_create_context(const struct lws_context_creation_info *info) } #endif -n = 0; + n = 0; #if defined(LWS_WITH_NETWORK) context->default_retry.retry_ms_table = default_backoff_table; @@ -773,6 +858,11 @@ n = 0; memset(context->pt[n].fake_wsi, 0, sizeof(struct lws)); #endif +#if defined(LWS_WITH_EVENT_LIBS) + context->pt[n].evlib_pt = u; + u += plev->ops->evlib_size_pt; +#endif + #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) context->pt[n].http.ah_list = NULL; context->pt[n].http.ah_pool_length = 0; @@ -1100,19 +1190,9 @@ bail: return NULL; -#if defined(LWS_WITH_NETWORK) fail_event_libs: - lwsl_err("Requested event library support not configured, available:\n"); - { - extern const struct lws_event_loop_ops *available_event_libs[]; - const struct lws_event_loop_ops **elops = available_event_libs; + lwsl_err("Requested event library support not configured\n"); - while (*elops) { - lwsl_err(" - %s\n", (*elops)->name); - elops++; - } - } -#endif lws_free(context); return NULL; @@ -1282,6 +1362,11 @@ lws_context_destroy3(struct lws_context *context) lws_free(df); }; +#if defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS) + if (context->evlib_plugin_list) + lws_plugins_destroy(&context->evlib_plugin_list, NULL, NULL); +#endif + lws_free(context); lwsl_debug("%s: ctx %p freed\n", __func__, context); diff --git a/lib/core/private-lib-core.h b/lib/core/private-lib-core.h index f38b07a12..ca82651a9 100644 --- a/lib/core/private-lib-core.h +++ b/lib/core/private-lib-core.h @@ -212,56 +212,24 @@ struct lws_ring { struct lws_protocols; struct lws; -#if defined(LWS_WITH_NETWORK) +#if defined(LWS_WITH_NETWORK) /* network */ #include "private-lib-event-libs.h" #if defined(LWS_WITH_SECURE_STREAMS) #include "private-lib-secure-streams.h" #endif - #if defined(LWS_WITH_SYS_SMD) #include "private-lib-system-smd.h" #endif -struct lws_io_watcher { -#ifdef LWS_WITH_LIBEV - struct lws_io_watcher_libev ev; -#endif -#ifdef LWS_WITH_LIBUV - struct lws_io_watcher_libuv uv; -#endif -#ifdef LWS_WITH_LIBEVENT - struct lws_io_watcher_libevent event; -#endif -#ifdef LWS_WITH_GLIB - struct lws_io_watcher_glib glib; -#endif - struct lws_context *context; - - uint8_t actual_events; -}; - -struct lws_signal_watcher { -#ifdef LWS_WITH_LIBEV - struct lws_signal_watcher_libev ev; -#endif -#ifdef LWS_WITH_LIBUV - struct lws_signal_watcher_libuv uv; -#endif -#ifdef LWS_WITH_LIBEVENT - struct lws_signal_watcher_libevent event; -#endif - struct lws_context *context; -}; - struct lws_foreign_thread_pollfd { struct lws_foreign_thread_pollfd *next; int fd_index; int _and; int _or; }; -#endif +#endif /* network */ #if LWS_MAX_SMP > 1 @@ -368,20 +336,13 @@ struct lws_context { * LWS_WITH_NETWORK =====> */ -#if defined(LWS_WITH_LIBEV) - struct lws_context_eventlibs_libev ev; -#endif -#if defined(LWS_WITH_LIBUV) - struct lws_context_eventlibs_libuv uv; -#endif -#if defined(LWS_WITH_LIBEVENT) - struct lws_context_eventlibs_libevent event; -#endif -#if defined(LWS_WITH_GLIB) - struct lws_context_eventlibs_glib glib; +#if defined(LWS_WITH_EVENT_LIBS) + struct lws_plugin *evlib_plugin_list; + void *evlib_ctx; /* overallocated */ #endif + #if defined(LWS_WITH_TLS) - struct lws_context_tls tls; + struct lws_context_tls tls; #endif #if defined(LWS_WITH_DRIVERS) lws_netdevs_t netdevs; @@ -427,7 +388,7 @@ struct lws_context { const char *server_string; #endif - struct lws_event_loop_ops *event_loop_ops; + const struct lws_event_loop_ops *event_loop_ops; #endif #if defined(LWS_WITH_TLS) diff --git a/lib/event-libs/CMakeLists.txt b/lib/event-libs/CMakeLists.txt index 237f484eb..b05c2ec19 100644 --- a/lib/event-libs/CMakeLists.txt +++ b/lib/event-libs/CMakeLists.txt @@ -24,15 +24,50 @@ include_directories(.) +macro(create_evlib_plugin PLUGIN_NAME MAIN_SRC PLUGIN_HDR EVLIB) + + set(PLUGIN_SRCS ${MAIN_SRC}) + + source_group("Headers Private" FILES ${PLUGIN_HDR}) + source_group("Sources" FILES ${MAIN_SRC}) + add_library(websockets-${PLUGIN_NAME} SHARED ${MAIN_SRC} ${PLUGIN_HDR}) + + foreach(libpath ${LWS_DEP_LIB_PATHS}) + target_link_directories(${TEST_NAME} ${libpath}) + endforeach() + + target_link_libraries(websockets-${PLUGIN_NAME} websockets_shared ${EVLIB}) + add_dependencies(websockets-${PLUGIN_NAME} websockets_shared) + + target_include_directories(websockets-${PLUGIN_NAME} PRIVATE + ${PLUGIN_INCLUDE} ${LWS_LIB_BUILD_INC_PATHS}) + + # Set test app specific defines. + # set_property(TARGET ${PLUGIN_NAME} + # PROPERTY COMPILE_DEFINITIONS + # INSTALL_DATADIR="${CMAKE_INSTALL_PREFIX}/evlib-plugins" + #) + + set(CMAKE_POSITION_INDEPENDENT_CODE ON) + + install(TARGETS websockets-${PLUGIN_NAME} + EXPORT LibwebsocketsTargets + LIBRARY DESTINATION "${LWS_INSTALL_LIB_DIR}${LIB_SUFFIX}" + COMPONENT ${PLUGIN_NAME}) + + list(APPEND EVLIB_PLUGINS_LIST websockets-${PLUGIN_NAME}) + +endmacro() + # -# These can coexist, except libev conflicts with libevent +# poll support gets built into the lib as the default # if (LWS_WITH_POLL) add_subdir_include_directories(poll) endif() -if (LWS_WITH_LIBUV) +if (LWS_WITH_LIBUV OR LWS_WITH_LIBUV_INTERNAL) add_subdir_include_directories(libuv) set(LWS_HAVE_UV_VERSION_H ${LWS_HAVE_UV_VERSION_H} PARENT_SCOPE) set(LWS_HAVE_NEW_UV_VERSION_H ${LWS_HAVE_NEW_UV_VERSION_H} PARENT_SCOPE) @@ -52,8 +87,12 @@ if (LWS_WITH_LIBEV) set(LWS_HAVE_EVBACKEND_IOURING ${LWS_HAVE_EVBACKEND_IOURING} PARENT_SCOPE) endif() + + # # Keep explicit parent scope exports at end # export_to_parent_intermediate() +set(EVLIB_PLUGINS_LIST ${EVLIB_PLUGINS_LIST} PARENT_SCOPE) + diff --git a/lib/event-libs/glib/CMakeLists.txt b/lib/event-libs/glib/CMakeLists.txt index 598572407..90b5222b8 100644 --- a/lib/event-libs/glib/CMakeLists.txt +++ b/lib/event-libs/glib/CMakeLists.txt @@ -52,13 +52,24 @@ endif() message("glib include dir: ${GLIB_INCLUDE_DIRS}") message("glib libraries: ${GLIB_LIBRARIES}") include_directories("${GLIB_INCLUDE_DIRS}") -list(APPEND LIB_LIST ${GLIB_LIBRARIES}) -if (LWS_WITH_NETWORK) - list(APPEND SOURCES - event-libs/glib/glib.c) +if (LWS_WITH_EVLIB_PLUGINS) + + create_evlib_plugin(evlib_glib + glib.c + private-lib-event-libs-glib.h + ${GLIB_LIBRARIES}) + +else() + + list(APPEND LIB_LIST ${GLIB_LIBRARIES}) + + if (LWS_WITH_NETWORK) + list(APPEND SOURCES + event-libs/glib/glib.c) + endif() + endif() - # # Keep explicit parent scope exports at end # diff --git a/lib/event-libs/glib/glib.c b/lib/event-libs/glib/glib.c index 696a0de3f..e5c01ec9c 100644 --- a/lib/event-libs/glib/glib.c +++ b/lib/event-libs/glib/glib.c @@ -26,13 +26,18 @@ #include +#include "private-lib-event-libs-glib.h" + #if !defined(G_SOURCE_FUNC) #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f)) #endif -#define wsi_to_subclass(_w) ((_w)->w_read.glib.source) +#define pt_to_priv_glib(_pt) ((struct lws_pt_eventlibs_glib *)(_pt)->evlib_pt) +#define wsi_to_priv_glib(_w) ((struct lws_wsi_eventlibs_glib *)(_w)->evlib_wsi) + +#define wsi_to_subclass(_w) (wsi_to_priv_glib(_w)->w_read.source) #define wsi_to_gsource(_w) ((GSource *)wsi_to_subclass(_w)) -#define pt_to_loop(_pt) ((_pt)->glib.loop) +#define pt_to_loop(_pt) (pt_to_priv_glib(_pt)->loop) #define pt_to_g_main_context(_pt) g_main_loop_get_context(pt_to_loop(_pt)) #define lws_gs_valid(t) (t.gs) @@ -68,17 +73,17 @@ lws_glib_check(GSource *src) static int lws_glib_set_idle(struct lws_context_per_thread *pt) { - if (lws_gs_valid(pt->glib.idle)) + if (lws_gs_valid(pt_to_priv_glib(pt)->idle)) return 0; - pt->glib.idle.gs = g_idle_source_new(); - if (!pt->glib.idle.gs) + pt_to_priv_glib(pt)->idle.gs = g_idle_source_new(); + if (!pt_to_priv_glib(pt)->idle.gs) return 1; - g_source_set_callback(pt->glib.idle.gs, lws_glib_idle_timer_cb, pt, - NULL); - pt->glib.idle.tag = g_source_attach(pt->glib.idle.gs, - pt_to_g_main_context(pt)); + g_source_set_callback(pt_to_priv_glib(pt)->idle.gs, + lws_glib_idle_timer_cb, pt, NULL); + pt_to_priv_glib(pt)->idle.tag = g_source_attach( + pt_to_priv_glib(pt)->idle.gs, pt_to_g_main_context(pt)); return 0; } @@ -86,16 +91,17 @@ lws_glib_set_idle(struct lws_context_per_thread *pt) static int lws_glib_set_timeout(struct lws_context_per_thread *pt, unsigned int ms) { - lws_gs_destroy(pt->glib.hrtimer); + lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer); - pt->glib.hrtimer.gs = g_timeout_source_new(ms); - if (!pt->glib.hrtimer.gs) + pt_to_priv_glib(pt)->hrtimer.gs = g_timeout_source_new(ms); + if (!pt_to_priv_glib(pt)->hrtimer.gs) return 1; - g_source_set_callback(pt->glib.hrtimer.gs, lws_glib_hrtimer_cb, pt, - NULL); - pt->glib.hrtimer.tag = g_source_attach(pt->glib.hrtimer.gs, - pt_to_g_main_context(pt)); + g_source_set_callback(pt_to_priv_glib(pt)->hrtimer.gs, + lws_glib_hrtimer_cb, pt, NULL); + pt_to_priv_glib(pt)->hrtimer.tag = g_source_attach( + pt_to_priv_glib(pt)->hrtimer.gs, + pt_to_g_main_context(pt)); return 0; } @@ -135,7 +141,7 @@ lws_glib_dispatch(GSource *src, GSourceFunc x, gpointer userData) lws_service_fd_tsi(sub->wsi->a.context, &eventfd, sub->wsi->tsi); - if (!lws_gs_valid(pt->glib.idle)) + if (!lws_gs_valid(pt_to_priv_glib(pt)->idle)) lws_glib_set_idle(pt); if (pt->destroy_self) @@ -166,7 +172,7 @@ lws_glib_hrtimer_cb(void *p) lws_pt_lock(pt, __func__); - lws_gs_destroy(pt->glib.hrtimer); + lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer); us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs()); @@ -217,7 +223,7 @@ lws_glib_idle_timer_cb(void *p) * We reenable the idle callback on the next network or scheduled event */ - lws_gs_destroy(pt->glib.idle); + lws_gs_destroy(pt_to_priv_glib(pt)->idle); return FALSE; } @@ -242,12 +248,12 @@ static int elops_init_context_glib(struct lws_context *context, const struct lws_context_creation_info *info) { - int n; +// int n; context->eventlib_signal_cb = info->signal_cb; - for (n = 0; n < context->count_threads; n++) - context->pt[n].w_sigint.context = context; +// for (n = 0; n < context->count_threads; n++) +// pt_to_priv_glib(&context->pt[n])->w_sigint.context = context; return 0; } @@ -256,6 +262,7 @@ static int elops_accept_glib(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_wsi_eventlibs_glib *wsipr = wsi_to_priv_glib(wsi); int fd; assert(!wsi_to_subclass(wsi)); @@ -266,7 +273,7 @@ elops_accept_glib(struct lws *wsi) if (!wsi_to_subclass(wsi)) return 1; - wsi->w_read.context = wsi->a.context; + wsipr->w_read.context = wsi->a.context; wsi_to_subclass(wsi)->wsi = wsi; if (wsi->role_ops->file_handle) @@ -276,7 +283,7 @@ elops_accept_glib(struct lws *wsi) wsi_to_subclass(wsi)->tag = g_source_add_unix_fd(wsi_to_gsource(wsi), fd, (GIOCondition)LWS_POLLIN); - wsi->w_read.actual_events = LWS_POLLIN; + wsipr->w_read.actual_events = LWS_POLLIN; g_source_set_callback(wsi_to_gsource(wsi), G_SOURCE_FUNC(lws_service_fd), wsi->a.context, NULL); @@ -290,6 +297,7 @@ static int elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt); struct lws_vhost *vh = context->vhost_list; GMainLoop *loop = (GMainLoop *)_loop; @@ -304,7 +312,7 @@ elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi) return -1; } - pt->glib.loop = loop; + ptpr->loop = loop; /* * Initialize all events with the listening sockets @@ -325,7 +333,7 @@ elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi) if (pt->event_loop_foreign) return 0; - pt->glib.sigint.tag = g_unix_signal_add(SIGINT, + ptpr->sigint.tag = g_unix_signal_add(SIGINT, G_SOURCE_FUNC(lws_glib_sigint_cb), pt); return 0; @@ -339,9 +347,11 @@ static void elops_io_glib(struct lws *wsi, int flags) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; - GIOCondition cond = wsi->w_read.actual_events | G_IO_ERR; + struct lws_wsi_eventlibs_glib *wsipr = wsi_to_priv_glib(wsi); + GIOCondition cond = wsipr->w_read.actual_events | G_IO_ERR; - if (!pt_to_loop(pt) || wsi->a.context->being_destroyed || pt->is_destroyed) + if (!pt_to_loop(pt) || wsi->a.context->being_destroyed || + pt->is_destroyed) return; if (!wsi_to_subclass(wsi)) @@ -366,7 +376,7 @@ elops_io_glib(struct lws *wsi, int flags) cond |= G_IO_OUT; } - wsi->w_read.actual_events = cond; + wsipr->w_read.actual_events = cond; lwsl_debug("%s: wsi %p, fd %d, 0x%x/0x%x\n", __func__, wsi, wsi->desc.sockfd, flags, (int)cond); @@ -414,6 +424,7 @@ static void elops_destroy_pt_glib(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt); struct lws_vhost *vh = context->vhost_list; if (!pt_to_loop(pt)) @@ -429,12 +440,12 @@ elops_destroy_pt_glib(struct lws_context *context, int tsi) vh = vh->vhost_next; } - lws_gs_destroy(pt->glib.idle); - lws_gs_destroy(pt->glib.hrtimer); + lws_gs_destroy(ptpr->idle); + lws_gs_destroy(ptpr->hrtimer); if (!pt->event_loop_foreign) { g_main_loop_quit(pt_to_loop(pt)); - lws_gs_destroy(pt->glib.sigint); + lws_gs_destroy(ptpr->sigint); g_main_loop_unref(pt_to_loop(pt)); } @@ -464,7 +475,7 @@ elops_wsi_logical_close_glib(struct lws *wsi) return 0; } -struct lws_event_loop_ops event_loop_ops_glib = { +static const struct lws_event_loop_ops event_loop_ops_glib = { /* name */ "glib", /* init_context */ elops_init_context_glib, /* destroy_context1 */ NULL, @@ -481,4 +492,22 @@ struct lws_event_loop_ops event_loop_ops_glib = { /* destroy wsi */ elops_destroy_wsi_glib, /* flags */ LELOF_DESTROY_FINAL, + + /* evlib_size_ctx */ 0, + /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_glib), + /* evlib_size_vh */ 0, + /* evlib_size_wsi */ sizeof(struct lws_io_watcher_glib), +}; + +#if defined(LWS_WITH_EVLIB_PLUGINS) +LWS_VISIBLE +#endif +const lws_plugin_evlib_t evlib_glib = { + .hdr = { + "glib event loop", + "lws_evlib_plugin", + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_glib }; diff --git a/lib/event-libs/glib/private-lib-event-libs-glib.h b/lib/event-libs/glib/private-lib-event-libs-glib.h index 4de461f96..cd976f895 100644 --- a/lib/event-libs/glib/private-lib-event-libs-glib.h +++ b/lib/event-libs/glib/private-lib-event-libs-glib.h @@ -41,6 +41,8 @@ struct lws_pt_eventlibs_glib { lws_glib_tag_t hrtimer; lws_glib_tag_t sigint; lws_glib_tag_t idle; + + //struct lws_signal_watcher_libuv w_sigint; }; struct lws_io_watcher_glib_subclass { @@ -55,10 +57,11 @@ struct lws_io_watcher_glib_subclass { struct lws_io_watcher_glib { struct lws_io_watcher_glib_subclass *source; /* these are created and destroyed by glib */ + struct lws_context *context; + uint8_t actual_events; }; -struct lws_context_eventlibs_glib { - //int placeholder; +struct lws_wsi_eventlibs_glib { + struct lws_io_watcher_glib w_read; }; -extern struct lws_event_loop_ops event_loop_ops_glib; diff --git a/lib/event-libs/libev/CMakeLists.txt b/lib/event-libs/libev/CMakeLists.txt index a638fd51a..9fc8540ff 100644 --- a/lib/event-libs/libev/CMakeLists.txt +++ b/lib/event-libs/libev/CMakeLists.txt @@ -40,7 +40,6 @@ endif() message("libev include dir: ${LIBEV_INCLUDE_DIRS}") message("libev libraries: ${LIBEV_LIBRARIES}") include_directories("${LIBEV_INCLUDE_DIRS}") -list(APPEND LIB_LIST ${LIBEV_LIBRARIES}) if ("${LWS_LIBEV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEV_INCLUDE_DIRS}" STREQUAL "") else() @@ -48,13 +47,26 @@ else() set(LIBEV_INCLUDE_DIRS ${LWS_LIBEV_INCLUDE_DIRS}) endif() -list(APPEND SOURCES - event-libs/libev/libev.c) +if (LWS_WITH_EVLIB_PLUGINS) + + create_evlib_plugin( + evlib_ev + libev.c + private-lib-event-libs-libev.h + ${LIBEV_LIBRARIES}) + +else() + + list(APPEND LIB_LIST ${LIBEV_LIBRARIES}) + + list(APPEND SOURCES + event-libs/libev/libev.c) # see README.build.md for discussion of why of the supported event libs, # only libev cannot cope with -Werror -set_source_files_properties(event-libs/libev/libev.c - PROPERTIES COMPILE_FLAGS "-Wno-error" ) - + set_source_files_properties(event-libs/libev/libev.c + PROPERTIES COMPILE_FLAGS "-Wno-error" ) +endif() + set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST}) CHECK_C_SOURCE_COMPILES( diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c index 586beaf78..c20995de0 100644 --- a/lib/event-libs/libev/libev.c +++ b/lib/event-libs/libev/libev.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 - 2019 Andy Green + * Copyright (C) 2010 - 2020 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -23,20 +23,26 @@ */ #include "private-lib-core.h" +#include "private-lib-event-libs-libev.h" + +#define pt_to_priv_ev(_pt) ((struct lws_pt_eventlibs_libev *)(_pt)->evlib_pt) +#define vh_to_priv_ev(_vh) ((struct lws_vh_eventlibs_libev *)(_vh)->evlib_vh) +#define wsi_to_priv_ev(_w) ((struct lws_wsi_eventlibs_libev *)(_w)->evlib_wsi) static void lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) { - struct lws_context_per_thread *pt = - (struct lws_context_per_thread *)watcher->data; + struct lws_pt_eventlibs_libev *ptpr = lws_container_of(watcher, + struct lws_pt_eventlibs_libev, hrtimer); + struct lws_context_per_thread *pt = ptpr->pt; lws_usec_t us; lws_pt_lock(pt, __func__); us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs()); if (us) { - ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0); - ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer); + ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0); + ev_timer_start(ptpr->io_loop, &ptpr->hrtimer); } lws_pt_unlock(pt); } @@ -44,10 +50,11 @@ lws_ev_hrtimer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) static void lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents) { - struct lws_context_per_thread *pt = lws_container_of(handle, - struct lws_context_per_thread, ev.idle); - lws_usec_t us; + struct lws_pt_eventlibs_libev *ptpr = lws_container_of(handle, + struct lws_pt_eventlibs_libev, idle); + struct lws_context_per_thread *pt = ptpr->pt; int reschedule = 0; + lws_usec_t us; lws_service_do_ripe_rxflow(pt); @@ -64,8 +71,8 @@ lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents) us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs()); if (us) { - ev_timer_set(&pt->ev.hrtimer, ((float)us) / 1000000.0, 0); - ev_timer_start(pt->ev.io_loop, &pt->ev.hrtimer); + ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0); + ev_timer_start(ptpr->io_loop, &ptpr->hrtimer); } lws_pt_unlock(pt); @@ -80,9 +87,10 @@ lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents) static void lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) { - struct lws_io_watcher *lws_io = lws_container_of(watcher, - struct lws_io_watcher, ev.watcher); + struct lws_io_watcher_libev *lws_io = lws_container_of(watcher, + struct lws_io_watcher_libev, watcher); struct lws_context *context = lws_io->context; + struct lws_pt_eventlibs_libev *ptpr; struct lws_context_per_thread *pt; struct lws_pollfd eventfd; struct lws *wsi; @@ -105,10 +113,11 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) wsi = wsi_from_fd(context, watcher->fd); pt = &context->pt[(int)wsi->tsi]; + ptpr = pt_to_priv_ev(pt); lws_service_fd_tsi(context, &eventfd, (int)wsi->tsi); - ev_idle_start(pt->ev.io_loop, &pt->ev.idle); + ev_idle_start(ptpr->io_loop, &ptpr->idle); } void @@ -128,7 +137,8 @@ static int elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; - struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev.watcher; + struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); + struct ev_signal *w_sigint = &ptpr->w_sigint.watcher; struct ev_loop *loop = (struct ev_loop *)_loop; struct lws_vhost *vh = context->vhost_list; const char *backend_name; @@ -137,6 +147,8 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) lwsl_info("%s: loop %p\n", __func__, _loop); + ptpr->pt = pt; + if (!loop) loop = ev_loop_new(0); else @@ -148,7 +160,7 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) return -1; } - pt->ev.io_loop = loop; + ptpr->io_loop = loop; /* * Initialize the accept w_accept with all the listening sockets @@ -156,13 +168,17 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) */ while (vh) { if (vh->lserv_wsi) { - vh->lserv_wsi->w_read.context = context; - vh->w_accept.context = context; + struct lws_wsi_eventlibs_libev *w = + wsi_to_priv_ev(vh->lserv_wsi); - ev_io_init(&vh->w_accept.ev.watcher, lws_accept_cb, + w->w_read.context = context; + w->w_write.context = context; + vh_to_priv_ev(vh)->w_accept.context = context; + + ev_io_init(&vh_to_priv_ev(vh)->w_accept.watcher, + lws_accept_cb, vh->lserv_wsi->desc.sockfd, EV_READ); - ev_io_start(loop, &vh->w_accept.ev.watcher); - + ev_io_start(loop, &vh_to_priv_ev(vh)->w_accept.watcher); } vh = vh->vhost_next; } @@ -212,10 +228,10 @@ elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi) lwsl_info(" libev backend: %s\n", backend_name); (void)backend_name; - ev_timer_init(&pt->ev.hrtimer, lws_ev_hrtimer_cb, 0, 0); - pt->ev.hrtimer.data = pt; + ev_timer_init(&ptpr->hrtimer, lws_ev_hrtimer_cb, 0, 0); + ptpr->hrtimer.data = pt; - ev_idle_init(&pt->ev.idle, lws_ev_idle_cb); + ev_idle_init(&ptpr->idle, lws_ev_idle_cb); return status; } @@ -224,21 +240,23 @@ static void elops_destroy_pt_ev(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); struct lws_vhost *vh = context->vhost_list; while (vh) { if (vh->lserv_wsi) - ev_io_stop(pt->ev.io_loop, &vh->w_accept.ev.watcher); + ev_io_stop(ptpr->io_loop, + &vh_to_priv_ev(vh)->w_accept.watcher); vh = vh->vhost_next; } /* static assets */ - ev_timer_stop(pt->ev.io_loop, &pt->ev.hrtimer); - ev_idle_stop(pt->ev.io_loop, &pt->ev.idle); + ev_timer_stop(ptpr->io_loop, &ptpr->hrtimer); + ev_idle_stop(ptpr->io_loop, &ptpr->idle); if (!pt->event_loop_foreign) - ev_signal_stop(pt->ev.io_loop, &pt->w_sigint.ev.watcher); + ev_signal_stop(ptpr->io_loop, &ptpr->w_sigint.watcher); } static int @@ -250,7 +268,7 @@ elops_init_context_ev(struct lws_context *context, context->eventlib_signal_cb = info->signal_cb; for (n = 0; n < context->count_threads; n++) - context->pt[n].w_sigint.context = context; + pt_to_priv_ev(&context->pt[n])->w_sigint.context = context; return 0; } @@ -258,18 +276,21 @@ elops_init_context_ev(struct lws_context *context, static int elops_accept_ev(struct lws *wsi) { + struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi); int fd; + lwsl_notice("%s\n", __func__); + if (wsi->role_ops->file_handle) fd = wsi->desc.filefd; else fd = wsi->desc.sockfd; - wsi->w_read.context = wsi->a.context; - wsi->w_write.context = wsi->a.context; + w->w_read.context = wsi->a.context; + w->w_write.context = wsi->a.context; - ev_io_init(&wsi->w_read.ev.watcher, lws_accept_cb, fd, EV_READ); - ev_io_init(&wsi->w_write.ev.watcher, lws_accept_cb, fd, EV_WRITE); + ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ); + ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE); return 0; } @@ -278,8 +299,14 @@ static void elops_io_ev(struct lws *wsi, int flags) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); + struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi); - if (!pt->ev.io_loop || pt->is_destroyed) + lwsl_notice("%s: wsi %p %s flags 0x%x %p %d\n", __func__, + wsi, wsi->role_ops->name, flags, + ptpr->io_loop, pt->is_destroyed); + + if (!ptpr->io_loop || pt->is_destroyed) return; assert((flags & (LWS_EV_START | LWS_EV_STOP)) && @@ -287,14 +314,14 @@ elops_io_ev(struct lws *wsi, int flags) if (flags & LWS_EV_START) { if (flags & LWS_EV_WRITE) - ev_io_start(pt->ev.io_loop, &wsi->w_write.ev.watcher); + ev_io_start(ptpr->io_loop, &w->w_write.watcher); if (flags & LWS_EV_READ) - ev_io_start(pt->ev.io_loop, &wsi->w_read.ev.watcher); + ev_io_start(ptpr->io_loop, &w->w_read.watcher); } else { if (flags & LWS_EV_WRITE) - ev_io_stop(pt->ev.io_loop, &wsi->w_write.ev.watcher); + ev_io_stop(ptpr->io_loop, &w->w_write.watcher); if (flags & LWS_EV_READ) - ev_io_stop(pt->ev.io_loop, &wsi->w_read.ev.watcher); + ev_io_stop(ptpr->io_loop, &w->w_read.watcher); } if (pt->destroy_self) @@ -304,14 +331,15 @@ elops_io_ev(struct lws *wsi, int flags) static void elops_run_pt_ev(struct lws_context *context, int tsi) { - if (context->pt[tsi].ev.io_loop) - ev_run(context->pt[tsi].ev.io_loop, 0); + if (pt_to_priv_ev(&context->pt[tsi])->io_loop) + ev_run(pt_to_priv_ev(&context->pt[tsi])->io_loop, 0); } static int elops_destroy_context2_ev(struct lws_context *context) { struct lws_context_per_thread *pt; + struct lws_pt_eventlibs_libev *ptpr; int n, m; lwsl_debug("%s\n", __func__); @@ -320,21 +348,22 @@ elops_destroy_context2_ev(struct lws_context *context) int budget = 1000; pt = &context->pt[n]; + ptpr = pt_to_priv_ev(pt); /* only for internal loops... */ - if (pt->event_loop_foreign || !pt->ev.io_loop) + if (pt->event_loop_foreign || !ptpr->io_loop) continue; if (!context->finalize_destroy_after_internal_loops_stopped) { - ev_break(pt->ev.io_loop, EVBREAK_ONE); + ev_break(ptpr->io_loop, EVBREAK_ONE); continue; } while (budget-- && - (m = ev_run(pt->ev.io_loop, 0))) + (m = ev_run(ptpr->io_loop, 0))) ; - ev_loop_destroy(pt->ev.io_loop); + ev_loop_destroy(ptpr->io_loop); } return 0; @@ -343,6 +372,7 @@ elops_destroy_context2_ev(struct lws_context *context) static int elops_init_vhost_listen_wsi_ev(struct lws *wsi) { + struct lws_wsi_eventlibs_libev *w; int fd; if (!wsi) { @@ -350,16 +380,17 @@ elops_init_vhost_listen_wsi_ev(struct lws *wsi) return 0; } - wsi->w_read.context = wsi->a.context; - wsi->w_write.context = wsi->a.context; + w = wsi_to_priv_ev(wsi); + w->w_read.context = wsi->a.context; + w->w_write.context = wsi->a.context; if (wsi->role_ops->file_handle) fd = wsi->desc.filefd; else fd = wsi->desc.sockfd; - ev_io_init(&wsi->w_read.ev.watcher, lws_accept_cb, fd, EV_READ); - ev_io_init(&wsi->w_write.ev.watcher, lws_accept_cb, fd, EV_WRITE); + ev_io_init(&w->w_read.watcher, lws_accept_cb, fd, EV_READ); + //ev_io_init(&w->w_write.watcher, lws_accept_cb, fd, EV_WRITE); elops_io_ev(wsi, LWS_EV_START | LWS_EV_READ); @@ -370,12 +401,14 @@ static void elops_destroy_wsi_ev(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt); + struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi); - ev_io_stop(pt->ev.io_loop, &wsi->w_read.ev.watcher); - ev_io_stop(pt->ev.io_loop, &wsi->w_write.ev.watcher); + ev_io_stop(ptpr->io_loop, &w->w_read.watcher); + ev_io_stop(ptpr->io_loop, &w->w_write.watcher); } -struct lws_event_loop_ops event_loop_ops_ev = { +static const struct lws_event_loop_ops event_loop_ops_ev = { /* name */ "libev", /* init_context */ elops_init_context_ev, /* destroy_context1 */ NULL, @@ -392,4 +425,22 @@ struct lws_event_loop_ops event_loop_ops_ev = { /* destroy wsi */ elops_destroy_wsi_ev, /* flags */ 0, + + /* evlib_size_ctx */ 0, + /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_libev), + /* evlib_size_vh */ sizeof(struct lws_vh_eventlibs_libev), + /* evlib_size_wsi */ sizeof(struct lws_wsi_eventlibs_libev), +}; + +#if defined(LWS_WITH_EVLIB_PLUGINS) +LWS_VISIBLE +#endif +const lws_plugin_evlib_t evlib_ev = { + .hdr = { + "libev event loop", + "lws_evlib_plugin", + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_ev }; diff --git a/lib/event-libs/libev/private-lib-event-libs-libev.h b/lib/event-libs/libev/private-lib-event-libs-libev.h index e3d12dca0..5ea002f8f 100644 --- a/lib/event-libs/libev/private-lib-event-libs-libev.h +++ b/lib/event-libs/libev/private-lib-event-libs-libev.h @@ -33,22 +33,30 @@ (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-> \ count_event_loop_static_asset_handles)) +struct lws_signal_watcher_libev { + ev_signal watcher; + struct lws_context *context; +}; + struct lws_pt_eventlibs_libev { struct ev_loop *io_loop; struct ev_timer hrtimer; struct ev_idle idle; + struct lws_signal_watcher_libev w_sigint; + struct lws_context_per_thread *pt; }; struct lws_io_watcher_libev { ev_io watcher; + struct lws_context *context; }; -struct lws_signal_watcher_libev { - ev_signal watcher; +struct lws_vh_eventlibs_libev { + struct lws_io_watcher_libev w_accept; }; -struct lws_context_eventlibs_libev { - int placeholder; +struct lws_wsi_eventlibs_libev { + struct lws_io_watcher_libev w_read; + struct lws_io_watcher_libev w_write; }; -extern struct lws_event_loop_ops event_loop_ops_ev; diff --git a/lib/event-libs/libevent/CMakeLists.txt b/lib/event-libs/libevent/CMakeLists.txt index eb0689586..44041785f 100644 --- a/lib/event-libs/libevent/CMakeLists.txt +++ b/lib/event-libs/libevent/CMakeLists.txt @@ -40,18 +40,29 @@ endif() message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}") message("libevent libraries: ${LIBEVENT_LIBRARIES}") include_directories("${LIBEVENT_INCLUDE_DIRS}") -list(APPEND LIB_LIST ${LIBEVENT_LIBRARIES}) if ("${LWS_LIBEVENT_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEVENT_INCLUDE_DIRS}" STREQUAL "") else() set(LIBEVENT_LIBRARIES ${LWS_LIBEVENT_LIBRARIES}) set(LIBEVENT_INCLUDE_DIRS ${LWS_LIBEVENT_INCLUDE_DIRS}) - set(LIBEVENT_FOUND 1 PARENT_SCOPE) endif() -if (LWS_WITH_NETWORK) - list(APPEND SOURCES - event-libs/libevent/libevent.c) + +if (LWS_WITH_EVLIB_PLUGINS) + + create_evlib_plugin(evlib_event + libevent.c + private-lib-event-libs-libevent.h + ${LIBEVENT_LIBRARIES}) + +else() + + list(APPEND LIB_LIST ${LIBEVENT_LIBRARIES}) + set(LIBEVENT_FOUND 1 PARENT_SCOPE) + if (LWS_WITH_NETWORK) + list(APPEND SOURCES + event-libs/libevent/libevent.c) + endif() endif() # diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c index 10035bc6c..1191b6e78 100644 --- a/lib/event-libs/libevent/libevent.c +++ b/lib/event-libs/libevent/libevent.c @@ -23,11 +23,16 @@ */ #include "private-lib-core.h" +#include "private-lib-event-libs-libevent.h" + +#define pt_to_priv_event(_pt) ((struct lws_pt_eventlibs_libevent *)(_pt)->evlib_pt) +#define wsi_to_priv_event(_w) ((struct lws_wsi_eventlibs_libevent *)(_w)->evlib_wsi) static void lws_event_hrtimer_cb(int fd, short event, void *p) { struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); struct timeval tv; lws_usec_t us; @@ -37,7 +42,7 @@ lws_event_hrtimer_cb(int fd, short event, void *p) if (us) { tv.tv_sec = us / LWS_US_PER_SEC; tv.tv_usec = us - (tv.tv_sec * LWS_US_PER_SEC); - evtimer_add(pt->event.hrtimer, &tv); + evtimer_add(ptpr->hrtimer, &tv); } lws_pt_unlock(pt); } @@ -46,6 +51,7 @@ static void lws_event_idle_timer_cb(int fd, short event, void *p) { struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); struct timeval tv; lws_usec_t us; @@ -66,7 +72,7 @@ lws_event_idle_timer_cb(int fd, short event, void *p) tv.tv_sec = 0; tv.tv_usec = 1000; - evtimer_add(pt->event.idle_timer, &tv); + evtimer_add(ptpr->idle_timer, &tv); return; } @@ -82,11 +88,10 @@ lws_event_idle_timer_cb(int fd, short event, void *p) if (us) { tv.tv_sec = us / LWS_US_PER_SEC; tv.tv_usec = us - (tv.tv_sec * LWS_US_PER_SEC); - evtimer_add(pt->event.hrtimer, &tv); + evtimer_add(ptpr->hrtimer, &tv); } lws_pt_unlock(pt); - if (pt->destroy_self) lws_context_destroy(pt->context); } @@ -94,7 +99,8 @@ lws_event_idle_timer_cb(int fd, short event, void *p) static void lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx) { - struct lws_io_watcher *lws_io = (struct lws_io_watcher *)ctx; + struct lws_signal_watcher_libevent *lws_io = + (struct lws_signal_watcher_libevent *)ctx; struct lws_context *context = lws_io->context; struct lws_context_per_thread *pt; struct lws_pollfd eventfd; @@ -145,7 +151,7 @@ lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx) tv.tv_sec = 0; tv.tv_usec = 1000; - evtimer_add(pt->event.idle_timer, &tv); + evtimer_add(pt_to_priv_event(pt)->idle_timer, &tv); } void @@ -161,16 +167,16 @@ lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx) return; } if (!pt->event_loop_foreign) - event_base_loopbreak(pt->event.io_loop); + event_base_loopbreak(pt_to_priv_event(pt)->io_loop); } - static int elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) { struct lws_vhost *vh = context->vhost_list; struct event_base *loop = (struct event_base *)_loop; struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); lwsl_info("%s: loop %p\n", __func__, _loop); @@ -185,7 +191,7 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) return -1; } - pt->event.io_loop = loop; + ptpr->io_loop = loop; /* * Initialize all events with the listening sockets @@ -194,23 +200,26 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) while (vh) { if (vh->lserv_wsi) { - vh->lserv_wsi->w_read.context = context; - vh->lserv_wsi->w_read.event.watcher = event_new( + struct lws_io_watcher_libevent *w_read = + &(wsi_to_priv_event(vh->lserv_wsi)->w_read); + + w_read->context = context; + w_read->watcher = event_new( loop, vh->lserv_wsi->desc.sockfd, (EV_READ | EV_PERSIST), lws_event_cb, - &vh->lserv_wsi->w_read); - event_add(vh->lserv_wsi->w_read.event.watcher, NULL); - vh->lserv_wsi->w_read.event.set = 1; + w_read); + event_add(w_read->watcher, NULL); + w_read->set = 1; } vh = vh->vhost_next; } /* static event loop objects */ - pt->event.hrtimer = event_new(loop, -1, EV_PERSIST, + ptpr->hrtimer = event_new(loop, -1, EV_PERSIST, lws_event_hrtimer_cb, pt); - pt->event.idle_timer = event_new(loop, -1, 0, + ptpr->idle_timer = event_new(loop, -1, 0, lws_event_idle_timer_cb, pt); /* Register the signal watcher unless it's a foreign loop */ @@ -218,9 +227,9 @@ elops_init_pt_event(struct lws_context *context, void *_loop, int tsi) if (pt->event_loop_foreign) return 0; - pt->w_sigint.event.watcher = evsignal_new(loop, SIGINT, + ptpr->w_sigint.watcher = evsignal_new(loop, SIGINT, lws_event_sigint_cb, pt); - event_add(pt->w_sigint.event.watcher, NULL); + event_add(ptpr->w_sigint.watcher, NULL); return 0; } @@ -234,7 +243,7 @@ elops_init_context_event(struct lws_context *context, context->eventlib_signal_cb = info->signal_cb; for (n = 0; n < context->count_threads; n++) - context->pt[n].w_sigint.context = context; + pt_to_priv_event(&context->pt[n])->w_sigint.context = context; return 0; } @@ -244,23 +253,26 @@ elops_accept_event(struct lws *wsi) { struct lws_context *context = lws_get_context(wsi); struct lws_context_per_thread *pt; + struct lws_pt_eventlibs_libevent *ptpr; + struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi); int fd; - wsi->w_read.context = context; - wsi->w_write.context = context; + wpr->w_read.context = context; + wpr->w_write.context = context; // Initialize the event pt = &context->pt[(int)wsi->tsi]; + ptpr = pt_to_priv_event(pt); if (wsi->role_ops->file_handle) fd = wsi->desc.filefd; else fd = wsi->desc.sockfd; - wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd, - (EV_READ | EV_PERSIST), lws_event_cb, &wsi->w_read); - wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd, - (EV_WRITE | EV_PERSIST), lws_event_cb, &wsi->w_write); + wpr->w_read.watcher = event_new(ptpr->io_loop, fd, + (EV_READ | EV_PERSIST), lws_event_cb, &wpr->w_read); + wpr->w_write.watcher = event_new(ptpr->io_loop, fd, + (EV_WRITE | EV_PERSIST), lws_event_cb, &wpr->w_write); return 0; } @@ -269,8 +281,10 @@ static void elops_io_event(struct lws *wsi, int flags) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); + struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi); - if (!pt->event.io_loop || wsi->a.context->being_destroyed || + if (!ptpr->io_loop || wsi->a.context->being_destroyed || pt->is_destroyed) return; @@ -278,24 +292,24 @@ elops_io_event(struct lws *wsi, int flags) (flags & (LWS_EV_READ | LWS_EV_WRITE))); if (flags & LWS_EV_START) { - if ((flags & LWS_EV_WRITE) && !wsi->w_write.event.set) { - event_add(wsi->w_write.event.watcher, NULL); - wsi->w_write.event.set = 1; + if ((flags & LWS_EV_WRITE) && !wpr->w_write.set) { + event_add(wpr->w_write.watcher, NULL); + wpr->w_write.set = 1; } - if ((flags & LWS_EV_READ) && !wsi->w_read.event.set) { - event_add(wsi->w_read.event.watcher, NULL); - wsi->w_read.event.set = 1; + if ((flags & LWS_EV_READ) && !wpr->w_read.set) { + event_add(wpr->w_read.watcher, NULL); + wpr->w_read.set = 1; } } else { - if ((flags & LWS_EV_WRITE) && wsi->w_write.event.set) { - event_del(wsi->w_write.event.watcher); - wsi->w_write.event.set = 0; + if ((flags & LWS_EV_WRITE) && wpr->w_write.set) { + event_del(wpr->w_write.watcher); + wpr->w_write.set = 0; } - if ((flags & LWS_EV_READ) && wsi->w_read.event.set) { - event_del(wsi->w_read.event.watcher); - wsi->w_read.event.set = 0; + if ((flags & LWS_EV_READ) && wpr->w_read.set) { + event_del(wpr->w_read.watcher); + wpr->w_read.set = 0; } } } @@ -304,19 +318,21 @@ static void elops_run_pt_event(struct lws_context *context, int tsi) { /* Run / Dispatch the event_base loop */ - if (context->pt[tsi].event.io_loop) - event_base_dispatch(context->pt[tsi].event.io_loop); + if (pt_to_priv_event(&context->pt[tsi])->io_loop) + event_base_dispatch( + pt_to_priv_event(&context->pt[tsi])->io_loop); } static void elops_destroy_pt_event(struct lws_context *context, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt); struct lws_vhost *vh = context->vhost_list; lwsl_info("%s\n", __func__); - if (!pt->event.io_loop) + if (!ptpr->io_loop) return; /* @@ -324,21 +340,24 @@ elops_destroy_pt_event(struct lws_context *context, int tsi) */ while (vh) { if (vh->lserv_wsi) { - event_free(vh->lserv_wsi->w_read.event.watcher); - vh->lserv_wsi->w_read.event.watcher = NULL; - event_free(vh->lserv_wsi->w_write.event.watcher); - vh->lserv_wsi->w_write.event.watcher = NULL; + struct lws_wsi_eventlibs_libevent *w = + wsi_to_priv_event(vh->lserv_wsi); + + event_free(w->w_read.watcher); + w->w_read.watcher = NULL; + event_free(w->w_write.watcher); + w->w_write.watcher = NULL; } vh = vh->vhost_next; } - event_free(pt->event.hrtimer); - event_free(pt->event.idle_timer); + event_free(ptpr->hrtimer); + event_free(ptpr->idle_timer); if (!pt->event_loop_foreign) { - event_del(pt->w_sigint.event.watcher); - event_free(pt->w_sigint.event.watcher); - event_base_loopexit(pt->event.io_loop, NULL); + event_del(ptpr->w_sigint.watcher); + event_free(ptpr->w_sigint.watcher); + event_base_loopexit(ptpr->io_loop, NULL); // event_base_free(pt->event.io_loop); // pt->event.io_loop = NULL; lwsl_notice("%s: set to exit loop\n", __func__); @@ -349,6 +368,7 @@ static void elops_destroy_wsi_event(struct lws *wsi) { struct lws_context_per_thread *pt; + struct lws_wsi_eventlibs_libevent *w; if (!wsi) return; @@ -357,14 +377,16 @@ elops_destroy_wsi_event(struct lws *wsi) if (pt->is_destroyed) return; - if (wsi->w_read.event.watcher) { - event_free(wsi->w_read.event.watcher); - wsi->w_read.event.watcher = NULL; + w = wsi_to_priv_event(wsi); + + if (w->w_read.watcher) { + event_free(w->w_read.watcher); + w->w_read.watcher = NULL; } - if (wsi->w_write.event.watcher) { - event_free(wsi->w_write.event.watcher); - wsi->w_write.event.watcher = NULL; + if (w->w_write.watcher) { + event_free(w->w_write.watcher); + w->w_write.watcher = NULL; } } @@ -380,6 +402,8 @@ static int elops_init_vhost_listen_wsi_event(struct lws *wsi) { struct lws_context_per_thread *pt; + struct lws_pt_eventlibs_libevent *ptpr; + struct lws_wsi_eventlibs_libevent *w; int fd; if (!wsi) { @@ -387,22 +411,24 @@ elops_init_vhost_listen_wsi_event(struct lws *wsi) return 0; } - wsi->w_read.context = wsi->a.context; - wsi->w_write.context = wsi->a.context; + w = wsi_to_priv_event(wsi); + + w->w_read.context = wsi->a.context; + w->w_write.context = wsi->a.context; pt = &wsi->a.context->pt[(int)wsi->tsi]; + ptpr = pt_to_priv_event(pt); if (wsi->role_ops->file_handle) fd = wsi->desc.filefd; else fd = wsi->desc.sockfd; - wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd, - (EV_READ | EV_PERSIST), - lws_event_cb, &wsi->w_read); - wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd, - (EV_WRITE | EV_PERSIST), - lws_event_cb, &wsi->w_write); + w->w_read.watcher = event_new(ptpr->io_loop, fd, (EV_READ | EV_PERSIST), + lws_event_cb, &w->w_read); + w->w_write.watcher = event_new(ptpr->io_loop, fd, + (EV_WRITE | EV_PERSIST), + lws_event_cb, &w->w_write); elops_io_event(wsi, LWS_EV_START | LWS_EV_READ); @@ -413,6 +439,7 @@ static int elops_destroy_context2_event(struct lws_context *context) { struct lws_context_per_thread *pt; + struct lws_pt_eventlibs_libevent *ptpr; int n, m; lwsl_debug("%s: in\n", __func__); @@ -421,31 +448,31 @@ elops_destroy_context2_event(struct lws_context *context) int budget = 1000; pt = &context->pt[n]; + ptpr = pt_to_priv_event(pt); /* only for internal loops... */ - if (pt->event_loop_foreign || !pt->event.io_loop) + if (pt->event_loop_foreign || !ptpr->io_loop) continue; if (!context->finalize_destroy_after_internal_loops_stopped) { - event_base_loopexit(pt->event.io_loop, NULL); + event_base_loopexit(ptpr->io_loop, NULL); continue; } while (budget-- && - (m = event_base_loop(pt->event.io_loop, EVLOOP_NONBLOCK))) + (m = event_base_loop(ptpr->io_loop, EVLOOP_NONBLOCK))) ; #if 0 if (m) { lwsl_err("%s: tsi %d: NOT everything closed\n", __func__, n); - event_base_dump_events(pt->event.io_loop, stderr); + event_base_dump_events(ptpr->io_loop, stderr); } else lwsl_debug("%s: %d: everything closed OK\n", __func__, n); #endif lwsl_err("%s: event_base_free\n", __func__); - event_base_free(pt->event.io_loop); - pt->event.io_loop = NULL; - + event_base_free(ptpr->io_loop); + ptpr->io_loop = NULL; } lwsl_debug("%s: out\n", __func__); @@ -453,7 +480,7 @@ elops_destroy_context2_event(struct lws_context *context) return 0; } -struct lws_event_loop_ops event_loop_ops_event = { +static const struct lws_event_loop_ops event_loop_ops_event = { /* name */ "libevent", /* init_context */ elops_init_context_event, /* destroy_context1 */ NULL, @@ -470,4 +497,22 @@ struct lws_event_loop_ops event_loop_ops_event = { /* destroy wsi */ elops_destroy_wsi_event, /* flags */ 0, + + /* evlib_size_ctx */ 0, + /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_libevent), + /* evlib_size_vh */ 0, + /* evlib_size_wsi */ sizeof(struct lws_wsi_eventlibs_libevent), +}; + +#if defined(LWS_WITH_EVLIB_PLUGINS) +LWS_VISIBLE +#endif +const lws_plugin_evlib_t evlib_event = { + .hdr = { + "libevent event loop", + "lws_evlib_plugin", + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_event }; diff --git a/lib/event-libs/libevent/private-lib-event-libs-libevent.h b/lib/event-libs/libevent/private-lib-event-libs-libevent.h index 9bc8e6841..aa9b4b050 100644 --- a/lib/event-libs/libevent/private-lib-event-libs-libevent.h +++ b/lib/event-libs/libevent/private-lib-event-libs-libevent.h @@ -24,23 +24,26 @@ #include +struct lws_signal_watcher_libevent { + struct event *watcher; + struct lws_context *context; +}; + struct lws_pt_eventlibs_libevent { struct event_base *io_loop; struct event *hrtimer; struct event *idle_timer; + struct lws_signal_watcher_libevent w_sigint; }; struct lws_io_watcher_libevent { struct event *watcher; + struct lws_context *context; + uint8_t actual_events; char set; }; -struct lws_signal_watcher_libevent { - struct event *watcher; +struct lws_wsi_eventlibs_libevent { + struct lws_io_watcher_libevent w_read; + struct lws_io_watcher_libevent w_write; }; - -struct lws_context_eventlibs_libevent { - int placeholder; -}; - -extern struct lws_event_loop_ops event_loop_ops_event; diff --git a/lib/event-libs/libuv/CMakeLists.txt b/lib/event-libs/libuv/CMakeLists.txt index 5193c7257..fb810a848 100644 --- a/lib/event-libs/libuv/CMakeLists.txt +++ b/lib/event-libs/libuv/CMakeLists.txt @@ -47,7 +47,6 @@ message("libuv include dir: ${LIBUV_INCLUDE_DIRS}") message("libuv libraries: ${LIBUV_LIBRARIES}") include_directories("${LIBUV_INCLUDE_DIRS}") -list(APPEND LIB_LIST ${LIBUV_LIBRARIES}) CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H) # libuv changed the location in 1.21.0. Retain both @@ -55,11 +54,27 @@ CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H) if (NOT LWS_HAVE_UV_VERSION_H) CHECK_INCLUDE_FILE(uv/version.h LWS_HAVE_NEW_UV_VERSION_H) endif() + + if (LWS_WITH_EVLIB_PLUGINS AND LWS_WITH_LIBUV) -if (LWS_WITH_NETWORK) - list(APPEND SOURCES - event-libs/libuv/libuv.c) -endif() + create_evlib_plugin(evlib_uv + libuv.c + private-lib-event-libs-libuv.h + ${LIBUV_LIBRARIES}) + endif() + + # wanting libuv in the library is a separate question than + # wanting libuv as a selectable event loop plugin + # we only came here because LWS_WITH_LIBUV or LWS_WITH_LIBUV_INTERNAL + + if ((NOT LWS_WITH_EVLIB_PLUGINS) OR LWS_WITH_LIBUV_INTERNAL) + list(APPEND LIB_LIST ${LIBUV_LIBRARIES}) + + if (LWS_WITH_NETWORK) + list(APPEND SOURCES + event-libs/libuv/libuv.c) + endif() + endif() # # Keep explicit parent scope exports at end diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c index ff0e0cbac..29323400b 100644 --- a/lib/event-libs/libuv/libuv.c +++ b/lib/event-libs/libuv/libuv.c @@ -23,6 +23,10 @@ */ #include "private-lib-core.h" +#include "private-lib-event-libs-libuv.h" + +#define pt_to_priv_uv(_pt) ((struct lws_pt_eventlibs_libuv *)(_pt)->evlib_pt) +#define wsi_to_priv_uv(_w) ((struct lws_wsi_eventlibs_libuv *)(_w)->evlib_wsi) static void lws_uv_sultimer_cb(uv_timer_t *timer @@ -31,15 +35,17 @@ lws_uv_sultimer_cb(uv_timer_t *timer #endif ) { - struct lws_context_per_thread *pt = lws_container_of(timer, - struct lws_context_per_thread, uv.sultimer); + struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(timer, + struct lws_pt_eventlibs_libuv, sultimer); + struct lws_context_per_thread *pt = lws_container_of(ptpr, + struct lws_context_per_thread, evlib_pt); lws_usec_t us; lws_pt_lock(pt, __func__); us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs()); if (us) - uv_timer_start(&pt->uv.sultimer, lws_uv_sultimer_cb, + uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb, LWS_US_TO_MS(us), 0); lws_pt_unlock(pt); } @@ -50,9 +56,10 @@ lws_uv_idle(uv_idle_t *handle , int status #endif ) -{ - struct lws_context_per_thread *pt = lws_container_of(handle, - struct lws_context_per_thread, uv.idle); +{ struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(handle, + struct lws_pt_eventlibs_libuv, idle); + struct lws_context_per_thread *pt = lws_container_of(ptpr, + struct lws_context_per_thread, evlib_pt); lws_usec_t us; lws_service_do_ripe_rxflow(pt); @@ -70,7 +77,7 @@ lws_uv_idle(uv_idle_t *handle us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, lws_now_usecs()); if (us) - uv_timer_start(&pt->uv.sultimer, lws_uv_sultimer_cb, + uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb, LWS_US_TO_MS(us), 0); lws_pt_unlock(pt); @@ -126,7 +133,7 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents) return; } - uv_idle_start(&pt->uv.idle, lws_uv_idle); + uv_idle_start(&pt_to_priv_uv(pt)->idle, lws_uv_idle); } /* @@ -161,7 +168,7 @@ lws_libuv_stop(struct lws_context *context) pt = &context->pt[m]; if (pt->pipe_wsi) { - uv_poll_stop(pt->pipe_wsi->w_read.uv.pwatcher); + uv_poll_stop(wsi_to_priv_uv(pt->pipe_wsi)->w_read.pwatcher); lws_destroy_event_pipe(pt->pipe_wsi); pt->pipe_wsi = NULL; } @@ -231,8 +238,8 @@ lws_uv_close_cb_sa(uv_handle_t *handle) for (n = 0; n < context->count_threads; n++) { struct lws_context_per_thread *pt = &context->pt[n]; - if (pt->uv.io_loop && !pt->event_loop_foreign) - uv_stop(pt->uv.io_loop); + if (pt_to_priv_uv(pt)->io_loop && !pt->event_loop_foreign) + uv_stop(pt_to_priv_uv(pt)->io_loop); } if (!context->pt[0].event_loop_foreign) { @@ -286,8 +293,8 @@ lws_close_all_handles_in_loop(uv_loop_t *loop) void lws_libuv_stop_without_kill(const struct lws_context *context, int tsi) { - if (context->pt[tsi].uv.io_loop) - uv_stop(context->pt[tsi].uv.io_loop); + if (pt_to_priv_uv(&context->pt[tsi])->io_loop) + uv_stop(pt_to_priv_uv(&context->pt[tsi])->io_loop); } @@ -295,8 +302,8 @@ lws_libuv_stop_without_kill(const struct lws_context *context, int tsi) uv_loop_t * lws_uv_getloop(struct lws_context *context, int tsi) { - if (context->pt[tsi].uv.io_loop) - return context->pt[tsi].uv.io_loop; + if (pt_to_priv_uv(&context->pt[tsi])->io_loop) + return pt_to_priv_uv(&context->pt[tsi])->io_loop; return NULL; } @@ -304,7 +311,7 @@ lws_uv_getloop(struct lws_context *context, int tsi) int lws_libuv_check_watcher_active(struct lws *wsi) { - uv_handle_t *h = (uv_handle_t *)wsi->w_read.uv.pwatcher; + uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher; if (!h) return 0; @@ -321,7 +328,7 @@ elops_init_context_uv(struct lws_context *context, context->eventlib_signal_cb = info->signal_cb; for (n = 0; n < context->count_threads; n++) - context->pt[n].w_sigint.context = context; + pt_to_priv_uv(&context->pt[n])->w_sigint.context = context; return 0; } @@ -340,7 +347,7 @@ elops_destroy_context1_uv(struct lws_context *context) if (!pt->event_loop_foreign) { - while (budget-- && (m = uv_run(pt->uv.io_loop, + while (budget-- && (m = uv_run(pt_to_priv_uv(pt)->io_loop, UV_RUN_NOWAIT))) ; if (m) @@ -365,15 +372,15 @@ elops_destroy_context2_uv(struct lws_context *context) /* only for internal loops... */ - if (!pt->event_loop_foreign && pt->uv.io_loop) { + if (!pt->event_loop_foreign && pt_to_priv_uv(pt)->io_loop) { internal = 1; if (!context->finalize_destroy_after_internal_loops_stopped) - uv_stop(pt->uv.io_loop); + uv_stop(pt_to_priv_uv(pt)->io_loop); else { #if UV_VERSION_MAJOR > 0 - uv_loop_close(pt->uv.io_loop); + uv_loop_close(pt_to_priv_uv(pt)->io_loop); #endif - lws_free_set_NULL(pt->uv.io_loop); + lws_free_set_NULL(pt_to_priv_uv(pt)->io_loop); } } } @@ -385,14 +392,14 @@ static int elops_wsi_logical_close_uv(struct lws *wsi) { if (!lws_socket_is_valid(wsi->desc.sockfd) && - wsi->role_ops != &role_ops_raw_file) + wsi->role_ops && strcmp(wsi->role_ops->name, "raw-file")) return 0; if (wsi->listener || wsi->event_pipe) { lwsl_debug("%s: %p: %d %d stop listener / pipe poll\n", __func__, wsi, wsi->listener, wsi->event_pipe); - if (wsi->w_read.uv.pwatcher) - uv_poll_stop(wsi->w_read.uv.pwatcher); + if (wsi_to_priv_uv(wsi)->w_read.pwatcher) + uv_poll_stop(wsi_to_priv_uv(wsi)->w_read.pwatcher); } lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi); /* @@ -426,7 +433,7 @@ lws_libuv_closewsi_m(uv_handle_t* handle) static void elops_close_handle_manually_uv(struct lws *wsi) { - uv_handle_t *h = (uv_handle_t *)wsi->w_read.uv.pwatcher; + uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher; lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi); @@ -442,7 +449,7 @@ elops_close_handle_manually_uv(struct lws *wsi) */ wsi->desc.sockfd = LWS_SOCK_INVALID; - wsi->w_read.uv.pwatcher = NULL; + wsi_to_priv_uv(wsi)->w_read.pwatcher = NULL; wsi->told_event_loop_closed = 1; uv_close(h, lws_libuv_closewsi_m); @@ -452,23 +459,22 @@ static int elops_accept_uv(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read; - wsi->w_read.context = wsi->a.context; + w_read->context = wsi->a.context; - wsi->w_read.uv.pwatcher = - lws_malloc(sizeof(*wsi->w_read.uv.pwatcher), "uvh"); - if (!wsi->w_read.uv.pwatcher) + w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh"); + if (!w_read->pwatcher) return -1; if (wsi->role_ops->file_handle) - uv_poll_init(pt->uv.io_loop, wsi->w_read.uv.pwatcher, + uv_poll_init(pt_to_priv_uv(pt)->io_loop, w_read->pwatcher, (int)(lws_intptr_t)wsi->desc.filefd); else - uv_poll_init_socket(pt->uv.io_loop, - wsi->w_read.uv.pwatcher, - wsi->desc.sockfd); + uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop, + w_read->pwatcher, wsi->desc.sockfd); - ((uv_handle_t *)wsi->w_read.uv.pwatcher)->data = (void *)wsi; + ((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi; return 0; } @@ -477,14 +483,14 @@ static void elops_io_uv(struct lws *wsi, int flags) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; - struct lws_io_watcher *w = &wsi->w_read; + struct lws_io_watcher_libuv *w = &(wsi_to_priv_uv(wsi)->w_read); int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE); lwsl_debug("%s: %p: %d\n", __func__, wsi, flags); /* w->context is set after the loop is initialized */ - if (!pt->uv.io_loop || !w->context) { + if (!pt_to_priv_uv(pt)->io_loop || !w->context) { lwsl_info("%s: no io loop yet\n", __func__); return; } @@ -495,7 +501,7 @@ elops_io_uv(struct lws *wsi, int flags) assert(0); } - if (!w->uv.pwatcher || wsi->told_event_loop_closed) { + if (!w->pwatcher || wsi->told_event_loop_closed) { lwsl_info("%s: no watcher\n", __func__); return; @@ -508,7 +514,7 @@ elops_io_uv(struct lws *wsi, int flags) if (flags & LWS_EV_READ) current_events |= UV_READABLE; - uv_poll_start(w->uv.pwatcher, current_events, lws_io_cb); + uv_poll_start(w->pwatcher, current_events, lws_io_cb); } else { if (flags & LWS_EV_WRITE) current_events &= ~UV_WRITABLE; @@ -517,10 +523,9 @@ elops_io_uv(struct lws *wsi, int flags) current_events &= ~UV_READABLE; if (!(current_events & (UV_READABLE | UV_WRITABLE))) - uv_poll_stop(w->uv.pwatcher); + uv_poll_stop(w->pwatcher); else - uv_poll_start(w->uv.pwatcher, current_events, - lws_io_cb); + uv_poll_start(w->pwatcher, current_events, lws_io_cb); } w->actual_events = current_events; @@ -530,26 +535,26 @@ static int elops_init_vhost_listen_wsi_uv(struct lws *wsi) { struct lws_context_per_thread *pt; + struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read; int n; if (!wsi) return 0; - if (wsi->w_read.context) + if (w_read->context) return 0; pt = &wsi->a.context->pt[(int)wsi->tsi]; - if (!pt->uv.io_loop) + if (!pt_to_priv_uv(pt)->io_loop) return 0; - wsi->w_read.context = wsi->a.context; + w_read->context = wsi->a.context; - wsi->w_read.uv.pwatcher = - lws_malloc(sizeof(*wsi->w_read.uv.pwatcher), "uvh"); - if (!wsi->w_read.uv.pwatcher) + w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh"); + if (!w_read->pwatcher) return -1; - n = uv_poll_init_socket(pt->uv.io_loop, wsi->w_read.uv.pwatcher, - wsi->desc.sockfd); + n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop, + w_read->pwatcher, wsi->desc.sockfd); if (n) { lwsl_err("uv_poll_init failed %d, sockfd=%p\n", n, (void *)(lws_intptr_t)wsi->desc.sockfd); @@ -557,7 +562,7 @@ elops_init_vhost_listen_wsi_uv(struct lws *wsi) return -1; } - ((uv_handle_t *)wsi->w_read.uv.pwatcher)->data = (void *)wsi; + ((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi; elops_io_uv(wsi, LWS_EV_START | LWS_EV_READ); @@ -567,8 +572,8 @@ elops_init_vhost_listen_wsi_uv(struct lws *wsi) static void elops_run_pt_uv(struct lws_context *context, int tsi) { - if (context->pt[tsi].uv.io_loop) - uv_run(context->pt[tsi].uv.io_loop, 0); + if (pt_to_priv_uv(&context->pt[tsi])->io_loop) + uv_run(pt_to_priv_uv(&context->pt[tsi])->io_loop, 0); } static void @@ -582,7 +587,7 @@ elops_destroy_pt_uv(struct lws_context *context, int tsi) if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)) return; - if (!pt->uv.io_loop) + if (!pt_to_priv_uv(pt)->io_loop) return; if (pt->event_loop_destroy_processing_done) @@ -591,7 +596,7 @@ elops_destroy_pt_uv(struct lws_context *context, int tsi) pt->event_loop_destroy_processing_done = 1; if (!pt->event_loop_foreign) { - uv_signal_stop(&pt->w_sigint.uv.watcher); + uv_signal_stop(&pt_to_priv_uv(pt)->w_sigint.watcher); ns = LWS_ARRAY_SIZE(sigs); if (lws_check_opt(context->options, @@ -599,18 +604,18 @@ elops_destroy_pt_uv(struct lws_context *context, int tsi) ns = 2; for (m = 0; m < ns; m++) { - uv_signal_stop(&pt->uv.signals[m]); - uv_close((uv_handle_t *)&pt->uv.signals[m], + uv_signal_stop(&pt_to_priv_uv(pt)->signals[m]); + uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->signals[m], lws_uv_close_cb_sa); } } else lwsl_debug("%s: not closing pt signals\n", __func__); - uv_timer_stop(&pt->uv.sultimer); - uv_close((uv_handle_t *)&pt->uv.sultimer, lws_uv_close_cb_sa); + uv_timer_stop(&pt_to_priv_uv(pt)->sultimer); + uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->sultimer, lws_uv_close_cb_sa); - uv_idle_stop(&pt->uv.idle); - uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa); + uv_idle_stop(&pt_to_priv_uv(pt)->idle); + uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->idle, lws_uv_close_cb_sa); } /* @@ -624,11 +629,12 @@ int elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) { struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt); struct lws_vhost *vh = context->vhost_list; int status = 0, n, ns, first = 1; uv_loop_t *loop = (uv_loop_t *)_loop; - if (!pt->uv.io_loop) { + if (!ptpriv->io_loop) { if (!loop) { loop = lws_malloc(sizeof(*loop), "libuv loop"); if (!loop) { @@ -647,9 +653,9 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) pt->event_loop_foreign = 1; } - pt->uv.io_loop = loop; - uv_idle_init(loop, &pt->uv.idle); - LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.idle, context); + ptpriv->io_loop = loop; + uv_idle_init(loop, &ptpriv->idle); + LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->idle, context); ns = LWS_ARRAY_SIZE(sigs); @@ -658,13 +664,13 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) ns = 2; if (!pt->event_loop_foreign) { - assert(ns <= (int)LWS_ARRAY_SIZE(pt->uv.signals)); + assert(ns <= (int)LWS_ARRAY_SIZE(ptpriv->signals)); for (n = 0; n < ns; n++) { - uv_signal_init(loop, &pt->uv.signals[n]); - LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.signals[n], + uv_signal_init(loop, &ptpriv->signals[n]); + LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->signals[n], context); - pt->uv.signals[n].data = pt->context; - uv_signal_start(&pt->uv.signals[n], + ptpriv->signals[n].data = pt->context; + uv_signal_start(&ptpriv->signals[n], lws_uv_signal_handler, sigs[n]); } } @@ -687,8 +693,8 @@ elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi) if (!first) return status; - uv_timer_init(pt->uv.io_loop, &pt->uv.sultimer); - LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.sultimer, context); + uv_timer_init(ptpriv->io_loop, &ptpriv->sultimer); + LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->sultimer, context); return status; } @@ -710,7 +716,8 @@ lws_libuv_closewsi(uv_handle_t* handle) */ #if defined(LWS_WITH_SERVER) - if (wsi->role_ops == &role_ops_listen && wsi->a.context->deprecated) { + if (wsi->role_ops && !strcmp(wsi->role_ops->name, "listen") && + wsi->a.context->deprecated) { lspd = 1; context->deprecation_pending_listen_close_count--; if (!context->deprecation_pending_listen_close_count) @@ -773,8 +780,9 @@ void lws_libuv_closehandle(struct lws *wsi) { uv_handle_t* handle; + struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read; - if (!wsi->w_read.uv.pwatcher) + if (!w_read->pwatcher) return; if (wsi->told_event_loop_closed) { @@ -791,16 +799,16 @@ lws_libuv_closehandle(struct lws *wsi) * handle->data. */ - handle = (uv_handle_t *)wsi->w_read.uv.pwatcher; + handle = (uv_handle_t *)w_read->pwatcher; /* ensure we can only do this once */ - wsi->w_read.uv.pwatcher = NULL; + w_read->pwatcher = NULL; uv_close(handle, lws_libuv_closewsi); } -struct lws_event_loop_ops event_loop_ops_uv = { +static const struct lws_event_loop_ops event_loop_ops_uv = { /* name */ "libuv", /* init_context */ elops_init_context_uv, /* destroy_context1 */ elops_destroy_context1_uv, @@ -817,4 +825,23 @@ struct lws_event_loop_ops event_loop_ops_uv = { /* destroy wsi */ NULL, /* flags */ 0, + + /* evlib_size_ctx */ sizeof(struct lws_context_eventlibs_libuv), + /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_libuv), + /* evlib_size_vh */ 0, + /* evlib_size_wsi */ sizeof(struct lws_io_watcher_libuv), }; + +#if defined(LWS_WITH_EVLIB_PLUGINS) +LWS_VISIBLE +#endif +const lws_plugin_evlib_t evlib_uv = { + .hdr = { + "libuv event loop", + "lws_evlib_plugin", + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_uv +}; + diff --git a/lib/event-libs/libuv/private-lib-event-libs-libuv.h b/lib/event-libs/libuv/private-lib-event-libs-libuv.h index c136a10ab..bb6be8683 100644 --- a/lib/event-libs/libuv/private-lib-event-libs-libuv.h +++ b/lib/event-libs/libuv/private-lib-event-libs-libuv.h @@ -46,11 +46,17 @@ (--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-> \ count_event_loop_static_asset_handles)) +struct lws_signal_watcher_libuv { + uv_signal_t watcher; + struct lws_context *context; +}; + struct lws_pt_eventlibs_libuv { uv_loop_t *io_loop; uv_signal_t signals[8]; uv_timer_t sultimer; uv_idle_t idle; + struct lws_signal_watcher_libuv w_sigint; }; struct lws_context_eventlibs_libuv { @@ -59,14 +65,14 @@ struct lws_context_eventlibs_libuv { struct lws_io_watcher_libuv { uv_poll_t *pwatcher; + struct lws_context *context; + uint8_t actual_events; }; -struct lws_signal_watcher_libuv { - uv_signal_t watcher; +struct lws_wsi_eventlibs_libuv { + struct lws_io_watcher_libuv w_read; }; -extern struct lws_event_loop_ops event_loop_ops_uv; - uv_loop_t * lws_uv_getloop(struct lws_context *context, int tsi); diff --git a/lib/event-libs/poll/poll.c b/lib/event-libs/poll/poll.c index 85ffdc546..006d0f5ef 100644 --- a/lib/event-libs/poll/poll.c +++ b/lib/event-libs/poll/poll.c @@ -19,12 +19,11 @@ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - * - * This is included from private-lib-core.h if LWS_ROLE_WS + * IN THE SOFTWARE */ #include +#include "private-lib-event-libs-poll.h" struct lws_event_loop_ops event_loop_ops_poll = { /* name */ "poll", @@ -43,4 +42,19 @@ struct lws_event_loop_ops event_loop_ops_poll = { /* destroy wsi */ NULL, /* flags */ LELOF_ISPOLL, + + /* evlib_size_ctx */ 0, + /* evlib_size_pt */ 0, + /* evlib_size_vh */ 0, + /* evlib_size_wsi */ 0, +}; + +const lws_plugin_evlib_t evlib_poll = { + .hdr = { + "poll", + "lws_evlib_plugin", + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_poll }; diff --git a/lib/event-libs/private-lib-event-libs.h b/lib/event-libs/private-lib-event-libs.h index 55f0169f4..c0d087f1a 100644 --- a/lib/event-libs/private-lib-event-libs.h +++ b/lib/event-libs/private-lib-event-libs.h @@ -60,27 +60,9 @@ struct lws_event_loop_ops { void (*destroy_wsi)(struct lws *wsi); uint8_t flags; + + uint16_t evlib_size_ctx; + uint16_t evlib_size_pt; + uint16_t evlib_size_vh; + uint16_t evlib_size_wsi; }; - -/* bring in event libs private declarations */ - -#if defined(LWS_WITH_POLL) -#include "private-lib-event-libs-poll.h" -#endif - -#if defined(LWS_WITH_LIBUV) -#include "private-lib-event-libs-libuv.h" -#endif - -#if defined(LWS_WITH_LIBEVENT) -#include "private-lib-event-libs-libevent.h" -#endif - -#if defined(LWS_WITH_GLIB) -#include "private-lib-event-libs-glib.h" -#endif - -#if defined(LWS_WITH_LIBEV) -#include "private-lib-event-libs-libev.h" -#endif - diff --git a/lib/misc/dir.c b/lib/misc/dir.c index 760c6953b..94ad3e96f 100644 --- a/lib/misc/dir.c +++ b/lib/misc/dir.c @@ -50,7 +50,7 @@ #endif #endif /* win32 */ -#define COMBO_SIZEOF 256 +#define COMBO_SIZEOF 512 #if !defined(LWS_PLAT_FREERTOS) @@ -189,7 +189,7 @@ lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb) } #endif if (cb(dirpath, user, &lde)) { - while (i++ < n) + while (++i < n) free(namelist[i]); goto bail; } @@ -265,7 +265,16 @@ lws_dir_rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde) lws_snprintf(path, sizeof(path), "%s%c%s", dirpath, csep, lde->name); if (lde->type == LDOT_DIR) { - lws_dir(path, NULL, lws_dir_rm_rf_cb); +#if !defined(WIN32) && !defined(_WIN32) + char dummy[8]; + /* + * hm... eg, recursive dir symlinks can show up a LDOT_DIR + * here + */ + if (readlink(path, dummy, sizeof(dummy)) < 0) +#endif + lws_dir(path, NULL, lws_dir_rm_rf_cb); + if (rmdir(path)) lwsl_warn("%s: rmdir %s failed %d\n", __func__, path, errno); } else { @@ -287,7 +296,8 @@ lws_dir_rm_rf_cb(const char *dirpath, void *user, struct lws_dir_entry *lde) #endif -#if defined(LWS_WITH_PLUGINS) +#if defined(LWS_WITH_PLUGINS) || \ + (defined(LWS_WITH_EVLIB_PLUGINS) && defined(LWS_WITH_EVENT_LIBS)) struct lws_plugins_args { struct lws_plugin **pplugin; @@ -301,19 +311,38 @@ static int lws_plugins_dir_cb(const char *dirpath, void *user, struct lws_dir_entry *lde) { struct lws_plugins_args *pa = (struct lws_plugins_args *)user; - char path[256]; + char path[256], base[64], *q = base; + const char *p; if (strlen(lde->name) < 7) return 0; - /* if he's given a filter, only match if name + 3 matches it */ - if (pa->filter && strncmp(lde->name + 3, pa->filter, strlen(pa->filter))) + /* + * The actual plugin names for protocol plugins look like + * "libprotocol_lws_ssh_base.so" and for event libs + * "libwebsockets-evlib_ev.so"... to recover the base name of + * "lws_ssh_base" and "evlib_ev" we strip from the left to after the + * first _ or -, and then truncate at the first . + */ + + p = lde->name; + while (*p && *p != '_' && *p != '-') + p++; + if (!*p) + return 0; + p++; + while (*p && *p != '.' && lws_ptr_diff(q, base) < (int)sizeof(base) - 1) + *q++ = *p++; + *q = '\0'; + + /* if he's given a filter, only match if base matches it */ + if (pa->filter && strcmp(base, pa->filter)) return 0; lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name); lwsl_notice(" %s\n", path); - return !lws_plat_dlopen(pa->pplugin, path, lde->name + 3, pa->_class, + return !lws_plat_dlopen(pa->pplugin, path, base, pa->_class, pa->each, pa->each_user); } diff --git a/lib/plat/unix/CMakeLists.txt b/lib/plat/unix/CMakeLists.txt index efe52f398..70a421745 100644 --- a/lib/plat/unix/CMakeLists.txt +++ b/lib/plat/unix/CMakeLists.txt @@ -65,7 +65,7 @@ if (LWS_WITH_NETWORK) endif() endif() -if (LWS_WITH_PLUGINS AND LWS_WITH_LIBUV) +if (LWS_WITH_PLUGINS OR LWS_WITH_EVLIB_PLUGINS) list(APPEND SOURCES plat/unix/unix-plugins.c) endif() diff --git a/lib/plat/unix/unix-init.c b/lib/plat/unix/unix-init.c index 1a53a1c92..9d72598e5 100644 --- a/lib/plat/unix/unix-init.c +++ b/lib/plat/unix/unix-init.c @@ -80,6 +80,7 @@ lws_sul_plat_unix(lws_sorted_usec_list_t *sul) } #endif +#if defined(LWS_WITH_PLUGINS) static int protocol_plugin_cb(struct lws_plugin *pin, void *each_user) { @@ -92,6 +93,7 @@ protocol_plugin_cb(struct lws_plugin *pin, void *each_user) return 0; } +#endif int lws_plat_init(struct lws_context *context, diff --git a/lib/plat/unix/unix-pipe.c b/lib/plat/unix/unix-pipe.c index 2513a9ba5..a225dab7b 100644 --- a/lib/plat/unix/unix-pipe.c +++ b/lib/plat/unix/unix-pipe.c @@ -1,7 +1,7 @@ /* * libwebsockets - small server side websockets and web server implementation * - * Copyright (C) 2010 - 2019 Andy Green + * Copyright (C) 2010 - 2020 Andy Green * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -27,15 +27,17 @@ #endif #include "private-lib-core.h" - int lws_plat_pipe_create(struct lws *wsi) { struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + #if defined(LWS_HAVE_EVENTFD) - pt->dummy_pipe_fds[0] = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK); + pt->dummy_pipe_fds[0] = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); pt->dummy_pipe_fds[1] = -1; - return pt->dummy_pipe_fds[0]<0?-1:0; + + return pt->dummy_pipe_fds[0] < 0 ? -1 : 0; + #elif defined(LWS_HAVE_PIPE2) return pipe2(pt->dummy_pipe_fds, O_NONBLOCK); #else @@ -49,6 +51,7 @@ lws_plat_pipe_signal(struct lws *wsi) struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; #if defined(LWS_HAVE_EVENTFD) eventfd_t value = 1; + return eventfd_write(pt->dummy_pipe_fds[0], value); #else char buf = 0; diff --git a/lib/plat/unix/unix-plugins.c b/lib/plat/unix/unix-plugins.c index 05fb79382..a68507740 100644 --- a/lib/plat/unix/unix-plugins.c +++ b/lib/plat/unix/unix-plugins.c @@ -30,10 +30,9 @@ #include #include -#ifdef LWS_WITH_PLUGINS +#if defined(LWS_WITH_PLUGINS) || defined(LWS_WITH_EVLIB_PLUGINS) #include #endif -#include const lws_plugin_header_t * lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, diff --git a/lib/plat/windows/windows-init.c b/lib/plat/windows/windows-init.c index 1f2b39f9f..29477504a 100644 --- a/lib/plat/windows/windows-init.c +++ b/lib/plat/windows/windows-init.c @@ -55,6 +55,7 @@ lws_plat_context_early_init(void) return 1; } +#if defined(LWS_WITH_PLUGINS) static int protocol_plugin_cb(struct lws_plugin *pin, void *each_user) { @@ -67,6 +68,7 @@ protocol_plugin_cb(struct lws_plugin *pin, void *each_user) return 0; } +#endif int lws_plat_init(struct lws_context *context, diff --git a/lib/plat/windows/windows-plugins.c b/lib/plat/windows/windows-plugins.c index e55f802d3..3ff412537 100644 --- a/lib/plat/windows/windows-plugins.c +++ b/lib/plat/windows/windows-plugins.c @@ -27,7 +27,8 @@ #endif #include "private-lib-core.h" -#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0) +#if (defined(LWS_WITH_PLUGINS) || defined(LWS_WITH_EVLIB_PLUGINS)) && \ + (UV_VERSION_MAJOR > 0) const lws_plugin_header_t * lws_plat_dlopen(struct lws_plugin **pplugin, const char *libpath, @@ -116,11 +117,13 @@ protocol_plugin_cb(struct lws_plugin *pin, void *each_user) return 0; } +#endif int lws_plat_plugins_init(struct lws_context *context, const char * const *d) { -#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0) +#if (defined(LWS_WITH_PLUGINS) || defined(LWS_WITH_EVLIB_PLUGINS)) && \ + (UV_VERSION_MAJOR > 0) if (info->plugin_dirs) { uv_loop_init(&context->uv.loop); lws_plugins_init(&context->plugin_list, info->plugin_dirs, @@ -135,7 +138,8 @@ lws_plat_plugins_init(struct lws_context *context, const char * const *d) int lws_plat_plugins_destroy(struct lws_context * context) { -#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0) +#if (defined(LWS_WITH_PLUGINS) || defined(LWS_WITH_EVLIB_PLUGINS)) && \ + (UV_VERSION_MAJOR > 0) if (lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV) && context->plugin_list) { lws_plugins_destroy(&context->plugin_list, NULL, NULL); diff --git a/lib/plat/windows/windows-spawn.c b/lib/plat/windows/windows-spawn.c index a65968fad..d6fabb01a 100644 --- a/lib/plat/windows/windows-spawn.c +++ b/lib/plat/windows/windows-spawn.c @@ -66,6 +66,7 @@ lws_create_basic_wsi(struct lws_context *context, int tsi, const struct lws_role_ops *ops) { struct lws *new_wsi; + size_t s = sizeof(*new_wsi); if (!context->vhost_list) return NULL; @@ -76,12 +77,20 @@ lws_create_basic_wsi(struct lws_context *context, int tsi, return NULL; } - new_wsi = lws_zalloc(sizeof(*new_wsi), "new wsi"); +#if defined(LWS_WITH_EVENT_LIBS) + s += vhost->context->event_loop_ops->evlib_size_wsi; +#endif + + new_wsi = lws_zalloc(s, "new wsi"); if (new_wsi == NULL) { lwsl_err("Out of memory for new connection\n"); return NULL; } +#if defined(LWS_WITH_EVENT_LIBS) + new_wsi->evlib_wsi = (uint8_t *)new_wsi + sizeof(*new_wsi); +#endif + new_wsi->tsi = tsi; new_wsi->a.context = context; new_wsi->pending_timeout = NO_PENDING_TIMEOUT; @@ -324,7 +333,7 @@ windows_pipe_poll_hack(lws_sorted_usec_list_t *sul) */ } else if (br) - wsi1->protocol->callback(wsi1, + wsi1->a.protocol->callback(wsi1, LWS_CALLBACK_RAW_RX_FILE, NULL, NULL, 0); } @@ -417,8 +426,8 @@ lws_spawn_piped(const struct lws_spawn_piped_info *i) } lsp->stdwsi[n]->lsp_channel = n; lws_vhost_bind_wsi(i->vh, lsp->stdwsi[n]); - lsp->stdwsi[n]->protocol = pcol; - lsp->stdwsi[n]->opaque_user_data = i->opaque; + lsp->stdwsi[n]->a.protocol = pcol; + lsp->stdwsi[n]->a.opaque_user_data = i->opaque; lsp->stdwsi[n]->desc.filefd = lsp->pipe_fds[n][!n]; lsp->stdwsi[n]->file_desc = 1; diff --git a/lib/roles/dbus/dbus.c b/lib/roles/dbus/dbus.c index cffed03a2..6e651018d 100644 --- a/lib/roles/dbus/dbus.c +++ b/lib/roles/dbus/dbus.c @@ -48,6 +48,7 @@ static struct lws * __lws_shadow_wsi(struct lws_dbus_ctx *ctx, DBusWatch *w, int fd, int create_ok) { + size_t s = sizeof(struct lws); struct lws *wsi; if (fd < 0 || fd >= (int)ctx->vh->context->fd_limit_per_thread) { @@ -68,12 +69,20 @@ __lws_shadow_wsi(struct lws_dbus_ctx *ctx, DBusWatch *w, int fd, int create_ok) if (!create_ok) return NULL; - wsi = lws_zalloc(sizeof(*wsi), "shadow wsi"); +#if defined(LWS_WITH_EVENT_LIBS) + s += ctx->vh->context->event_loop_ops->evlib_size_wsi; +#endif + + wsi = lws_zalloc(s, "shadow wsi"); if (wsi == NULL) { lwsl_err("Out of mem\n"); return NULL; } +#if defined(LWS_WITH_EVENT_LIBS) + wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi); +#endif + lwsl_info("%s: creating shadow wsi\n", __func__); wsi->a.context = ctx->vh->context; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index 2e6d09b69..01a6b38bc 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -271,10 +271,21 @@ done_list: goto deal; } - wsi = lws_zalloc(sizeof(struct lws), "listen wsi"); - if (wsi == NULL) { - lwsl_err("Out of mem\n"); - goto bail; + { + size_t s = sizeof(struct lws); + +#if defined(LWS_WITH_EVENT_LIBS) + s += vhost->context->event_loop_ops->evlib_size_wsi; +#endif + + wsi = lws_zalloc(s, "listen wsi"); + if (wsi == NULL) { + lwsl_err("Out of mem\n"); + goto bail; + } +#if defined(LWS_WITH_EVENT_LIBS) + wsi->evlib_wsi = (uint8_t *)wsi + sizeof(*wsi); +#endif } #ifdef LWS_WITH_UNIX_SOCK diff --git a/lib/roles/pipe/ops-pipe.c b/lib/roles/pipe/ops-pipe.c index 6b1dfe413..89b150f61 100644 --- a/lib/roles/pipe/ops-pipe.c +++ b/lib/roles/pipe/ops-pipe.c @@ -30,8 +30,14 @@ rops_handle_POLLIN_pipe(struct lws_context_per_thread *pt, struct lws *wsi, { #if defined(LWS_HAVE_EVENTFD) eventfd_t value; - if (eventfd_read(wsi->desc.sockfd, &value) < 0) + int n; + + n = eventfd_read(wsi->desc.sockfd, &value); + if (n < 0) { + lwsl_notice("%s: eventfd read %d bailed errno %d\n", __func__, + wsi->desc.sockfd, LWS_ERRNO); return LWS_HPI_RET_PLEASE_CLOSE_ME; + } #elif !defined(WIN32) && !defined(_WIN32) char s[100]; int n; diff --git a/minimal-examples/api-tests/api-test-lws_struct-json/main.c b/minimal-examples/api-tests/api-test-lws_struct-json/main.c index 263e0550d..d6d06fa16 100644 --- a/minimal-examples/api-tests/api-test-lws_struct-json/main.c +++ b/minimal-examples/api-tests/api-test-lws_struct-json/main.c @@ -780,7 +780,7 @@ done: lws_struct_json_init_parse(&ctx, NULL, &a); - m = lejp_parse(&ctx, (uint8_t *)jig_conf, strlen(jig_conf)); + m = lejp_parse(&ctx, (uint8_t *)jig_conf, (int)strlen(jig_conf)); if (m < 0 || !a.dest) { lwsl_err("%s: line %d: JSON decode failed '%s'\n", diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt index 5bba0c5d8..75b5fba4b 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/CMakeLists.txt @@ -28,6 +28,7 @@ if (LWS_WITH_LIBUV) message("libuv libraries: ${LIBUV_LIBRARIES}") include_directories("${LIBUV_INCLUDE_DIRS}") set(extralibs ${extralibs} ${LIBUV_LIBRARIES}) + list(APPEND SRCS libuv.c) endif() if (LWS_WITH_LIBEVENT) find_path(LIBEVENT_INCLUDE_DIRS NAMES event2/event.h) @@ -36,6 +37,7 @@ if (LWS_WITH_LIBEVENT) message("libevent libraries: ${LIBEVENT_LIBRARIES}") include_directories("${LIBEVENT_INCLUDE_DIRS}") set(extralibs ${extralibs} ${LIBEVENT_LIBRARIES}) + list(APPEND SRCS libevent.c) endif() if (LWS_WITH_LIBEV) find_path(LIBEV_INCLUDE_DIRS NAMES ev.h) @@ -44,6 +46,7 @@ if (LWS_WITH_LIBEV) message("libev libraries: ${LIBEV_LIBRARIES}") include_directories("${LIBEV_INCLUDE_DIRS}") set(extralibs ${extralibs} ${LIBEV_LIBRARIES}) + list(APPEND SRCS libev.c) endif() if (LWS_WITH_GLIB) set(LWS_GLIB_INCLUDE_DIRS CACHE PATH "Path to the glib include directory") @@ -67,6 +70,7 @@ if (LWS_WITH_GLIB) message("glib libraries: ${GLIB_LIBRARIES}") include_directories("${GLIB_INCLUDE_DIRS}") set(extralibs ${extralibs} ${GLIB_LIBRARIES}) + list(APPEND SRCS glib.c) endif() message("Extra libs: ${extralibs}") diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/glib.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/glib.c new file mode 100644 index 000000000..e2014cd6b --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/glib.c @@ -0,0 +1,92 @@ +/* + * lws-minimal-http-server-eventlib-foreign + * + * Written in 2010-2020 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The glib specific code + */ + +#include + +#include +#include + +#include +#include + +#include "private.h" + +typedef struct lws_glib_tag { + GSource *gs; + guint tag; +} lws_glib_tag_t; + +#define lws_gs_valid(t) (t.gs) +#define lws_gs_destroy(t) if (lws_gs_valid(t)) { \ + g_source_remove(t.tag); \ + g_source_unref(t.gs); \ + t.gs = NULL; t.tag = 0; } + +static GMainLoop *loop_glib; +static lws_glib_tag_t timer_outer_glib, sighandler_glib; + +static int +timer_cb_glib(void *p) +{ + foreign_timer_service(loop_glib); + return 1; +} + +static void +signal_cb_glib(void *p) +{ + signal_cb(SIGINT); +} + +static void +foreign_event_loop_init_and_run_glib(void) +{ + /* we create and start our "foreign loop" */ + + loop_glib = g_main_loop_new(NULL, 0); + + sighandler_glib.gs = g_unix_signal_source_new(SIGINT); + g_source_set_callback(sighandler_glib.gs, G_SOURCE_FUNC(signal_cb_glib), + NULL, NULL); + sighandler_glib.tag = g_source_attach(sighandler_glib.gs, + g_main_loop_get_context(loop_glib)); + + timer_outer_glib.gs = g_timeout_source_new(1000); + g_source_set_callback(timer_outer_glib.gs, timer_cb_glib, NULL, NULL); + timer_outer_glib.tag = g_source_attach(timer_outer_glib.gs, + g_main_loop_get_context(loop_glib)); + + g_main_loop_run(loop_glib); +} + +static void +foreign_event_loop_stop_glib(void) +{ + g_main_loop_quit(loop_glib); +} + +static void +foreign_event_loop_cleanup_glib(void) +{ + /* cleanup the foreign loop assets */ + + lws_gs_destroy(sighandler_glib); + lws_gs_destroy(timer_outer_glib); + + g_main_loop_unref(loop_glib); + loop_glib = NULL; +} + +const struct ops ops_glib = { + foreign_event_loop_init_and_run_glib, + foreign_event_loop_stop_glib, + foreign_event_loop_cleanup_glib +}; diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libev.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libev.c new file mode 100644 index 000000000..dcab933d3 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libev.c @@ -0,0 +1,76 @@ +/* + * lws-minimal-http-server-eventlib-foreign + * + * Written in 2010-2020 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The libev specific code + */ + +#include + +#include + +#include +#include + +#include "private.h" + +static struct ev_loop *loop_ev; +static struct ev_timer timer_outer_ev; +static struct ev_signal sighandler_ev; + +static void +timer_cb_ev(struct ev_loop *loop, struct ev_timer *watcher, int revents) +{ + foreign_timer_service(loop_ev); +} + +static void +signal_cb_ev(struct ev_loop *loop, struct ev_signal *watcher, int revents) +{ + signal_cb(watcher->signum); +} + +static void +foreign_event_loop_init_and_run_libev(void) +{ + /* we create and start our "foreign loop" */ + + loop_ev = ev_loop_new(0); + + ev_signal_init(&sighandler_ev, signal_cb_ev, SIGINT); + ev_signal_start(loop_ev, &sighandler_ev); + + ev_timer_init(&timer_outer_ev, timer_cb_ev, 0, 1); + ev_timer_start(loop_ev, &timer_outer_ev); + + ev_run(loop_ev, 0); +} + +static void +foreign_event_loop_stop_libev(void) +{ + ev_break(loop_ev, EVBREAK_ALL); +} + +static void +foreign_event_loop_cleanup_libev(void) +{ + /* cleanup the foreign loop assets */ + + ev_timer_stop(loop_ev, &timer_outer_ev); + ev_signal_stop(loop_ev, &sighandler_ev); + + ev_run(loop_ev, 0); + ev_loop_destroy(loop_ev); +} + +const struct ops ops_libev = { + foreign_event_loop_init_and_run_libev, + foreign_event_loop_stop_libev, + foreign_event_loop_cleanup_libev +}; + diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libevent.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libevent.c new file mode 100644 index 000000000..31d75872b --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libevent.c @@ -0,0 +1,84 @@ +/* + * lws-minimal-http-server-eventlib-foreign + * + * Written in 2010-2020 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The libevent specific code + */ + +#include + +#include + +#include +#include + +#include "private.h" + +static struct event_base *loop_event; +static struct event *timer_outer_event; +static struct event *sighandler_event; + +static void +timer_cb_event(int fd, short event, void *arg) +{ + foreign_timer_service(loop_event); +} + +static void +signal_cb_event(int fd, short event, void *arg) +{ + signal_cb((int)(lws_intptr_t)arg); +} + +static void +foreign_event_loop_init_and_run_libevent(void) +{ + struct timeval tv; + + /* we create and start our "foreign loop" */ + + tv.tv_sec = 1; + tv.tv_usec = 0; + + loop_event = event_base_new(); + + sighandler_event = evsignal_new(loop_event, SIGINT, signal_cb_event, + (void*)SIGINT); + + timer_outer_event = event_new(loop_event, -1, EV_PERSIST, + timer_cb_event, NULL); + //evtimer_new(loop_event, timer_cb_event, NULL); + evtimer_add(timer_outer_event, &tv); + + event_base_loop(loop_event, 0); +} + +static void +foreign_event_loop_stop_libevent(void) +{ + event_base_loopexit(loop_event, NULL); +} + +static void +foreign_event_loop_cleanup_libevent(void) +{ + /* cleanup the foreign loop assets */ + + evtimer_del(timer_outer_event); + event_free(timer_outer_event); + evsignal_del(sighandler_event); + event_free(sighandler_event); + + event_base_loop(loop_event, 0); + event_base_free(loop_event); +} + +const struct ops ops_libevent = { + foreign_event_loop_init_and_run_libevent, + foreign_event_loop_stop_libevent, + foreign_event_loop_cleanup_libevent +}; diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libuv.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libuv.c new file mode 100644 index 000000000..df1550de5 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/libuv.c @@ -0,0 +1,91 @@ +/* + * lws-minimal-http-server-eventlib-foreign + * + * Written in 2010-2020 by Andy Green + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The libuv specific code + */ + +#include + +#include +#include + +#include +#ifdef LWS_HAVE_UV_VERSION_H +#include +#endif +#ifdef LWS_HAVE_NEW_UV_VERSION_H +#include +#endif + +#include "private.h" + +static uv_loop_t loop_uv; +static uv_timer_t timer_outer_uv; +static uv_signal_t sighandler_uv; + +static void +timer_cb_uv(uv_timer_t *t) +{ + foreign_timer_service(&loop_uv); +} + +static void +signal_cb_uv(uv_signal_t *watcher, int signum) +{ + signal_cb(signum); +} + +static void +foreign_event_loop_init_and_run_libuv(void) +{ + /* we create and start our "foreign loop" */ + +#if (UV_VERSION_MAJOR > 0) // Travis... + uv_loop_init(&loop_uv); +#endif + uv_signal_init(&loop_uv, &sighandler_uv); + uv_signal_start(&sighandler_uv, signal_cb_uv, SIGINT); + + uv_timer_init(&loop_uv, &timer_outer_uv); +#if (UV_VERSION_MAJOR > 0) // Travis... + uv_timer_start(&timer_outer_uv, timer_cb_uv, 0, 1000); +#else + (void)timer_cb_uv; +#endif + + uv_run(&loop_uv, UV_RUN_DEFAULT); +} + +static void +foreign_event_loop_stop_libuv(void) +{ + uv_stop(&loop_uv); +} + +static void +foreign_event_loop_cleanup_libuv(void) +{ + /* cleanup the foreign loop assets */ + + uv_timer_stop(&timer_outer_uv); + uv_close((uv_handle_t*)&timer_outer_uv, NULL); + uv_signal_stop(&sighandler_uv); + uv_close((uv_handle_t *)&sighandler_uv, NULL); + + uv_run(&loop_uv, UV_RUN_DEFAULT); +#if (UV_VERSION_MAJOR > 0) // Travis... + uv_loop_close(&loop_uv); +#endif +} + +const struct ops ops_libuv = { + foreign_event_loop_init_and_run_libuv, + foreign_event_loop_stop_libuv, + foreign_event_loop_cleanup_libuv +}; + diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c index 90049232d..de289fb4a 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/minimal-http-server-eventlib-foreign.c @@ -23,11 +23,12 @@ #include #include -struct lws_context_creation_info info; -static struct lws_context *context; -static int lifetime = 5, reported; +#include "private.h" -static void foreign_timer_service(void *foreign_loop); +static struct lws_context_creation_info info; +static const struct ops *ops = NULL; +struct lws_context *context; +int lifetime = 5, reported; enum { TEST_STATE_CREATE_LWS_CONTEXT, @@ -57,7 +58,7 @@ static const struct lws_http_mount mount = { /* .basic_auth_login_file */ NULL, }; -static void +void signal_cb(int signum) { lwsl_notice("Signal %d caught, exiting...\n", signum); @@ -73,268 +74,9 @@ signal_cb(int signum) lws_context_destroy(context); } -/* - * The event-loop specific foreign loop code, one set for each event loop lib - * - * Only the code in this section is specific to the event library used. - */ - -#if defined(LWS_WITH_LIBUV) - -static uv_loop_t loop_uv; -static uv_timer_t timer_outer_uv; -static uv_signal_t sighandler_uv; - -static void -timer_cb_uv(uv_timer_t *t) -{ - foreign_timer_service(&loop_uv); -} - -static void -signal_cb_uv(uv_signal_t *watcher, int signum) -{ - signal_cb(signum); -} - -static void -foreign_event_loop_init_and_run_libuv(void) -{ - /* we create and start our "foreign loop" */ - -#if (UV_VERSION_MAJOR > 0) // Travis... - uv_loop_init(&loop_uv); -#endif - uv_signal_init(&loop_uv, &sighandler_uv); - uv_signal_start(&sighandler_uv, signal_cb_uv, SIGINT); - - uv_timer_init(&loop_uv, &timer_outer_uv); -#if (UV_VERSION_MAJOR > 0) // Travis... - uv_timer_start(&timer_outer_uv, timer_cb_uv, 0, 1000); -#else - (void)timer_cb_uv; -#endif - - uv_run(&loop_uv, UV_RUN_DEFAULT); -} - -static void -foreign_event_loop_stop_libuv(void) -{ - uv_stop(&loop_uv); -} - -static void -foreign_event_loop_cleanup_libuv(void) -{ - /* cleanup the foreign loop assets */ - - uv_timer_stop(&timer_outer_uv); - uv_close((uv_handle_t*)&timer_outer_uv, NULL); - uv_signal_stop(&sighandler_uv); - uv_close((uv_handle_t *)&sighandler_uv, NULL); - - uv_run(&loop_uv, UV_RUN_DEFAULT); -#if (UV_VERSION_MAJOR > 0) // Travis... - uv_loop_close(&loop_uv); -#endif -} - -#endif - -#if defined(LWS_WITH_LIBEVENT) - -static struct event_base *loop_event; -static struct event *timer_outer_event; -static struct event *sighandler_event; - -static void -timer_cb_event(int fd, short event, void *arg) -{ - foreign_timer_service(loop_event); -} - -static void -signal_cb_event(int fd, short event, void *arg) -{ - signal_cb((int)(lws_intptr_t)arg); -} - -static void -foreign_event_loop_init_and_run_libevent(void) -{ - struct timeval tv; - - /* we create and start our "foreign loop" */ - - tv.tv_sec = 1; - tv.tv_usec = 0; - - loop_event = event_base_new(); - - sighandler_event = evsignal_new(loop_event, SIGINT, signal_cb_event, - (void*)SIGINT); - - timer_outer_event = event_new(loop_event, -1, EV_PERSIST, - timer_cb_event, NULL); - //evtimer_new(loop_event, timer_cb_event, NULL); - evtimer_add(timer_outer_event, &tv); - - event_base_loop(loop_event, 0); -} - -static void -foreign_event_loop_stop_libevent(void) -{ - event_base_loopexit(loop_event, NULL); -} - -static void -foreign_event_loop_cleanup_libevent(void) -{ - /* cleanup the foreign loop assets */ - - evtimer_del(timer_outer_event); - event_free(timer_outer_event); - evsignal_del(sighandler_event); - event_free(sighandler_event); - - event_base_loop(loop_event, 0); - event_base_free(loop_event); -} - -#endif - -#if defined(LWS_WITH_GLIB) - -#include -#include - -typedef struct lws_glib_tag { - GSource *gs; - guint tag; -} lws_glib_tag_t; - -#define lws_gs_valid(t) (t.gs) -#define lws_gs_destroy(t) if (lws_gs_valid(t)) { \ - g_source_remove(t.tag); \ - g_source_unref(t.gs); \ - t.gs = NULL; t.tag = 0; } - -static GMainLoop *loop_glib; -static lws_glib_tag_t timer_outer_glib, sighandler_glib; - -static int -timer_cb_glib(void *p) -{ - foreign_timer_service(loop_glib); - return 1; -} - -static void -signal_cb_glib(void *p) -{ - signal_cb(SIGINT); -} - -static void -foreign_event_loop_init_and_run_glib(void) -{ - /* we create and start our "foreign loop" */ - - loop_glib = g_main_loop_new(NULL, 0); - - sighandler_glib.gs = g_unix_signal_source_new(SIGINT); - g_source_set_callback(sighandler_glib.gs, G_SOURCE_FUNC(signal_cb_glib), - NULL, NULL); - sighandler_glib.tag = g_source_attach(sighandler_glib.gs, - g_main_loop_get_context(loop_glib)); - - timer_outer_glib.gs = g_timeout_source_new(1000); - g_source_set_callback(timer_outer_glib.gs, timer_cb_glib, NULL, NULL); - timer_outer_glib.tag = g_source_attach(timer_outer_glib.gs, - g_main_loop_get_context(loop_glib)); - - g_main_loop_run(loop_glib); -} - -static void -foreign_event_loop_stop_glib(void) -{ - g_main_loop_quit(loop_glib); -} - -static void -foreign_event_loop_cleanup_glib(void) -{ - /* cleanup the foreign loop assets */ - - lws_gs_destroy(sighandler_glib); - lws_gs_destroy(timer_outer_glib); - - g_main_loop_unref(loop_glib); - loop_glib = NULL; -} - -#endif - -#if defined(LWS_WITH_LIBEV) - -static struct ev_loop *loop_ev; -static struct ev_timer timer_outer_ev; -static struct ev_signal sighandler_ev; - -static void -timer_cb_ev(struct ev_loop *loop, struct ev_timer *watcher, int revents) -{ - foreign_timer_service(loop_ev); -} - -static void -signal_cb_ev(struct ev_loop *loop, struct ev_signal *watcher, int revents) -{ - signal_cb(watcher->signum); -} - -static void -foreign_event_loop_init_and_run_libev(void) -{ - /* we create and start our "foreign loop" */ - - loop_ev = ev_loop_new(0); - - ev_signal_init(&sighandler_ev, signal_cb_ev, SIGINT); - ev_signal_start(loop_ev, &sighandler_ev); - - ev_timer_init(&timer_outer_ev, timer_cb_ev, 0, 1); - ev_timer_start(loop_ev, &timer_outer_ev); - - ev_run(loop_ev, 0); -} - -static void -foreign_event_loop_stop_libev(void) -{ - ev_break(loop_ev, EVBREAK_ALL); -} - -static void -foreign_event_loop_cleanup_libev(void) -{ - /* cleanup the foreign loop assets */ - - ev_timer_stop(loop_ev, &timer_outer_ev); - ev_signal_stop(loop_ev, &sighandler_ev); - - ev_run(loop_ev, 0); - ev_loop_destroy(loop_ev); -} - -#endif - /* this is called at 1Hz using a foreign loop timer */ -static void +void foreign_timer_service(void *foreign_loop) { void *foreign_loops[1]; @@ -377,22 +119,7 @@ foreign_timer_service(void *foreign_loop) case TEST_STATE_EXIT: lwsl_user("Deciding to exit foreign loop too\n"); -#if defined(LWS_WITH_LIBUV) - if (info.options & LWS_SERVER_OPTION_LIBUV) - foreign_event_loop_stop_libuv(); -#endif -#if defined(LWS_WITH_LIBEVENT) - if (info.options & LWS_SERVER_OPTION_LIBEVENT) - foreign_event_loop_stop_libevent(); -#endif -#if defined(LWS_WITH_LIBEV) - if (info.options & LWS_SERVER_OPTION_LIBEV) - foreign_event_loop_stop_libev(); -#endif -#if defined(LWS_WITH_GLIB) - if (info.options & LWS_SERVER_OPTION_GLIB) - foreign_event_loop_stop_glib(); -#endif + ops->stop(); break; default: break; @@ -437,23 +164,45 @@ int main(int argc, const char **argv) info.ssl_private_key_filepath = "localhost-100y.key"; } - if (lws_cmdline_option(argc, argv, "--uv")) + /* + * We configure lws to use the chosen event loop, and select the + * matching event-lib specific code for our demo operations + */ + +#if defined(LWS_WITH_LIBUV) + if (lws_cmdline_option(argc, argv, "--uv")) { info.options |= LWS_SERVER_OPTION_LIBUV; - else - if (lws_cmdline_option(argc, argv, "--event")) + ops = &ops_libuv; + lwsl_notice("%s: using libuv event loop\n", __func__); + } else +#endif +#if defined(LWS_WITH_LIBEVENT) + if (lws_cmdline_option(argc, argv, "--event")) { info.options |= LWS_SERVER_OPTION_LIBEVENT; - else - if (lws_cmdline_option(argc, argv, "--ev")) + ops = &ops_libevent; + lwsl_notice("%s: using libevent loop\n", __func__); + } else +#endif +#if defined(LWS_WITH_LIBEV) + if (lws_cmdline_option(argc, argv, "--ev")) { info.options |= LWS_SERVER_OPTION_LIBEV; - else - if (lws_cmdline_option(argc, argv, "--glib")) + ops = &ops_libev; + lwsl_notice("%s: using libev loop\n", __func__); + } else +#endif +#if defined(LWS_WITH_GLIB) + if (lws_cmdline_option(argc, argv, "--glib")) { info.options |= LWS_SERVER_OPTION_GLIB; - else { + ops = &ops_glib; + lwsl_notice("%s: using glib loop\n", __func__); + } else +#endif + { lwsl_err("This app only makes sense when used\n"); lwsl_err(" with a foreign loop, --uv, --event, --glib, or --ev\n"); return 1; - } + } lwsl_user(" This app creates a foreign event loop with a timer +\n"); lwsl_user(" signalhandler, and performs a test in three phases:\n"); @@ -469,43 +218,13 @@ int main(int argc, const char **argv) /* foreign loop specific startup and run */ -#if defined(LWS_WITH_LIBUV) - if (info.options & LWS_SERVER_OPTION_LIBUV) - foreign_event_loop_init_and_run_libuv(); -#endif -#if defined(LWS_WITH_LIBEVENT) - if (info.options & LWS_SERVER_OPTION_LIBEVENT) - foreign_event_loop_init_and_run_libevent(); -#endif -#if defined(LWS_WITH_LIBEV) - if (info.options & LWS_SERVER_OPTION_LIBEV) - foreign_event_loop_init_and_run_libev(); -#endif -#if defined(LWS_WITH_GLIB) - if (info.options & LWS_SERVER_OPTION_GLIB) - foreign_event_loop_init_and_run_glib(); -#endif + ops->init_and_run(); lws_context_destroy(context); /* foreign loop specific cleanup and exit */ -#if defined(LWS_WITH_LIBUV) - if (info.options & LWS_SERVER_OPTION_LIBUV) - foreign_event_loop_cleanup_libuv(); -#endif -#if defined(LWS_WITH_LIBEVENT) - if (info.options & LWS_SERVER_OPTION_LIBEVENT) - foreign_event_loop_cleanup_libevent(); -#endif -#if defined(LWS_WITH_LIBEV) - if (info.options & LWS_SERVER_OPTION_LIBEV) - foreign_event_loop_cleanup_libev(); -#endif -#if defined(LWS_WITH_GLIB) - if (info.options & LWS_SERVER_OPTION_GLIB) - foreign_event_loop_cleanup_glib(); -#endif + ops->cleanup(); lwsl_user("%s: exiting...\n", __func__); diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h new file mode 100644 index 000000000..71dfd2191 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h @@ -0,0 +1,15 @@ + + +struct ops { + void (*init_and_run)(void); + void (*stop)(void); + void (*cleanup)(void); +}; + +extern struct lws_context *context; +extern int lifetime, reported; + +void foreign_timer_service(void *foreign_loop); +void signal_cb(int signum); + +extern const struct ops ops_libuv, ops_libevent, ops_glib, ops_libev; diff --git a/minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c b/minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c index 3ca808332..11e4405ba 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-post/minimal-secure-streams-post.c @@ -396,7 +396,7 @@ myss_state(void *userobj, void *sh, lws_ss_constate_t state, /* provide a hint about the payload size */ m->pos = 0; m->len = strlen(postbody); - lws_ss_request_tx_len(m->ss, strlen(postbody)); + lws_ss_request_tx_len(m->ss, (unsigned long)strlen(postbody)); break; case LWSSSCS_CONNECTED: lws_ss_request_tx(m->ss); diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c b/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c index 5c2c2c176..b82f1f6e2 100644 --- a/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c +++ b/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c @@ -199,8 +199,9 @@ myss_srv_state(void *userobj, void *sh, lws_ss_constate_t state, /* * ...it's going to be whatever size it is (and request tx) */ - lws_ss_request_tx_len(m->ss, multipart ? strlen(multipart_html) : - strlen(html)); + lws_ss_request_tx_len(m->ss, (unsigned long) + (multipart ? strlen(multipart_html) : + strlen(html))); break; case LWSSSCS_SERVER_UPGRADE: diff --git a/plugins/protocol_lws_raw_test.c b/plugins/protocol_lws_raw_test.c index abe29bbd6..fb7d193dd 100644 --- a/plugins/protocol_lws_raw_test.c +++ b/plugins/protocol_lws_raw_test.c @@ -72,6 +72,7 @@ #endif #include +#include struct per_vhost_data__raw_test { struct lws_context *context;