diff --git a/CMakeLists-implied-options.txt b/CMakeLists-implied-options.txt index 89e319e1f..8c6d56b45 100644 --- a/CMakeLists-implied-options.txt +++ b/CMakeLists-implied-options.txt @@ -119,7 +119,8 @@ if (LWS_WITH_LIBEV OR LWS_WITH_LIBUV OR LWS_WITH_LIBEVENT OR LWS_WITH_GLIB OR - LWS_WITH_SDEVENT) + LWS_WITH_SDEVENT OR + LWS_WITH_ULOOP) set(LWS_WITH_EVENT_LIBS 1) else() unset(LWS_WITH_EVENT_LIBS) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20e739fd3..216d77bd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,7 @@ 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) option(LWS_WITH_SDEVENT "Compile with support for sd-event loop" OFF) +option(LWS_WITH_ULOOP "Compile with support for uloop" OFF) if (UNIX) # since v4.1, on unix platforms default is build any event libs as runtime plugins diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index e60433fe2..3e0f720f1 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -202,6 +202,7 @@ #cmakedefine LWS_WITH_THREADPOOL #cmakedefine LWS_WITH_TLS #cmakedefine LWS_WITH_UDP +#cmakedefine LWS_WITH_ULOOP #cmakedefine LWS_WITH_UNIX_SOCK #cmakedefine LWS_WITH_ZIP_FOPS #cmakedefine USE_OLD_CYASSL diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index c72ded05a..99e74ffb1 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -236,6 +236,9 @@ #define LWS_SERVER_OPTION_SDEVENT (1ll << 37) /**< (CTX) Use sd-event loop */ +#define LWS_SERVER_OPTION_ULOOP (1ll << 38) + /**< (CTX) Use libubox / uloop event loop */ + /****** add new things just above ---^ ******/ diff --git a/lib/core/context.c b/lib/core/context.c index 0639cde15..3eb30b3a3 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -343,6 +343,7 @@ static const struct lws_evlib_map { { LWS_SERVER_OPTION_GLIB, "evlib_glib" }, { LWS_SERVER_OPTION_LIBEV, "evlib_ev" }, { LWS_SERVER_OPTION_SDEVENT, "evlib_sd" }, + { LWS_SERVER_OPTION_ULOOP, "evlib_uloop" }, }; static const char * const dlist[] = { ".", /* Priority 1: plugins in cwd */ @@ -554,6 +555,14 @@ lws_create_context(const struct lws_context_creation_info *info) } #endif +#if defined(LWS_WITH_ULOOP) + if (lws_check_opt(info->options, LWS_SERVER_OPTION_ULOOP)) { + extern const lws_plugin_evlib_t evlib_uloop; + plev = &evlib_uloop; + us_wait_resolution = 0; + } +#endif + #endif /* with event libs */ #endif /* not with ev plugins */ diff --git a/lib/event-libs/CMakeLists.txt b/lib/event-libs/CMakeLists.txt index b0226c281..8cbbc2f1f 100644 --- a/lib/event-libs/CMakeLists.txt +++ b/lib/event-libs/CMakeLists.txt @@ -96,7 +96,9 @@ if (LWS_WITH_SDEVENT) add_subdir_include_directories(sdevent) endif() - +if (LWS_WITH_ULOOP) + add_subdir_include_directories(uloop) +endif() # # Keep explicit parent scope exports at end diff --git a/lib/event-libs/uloop/CMakeLists.txt b/lib/event-libs/uloop/CMakeLists.txt new file mode 100644 index 000000000..20be02010 --- /dev/null +++ b/lib/event-libs/uloop/CMakeLists.txt @@ -0,0 +1,72 @@ +# +# libwebsockets - small server side websockets and web server implementation +# +# Copyright (C) 2010 - 2021 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. +# +# The strategy is to only export to PARENT_SCOPE +# +# - changes to LIB_LIST +# - includes via include_directories +# +# and keep everything else private + +include_directories(.) + +set(LWS_ULOOP_INCLUDE_DIRS CACHE PATH "Path to the libubox / uloop.h include directory") +set(LWS_ULOOP_LIBRARIES CACHE PATH "Path to the libubox library") + +if (NOT ULOOP_FOUND) + find_path(ULOOP_INCLUDE_DIRS NAMES libubox/uloop.h) + find_library(ULOOP_LIBRARIES NAMES ubox) +endif() +message("libubox include dir: ${ULOOP_INCLUDE_DIRS}") +message("libubox libraries: ${ULOOP_LIBRARIES}") +include_directories("${ULOOP_INCLUDE_DIRS}") + +if ("${LWS_ULOOP_LIBRARIES}" STREQUAL "" OR "${LWS_ULOOP_INCLUDE_DIRS}" STREQUAL "") +else() + set(ULOOP_LIBRARIES ${LWS_ULOOP_LIBRARIES}) + set(ULOOP_INCLUDE_DIRS ${LWS_ULOOP_INCLUDE_DIRS}) +endif() + + +if (LWS_WITH_EVLIB_PLUGINS) + + create_evlib_plugin(evlib_uloop + uloop.c + private-lib-event-libs-uloop.h + ${ULOOP_LIBRARIES}) + +else() + + list(APPEND LIB_LIST ${ULOOP_LIBRARIES}) + set(ULOOP_FOUND 1 PARENT_SCOPE) + if (LWS_WITH_NETWORK) + list(APPEND SOURCES + event-libs/uloop/uloop.c) + endif() +endif() + +# +# Keep explicit parent scope exports at end +# + +exports_to_parent_scope() diff --git a/lib/event-libs/uloop/private-lib-event-libs-uloop.h b/lib/event-libs/uloop/private-lib-event-libs-uloop.h new file mode 100644 index 000000000..10347706e --- /dev/null +++ b/lib/event-libs/uloop/private-lib-event-libs-uloop.h @@ -0,0 +1,37 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 - 2021 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. + */ + +#include + +struct lws_pt_eventlibs_uloop { + struct lws_context_per_thread *pt; + struct uloop_timeout hrtimer; + struct uloop_timeout idle_timer; +}; + +struct lws_wsi_eventlibs_uloop { + struct lws *wsi; + struct uloop_fd fd; + unsigned int actual_events; +}; diff --git a/lib/event-libs/uloop/uloop.c b/lib/event-libs/uloop/uloop.c new file mode 100644 index 000000000..00ed5373d --- /dev/null +++ b/lib/event-libs/uloop/uloop.c @@ -0,0 +1,319 @@ +/* + * libwebsockets - small server side websockets and web server implementation + * + * Copyright (C) 2010 - 2021 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. + */ + +#include "private-lib-core.h" +#include "private-lib-event-libs-uloop.h" + +#define pt_to_priv_uloop(_pt) ((struct lws_pt_eventlibs_uloop *)(_pt)->evlib_pt) +#define wsi_to_priv_uloop(_w) ((struct lws_wsi_eventlibs_uloop *)(_w)->evlib_wsi) + +static void +lws_uloop_hrtimer_cb(struct uloop_timeout *ti) +{ + struct lws_pt_eventlibs_uloop *upt = lws_container_of(ti, + struct lws_pt_eventlibs_uloop, hrtimer); + struct lws_context_per_thread *pt = upt->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) + uloop_timeout_set(ti, us < 1000 ? 1 : (int)(us / 1000)); + + lws_pt_unlock(pt); +} + +static void +lws_uloop_idle_timer_cb(struct uloop_timeout *ti) +{ + struct lws_pt_eventlibs_uloop *upt = lws_container_of(ti, + struct lws_pt_eventlibs_uloop, + idle_timer); + struct lws_context_per_thread *pt = upt->pt; + lws_usec_t us; + + if (pt->is_destroyed) + return; + + lws_service_do_ripe_rxflow(pt); + + /* + * is there anybody with pending stuff that needs service forcing? + */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { + /* -1 timeout means just do forced service */ + _lws_plat_service_forced_tsi(pt->context, pt->tid); + /* still somebody left who wants forced service? */ + if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) { + /* yes... come back again later */ + + uloop_timeout_set(ti, 1 /* 1ms */); + + return; + } + } + + /* account for hrtimer */ + + lws_pt_lock(pt, __func__); + us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS, + lws_now_usecs()); + if (us) { + uloop_timeout_cancel(&upt->hrtimer); + uloop_timeout_set(&upt->hrtimer, + us < 1000 ? 1 : (int)(us / 1000)); + } + + lws_pt_unlock(pt); + + if (pt->destroy_self) + lws_context_destroy(pt->context); +} + +static void +lws_uloop_cb(struct uloop_fd *ufd, unsigned int revents) +{ + struct lws_wsi_eventlibs_uloop *wu = lws_container_of(ufd, + struct lws_wsi_eventlibs_uloop, fd); + struct lws_context *context = wu->wsi->a.context; + struct lws_context_per_thread *pt; + struct lws_pollfd eventfd; + + eventfd.fd = wu->wsi->desc.sockfd; + eventfd.events = 0; + eventfd.revents = 0; + + if (revents & ULOOP_READ) { + eventfd.events = LWS_POLLIN; + eventfd.revents = LWS_POLLIN; + } + if (revents & ULOOP_WRITE) { + eventfd.events |= LWS_POLLOUT; + eventfd.revents |= LWS_POLLOUT; + } + + pt = &context->pt[(int)wu->wsi->tsi]; + if (pt->is_destroyed) + return; + + lws_service_fd_tsi(context, &eventfd, wu->wsi->tsi); + + if (pt->destroy_self) { + lwsl_notice("%s: pt destroy self coming true\n", __func__); + lws_context_destroy(pt->context); + return; + } + + /* set the idle timer for 1ms ahead */ + + uloop_timeout_cancel(&pt_to_priv_uloop(pt)->idle_timer); + uloop_timeout_set(&pt_to_priv_uloop(pt)->idle_timer, 1); +} + +static int +elops_init_pt_uloop(struct lws_context *context, void *v, int tsi) +{ + struct lws_vhost *vh = context->vhost_list; + struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt); + + ptpr->pt = pt; + + /* + * Initialize all events with the listening sockets + * and register a callback for read operations + */ + + while (vh) { + if (vh->lserv_wsi) { + struct lws_wsi_eventlibs_uloop *wu = + wsi_to_priv_uloop(vh->lserv_wsi); + wu->wsi = vh->lserv_wsi; + wu->fd.fd = vh->lserv_wsi->desc.sockfd; + wu->fd.cb = lws_uloop_cb; + uloop_fd_add(&wu->fd, ULOOP_READ); + wu->actual_events = ULOOP_READ; + } + + vh = vh->vhost_next; + } + + /* static event loop objects */ + + ptpr->hrtimer.cb = lws_uloop_hrtimer_cb; + ptpr->idle_timer.cb = lws_uloop_idle_timer_cb; + + uloop_timeout_add(&ptpr->hrtimer); + uloop_timeout_add(&ptpr->idle_timer); + + uloop_timeout_set(&ptpr->hrtimer, 1); + + return 0; +} + +static int +elops_accept_uloop(struct lws *wsi) +{ + struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi); + + wu->wsi = wsi; + wu->fd.fd = wsi->desc.sockfd; + wu->fd.cb = lws_uloop_cb; + uloop_fd_add(&wu->fd, ULOOP_READ); + wu->actual_events = ULOOP_READ; + + return 0; +} + +static void +elops_io_uloop(struct lws *wsi, unsigned int flags) +{ + struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; + struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi); + unsigned int ulf = (unsigned int)(((flags & LWS_EV_WRITE) ? ULOOP_WRITE : 0) | + ((flags & LWS_EV_READ) ? ULOOP_READ : 0)), u; + + if (wsi->a.context->being_destroyed || pt->is_destroyed) + return; + + assert((flags & (LWS_EV_START | LWS_EV_STOP)) && + (flags & (LWS_EV_READ | LWS_EV_WRITE))); + + u = wu->actual_events; + if (flags & LWS_EV_START) + u |= ulf; + if (flags & LWS_EV_STOP) + u &= ~ulf; + + uloop_fd_add(&wu->fd, u); + wu->actual_events = u; +} + +static void +elops_run_pt_uloop(struct lws_context *context, int tsi) +{ + uloop_run(); +} + +static void +elops_destroy_pt_uloop(struct lws_context *context, int tsi) +{ + struct lws_context_per_thread *pt = &context->pt[tsi]; + struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt); + struct lws_vhost *vh; + + vh = context->vhost_list; + while (vh) { + if (vh->lserv_wsi) + uloop_fd_delete(&wsi_to_priv_uloop(vh->lserv_wsi)->fd); + + vh = vh->vhost_next; + } + + uloop_timeout_cancel(&ptpr->hrtimer); + uloop_timeout_cancel(&ptpr->idle_timer); +} + +static void +elops_destroy_wsi_uloop(struct lws *wsi) +{ + struct lws_context_per_thread *pt; + + if (!wsi) + return; + + pt = &wsi->a.context->pt[(int)wsi->tsi]; + if (pt->is_destroyed) + return; + + uloop_fd_delete(&wsi_to_priv_uloop(wsi)->fd); +} + +static int +elops_wsi_logical_close_uloop(struct lws *wsi) +{ + elops_destroy_wsi_uloop(wsi); + + return 0; +} + +static int +elops_init_vhost_listen_wsi_uloop(struct lws *wsi) +{ + struct lws_wsi_eventlibs_uloop *wu; + + if (!wsi) { + assert(0); + return 0; + } + + wu = wsi_to_priv_uloop(wsi); + wu->wsi = wsi; + wu->fd.fd = wsi->desc.sockfd; + wu->fd.cb = lws_uloop_cb; + uloop_fd_add(&wu->fd, ULOOP_READ); + + wu->actual_events = ULOOP_READ; + + return 0; +} + +static const struct lws_event_loop_ops event_loop_ops_uloop = { + /* name */ "uloop", + /* init_context */ NULL, + /* destroy_context1 */ NULL, + /* destroy_context2 */ NULL, + /* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_uloop, + /* init_pt */ elops_init_pt_uloop, + /* wsi_logical_close */ elops_wsi_logical_close_uloop, + /* check_client_connect_ok */ NULL, + /* close_handle_manually */ NULL, + /* accept */ elops_accept_uloop, + /* io */ elops_io_uloop, + /* run_pt */ elops_run_pt_uloop, + /* destroy_pt */ elops_destroy_pt_uloop, + /* destroy wsi */ elops_destroy_wsi_uloop, + + /* flags */ 0, + + /* evlib_size_ctx */ 0, + /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_uloop), + /* evlib_size_vh */ 0, + /* evlib_size_wsi */ sizeof(struct lws_wsi_eventlibs_uloop), +}; + +#if defined(LWS_WITH_EVLIB_PLUGINS) +LWS_VISIBLE +#endif +const lws_plugin_evlib_t evlib_uloop = { + .hdr = { + "uloop event loop", + "lws_evlib_plugin", + LWS_BUILD_HASH, + LWS_PLUGIN_API_MAGIC + }, + + .ops = &event_loop_ops_uloop +}; diff --git a/lib/misc/dir.c b/lib/misc/dir.c index e29e6573d..94a07ca92 100644 --- a/lib/misc/dir.c +++ b/lib/misc/dir.c @@ -170,8 +170,8 @@ lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb) } #endif if (cb(dirpath, user, &lde)) { - while (++i < n) - free(namelist[i]); + while (i < n) + free(namelist[i++]); ret = 0; /* told to stop by cb */ goto bail; } 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 dd1ed19d2..fc22523ed 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 @@ -20,6 +20,7 @@ CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defin CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(LWS_WITH_LIBEV)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_LIBEV) CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(LWS_WITH_GLIB)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_GLIB) CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(LWS_WITH_SDEVENT)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_SDEVENT) +CHECK_C_SOURCE_COMPILES("#include \nint main(void) {\n#if defined(LWS_WITH_ULOOP)\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" LWS_WITH_ULOOP) if (LWS_WITH_LIBUV) find_path(LIBUV_INCLUDE_DIRS NAMES uv.h) @@ -81,11 +82,19 @@ if (LWS_WITH_SDEVENT) set(extralibs ${extralibs} ${LIBSYSTEMD_LIBRARIES}) list(APPEND SRCS libsdevent.c) endif() - +if (LWS_WITH_ULOOP) + find_path(LIBUBOX_INCLUDE_DIRS NAMES libubox/uloop.h) + find_library(LIBUBOX_LIBRARIES NAMES ubox) + message("libubox include dir: ${LIBUBOX_INCLUDE_DIRS}") + message("libubox libraries: ${LIBUBOX_LIBRARIES}") + include_directories("${LIBUBOX_INCLUDE_DIRS}") + set(extralibs ${extralibs} ${LIBUBOX_LIBRARIES}) + list(APPEND SRCS uloop.c) +endif() message("Extra libs: ${extralibs}") -if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV AND NOT LWS_WITH_GLIB) +if (NOT LWS_WITH_LIBUV AND NOT LWS_WITH_LIBEVENT AND NOT LWS_WITH_LIBEV AND NOT LWS_WITH_GLIB AND NOT LWS_WITH_ULOOP) set(requirements 0) endif() @@ -164,5 +173,13 @@ if (requirements) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign TIMEOUT 50) endif() + if (LWS_WITH_SDEVENT) + add_test(NAME hs_evlib_foreign_uloop COMMAND lws-minimal-http-server-eventlib-foreign --uloop -p ${PORT_HSEF_SRV}5) + set_tests_properties(hs_evlib_foreign_uloop + PROPERTIES + ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/minimal-examples/http-server/minimal-http-server-eventlib-foreign + TIMEOUT 50) + endif() endif() 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 2beec618c..2110319e1 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 @@ -205,6 +205,13 @@ int main(int argc, const char **argv) ops = &ops_sdevent; lwsl_notice("%s: using sd-event loop\n", __func__); } else +#endif +#if defined(LWS_WITH_ULOOP) + if (lws_cmdline_option(argc, argv, "--uloop")) { + info.options |= LWS_SERVER_OPTION_ULOOP; + ops = &ops_uloop; + lwsl_notice("%s: using uloop loop\n", __func__); + } else #endif { lwsl_err("This app only makes sense when used\n"); 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 index 8f41c4721..17928c639 100644 --- a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/private.h @@ -12,4 +12,4 @@ 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, ops_sdevent; +extern const struct ops ops_libuv, ops_libevent, ops_glib, ops_libev, ops_sdevent, ops_uloop; diff --git a/minimal-examples/http-server/minimal-http-server-eventlib-foreign/uloop.c b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/uloop.c new file mode 100644 index 000000000..c528e89c0 --- /dev/null +++ b/minimal-examples/http-server/minimal-http-server-eventlib-foreign/uloop.c @@ -0,0 +1,59 @@ +/* + * 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 uloop specific code + */ + +#include + +#include + +#include +#include + +#include "private.h" + +static struct uloop_timeout timer_outer_uloop; + +static void +timer_cb_uloop(struct uloop_timeout *ti) +{ + foreign_timer_service(NULL); + uloop_timeout_set(&timer_outer_uloop, 1090); +} + +static void +foreign_event_loop_init_and_run_uloop(void) +{ + uloop_init(); + + timer_outer_uloop.cb = timer_cb_uloop; + uloop_timeout_add(&timer_outer_uloop); + + uloop_timeout_set(&timer_outer_uloop, 1090); + + uloop_run(); +} + +static void +foreign_event_loop_stop_uloop(void) +{ + uloop_end(); +} + +static void +foreign_event_loop_cleanup_uloop(void) +{ + uloop_timeout_cancel(&timer_outer_uloop); +} + +const struct ops ops_uloop = { + foreign_event_loop_init_and_run_uloop, + foreign_event_loop_stop_uloop, + foreign_event_loop_cleanup_uloop +};