Update Files
This commit is contained in:
109
Kinc/Sources/kinc/libs/event-libs/CMakeLists.txt
Normal file
109
Kinc/Sources/kinc/libs/event-libs/CMakeLists.txt
Normal file
@ -0,0 +1,109 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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_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})
|
||||
|
||||
if (APPLE)
|
||||
set_property(TARGET websockets-${PLUGIN_NAME} PROPERTY MACOSX_RPATH YES)
|
||||
endif()
|
||||
|
||||
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_compile_definitions(websockets-${PLUGIN_NAME} PRIVATE LWS_BUILDING_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()
|
||||
|
||||
#
|
||||
# poll support gets built into the lib as the default
|
||||
#
|
||||
|
||||
if (LWS_WITH_POLL)
|
||||
add_subdir_include_directories(poll)
|
||||
endif()
|
||||
|
||||
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)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEVENT)
|
||||
add_subdir_include_directories(libevent)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_GLIB)
|
||||
add_subdir_include_directories(glib)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_LIBEV)
|
||||
add_subdir_include_directories(libev)
|
||||
set(LWS_HAVE_EVBACKEND_LINUXAIO ${LWS_HAVE_EVBACKEND_LINUXAIO} PARENT_SCOPE)
|
||||
set(LWS_HAVE_EVBACKEND_IOURING ${LWS_HAVE_EVBACKEND_IOURING} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
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
|
||||
#
|
||||
|
||||
export_to_parent_intermediate()
|
||||
set(EVLIB_PLUGINS_LIST ${EVLIB_PLUGINS_LIST} PARENT_SCOPE)
|
||||
|
169
Kinc/Sources/kinc/libs/event-libs/README.md
Normal file
169
Kinc/Sources/kinc/libs/event-libs/README.md
Normal file
@ -0,0 +1,169 @@
|
||||
## Information for new event lib implementers
|
||||
|
||||
### Introduction
|
||||
|
||||
By default lws has built-in support for POSIX poll() as the event loop on unix,
|
||||
and native WSA on windows.
|
||||
|
||||
To get access to epoll() or other platform specific better poll waits, or to
|
||||
integrate with existing applications already using a specific event loop, it can
|
||||
be desirable for lws to use another external event library, like libuv, glib,
|
||||
libevent, libev, or sdevent.
|
||||
|
||||
Lws supports wholesale replacement of its wait selectable at runtime, either by
|
||||
building support for one or more event lib into the libwebsockets library, or by
|
||||
building runtime-loadable plugins. CMake symbol `LWS_WITH_EVLIB_PLUGINS`
|
||||
decides if the support is built as plugins or included into the lws lib.
|
||||
|
||||
Due to their history libevent and libev have conflicting defines in the same
|
||||
namespace and cannot be built together if included into the lib, however when
|
||||
built as plugins they are built separately without problems.
|
||||
See ./READMEs/README.event-libs.md for more details.
|
||||
|
||||
Despite it may be more work, lws event lib implementations must support
|
||||
"foreign" loops cleanly, that is integration with an already-existing loop and
|
||||
the ability to destroy the lws_context without stopping or leaving the foreign
|
||||
loop in any different state than when lws found it. For most loops this is
|
||||
fairly simple, but with libuv async close, it required refcounting lws libuv
|
||||
handles and deferring the actual destroy until they were all really closed.
|
||||
|
||||
### Code placement
|
||||
|
||||
The code specific to the event library should live in `./lib/event-libs/**lib name**`
|
||||
|
||||
### Allowing control over enabling event libs
|
||||
|
||||
All event libs should add a cmake define `LWS_WITH_**lib name**` and make its
|
||||
build dependent on it in CMakeLists.txt. Export the cmakedefine in
|
||||
`./cmake/lws_config.h.in` as well so user builds can understand if the event
|
||||
lib is available in the lws build it is trying to bind to.
|
||||
|
||||
If the event lib is disabled in cmake, nothing in its directory is built or
|
||||
referenced.
|
||||
|
||||
### Event loop ops struct
|
||||
|
||||
The event lib support is defined by `struct lws_event_loop_ops` in
|
||||
`lib/event-libs/private-lib-event-libs.h`,
|
||||
each event lib support instantiates one of these and fills in the appropriate
|
||||
ops callbacks to perform its job. By convention that lives in
|
||||
`./lib/event-libs/**lib name**/**lib_name**.c`.
|
||||
|
||||
The ops struct must be public, not static, and must be named using `**lib_name**`,
|
||||
eg
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
### Private event lib declarations
|
||||
|
||||
Truly private declarations for the event lib support that are only referenced by
|
||||
that code can go in the event-libs directory as you like. The convention is
|
||||
they should be in the event lib support directory in a file
|
||||
`private-lib-event-libs-**lib name**.h`.
|
||||
|
||||
### Integration with lws
|
||||
|
||||
There are a couple of places to add refererences in ./lib/core/context.c, in a
|
||||
table of context creation time server option flags mapped to the **lib_name**,
|
||||
used for plugin mode, like this...
|
||||
|
||||
```
|
||||
#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" },
|
||||
};
|
||||
```
|
||||
|
||||
and for backwards compatibility add a stanza to the built-in checks like this
|
||||
|
||||
```
|
||||
#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
|
||||
```
|
||||
|
||||
Both entries are the way the main libs hook up to the selected event lib ops
|
||||
struct at runtime.
|
||||
|
||||
### Integrating event lib assets to lws
|
||||
|
||||
Declare "container structs" in your private....h for anything you need at
|
||||
wsi, pt, vhost and context levels, eg, the libuv event lib support need to
|
||||
add its own assets in the perthread struct, it declares in its private....h
|
||||
|
||||
```
|
||||
struct lws_pt_eventlibs_libuv {
|
||||
uv_loop_t *io_loop;
|
||||
struct lws_context_per_thread *pt;
|
||||
uv_signal_t signals[8];
|
||||
uv_timer_t sultimer;
|
||||
uv_idle_t idle;
|
||||
struct lws_signal_watcher_libuv w_sigint;
|
||||
};
|
||||
```
|
||||
|
||||
this is completely private and opaque, but in the ops struct there are provided
|
||||
four entries to export the sizes of these event-lib specific objects
|
||||
|
||||
```
|
||||
...
|
||||
/* 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 the particular event lib doesn't need to have a private footprint in an
|
||||
object, it can just set the size it needs there to 0.
|
||||
|
||||
When the context, pts, vhosts or wsis are created in lws, they over-allocate
|
||||
to also allow for the event lib object, and set a pointer in the lws object
|
||||
being created to point at the over-allocation. For example for the wsi
|
||||
|
||||
```
|
||||
#if defined(LWS_WITH_EVENT_LIBS)
|
||||
void *evlib_wsi; /* overallocated */
|
||||
#endif
|
||||
```
|
||||
|
||||
and similarly there are `evlib_pt` and so on for those objects, usable by the
|
||||
event lib and opaque to everyone else. Once the event lib is selected at
|
||||
runtime, all of these objects are guaranteed to have the right size object at
|
||||
`wsi->evlib_wsi` initialized to zeroes.
|
||||
|
||||
### Enabling event lib adoption
|
||||
|
||||
You need to add a `LWS_SERVER_OPTION...` flag as necessary in `./lib/libwebsockets.h`
|
||||
`enum lws_context_options`, and follow the existing code in `lws_create_context()`
|
||||
to convert the flag into binding your ops struct to the context.
|
||||
|
||||
### Implementation of the event lib bindings
|
||||
|
||||
Study eg libuv implementation, using the available ops in the struct lws_event_loop_ops
|
||||
as a guide.
|
||||
|
||||
### Destruction
|
||||
|
||||
Ending the event loop is generally a bit tricky, because if the event loop is
|
||||
internal to the lws context, you cannot destroy it while the event loop is
|
||||
running.
|
||||
|
||||
Don't add special exports... we tried that, it's a huge mess. The same user
|
||||
code should be able work with any of the event loops including poll.
|
||||
|
||||
The solution we found was hide the different processing necessary for the
|
||||
different cases in `lws_destroy_context()`. To help with that there are event
|
||||
lib ops available that will be called at two different places in the context
|
||||
destroy processing.
|
||||
|
77
Kinc/Sources/kinc/libs/event-libs/glib/CMakeLists.txt
Normal file
77
Kinc/Sources/kinc/libs/event-libs/glib/CMakeLists.txt
Normal file
@ -0,0 +1,77 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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_GLIB_INCLUDE_DIRS CACHE PATH "Path to the glib include directory")
|
||||
set(LWS_GLIB_LIBRARIES CACHE PATH "Path to the glib library")
|
||||
|
||||
include (FindPkgConfig)
|
||||
if (NOT GLIB_FOUND)
|
||||
find_path(GLIB_INCLUDE_DIRS NAMES glib-2.0/glib.h)
|
||||
find_library(GLIB_LIBRARIES NAMES glib-2.0)
|
||||
if (GLIB_INCLUDE_DIRS AND GLIB_LIBRARIES)
|
||||
set(GLIB_FOUND)
|
||||
endif()
|
||||
if (GLIB_INCLUDE_DIRS)
|
||||
set(GLIB_INCLUDE_DIRS "${GLIB_INCLUDE_DIRS}/glib-2.0" PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
PKG_SEARCH_MODULE(LWS_GLIB2 glib-2.0)
|
||||
if (LWS_GLIB2_FOUND)
|
||||
list(APPEND GLIB_INCLUDE_DIRS "${LWS_GLIB2_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
message("glib include dir: ${GLIB_INCLUDE_DIRS}")
|
||||
message("glib libraries: ${GLIB_LIBRARIES}")
|
||||
include_directories("${GLIB_INCLUDE_DIRS}")
|
||||
|
||||
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
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
516
Kinc/Sources/kinc/libs/event-libs/glib/glib.c
Normal file
516
Kinc/Sources/kinc/libs/event-libs/glib/glib.c
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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 <glib-unix.h>
|
||||
|
||||
#include "private-lib-event-libs-glib.h"
|
||||
|
||||
#if !defined(G_SOURCE_FUNC)
|
||||
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
|
||||
#endif
|
||||
|
||||
#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_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)
|
||||
#define lws_gs_destroy(t) if (lws_gs_valid(t)) { \
|
||||
g_source_destroy(t.gs); \
|
||||
g_source_unref(t.gs); \
|
||||
t.gs = NULL; t.tag = 0; }
|
||||
|
||||
static gboolean
|
||||
lws_glib_idle_timer_cb(void *p);
|
||||
|
||||
static gboolean
|
||||
lws_glib_hrtimer_cb(void *p);
|
||||
|
||||
static gboolean
|
||||
lws_glib_check(GSource *src)
|
||||
{
|
||||
struct lws_io_watcher_glib_subclass *sub =
|
||||
(struct lws_io_watcher_glib_subclass *)src;
|
||||
|
||||
return !!g_source_query_unix_fd(src, sub->tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* These helpers attach only to the main_context that belongs to the pt's glib
|
||||
* mainloop. The simpler g_timeout_add() and g_idle_add() are forbidden
|
||||
* because they implicitly choose the default main context to attach to
|
||||
* instead of specifically the loop bound to the pt.
|
||||
*
|
||||
* https://developer.gnome.org/programming-guidelines/unstable/main-contexts.html.en#what-is-gmaincontext
|
||||
*/
|
||||
|
||||
static int
|
||||
lws_glib_set_idle(struct lws_context_per_thread *pt)
|
||||
{
|
||||
if (lws_gs_valid(pt_to_priv_glib(pt)->idle))
|
||||
return 0;
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_glib_set_timeout(struct lws_context_per_thread *pt, unsigned int ms)
|
||||
{
|
||||
lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer);
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
lws_glib_dispatch(GSource *src, GSourceFunc x, gpointer userData)
|
||||
{
|
||||
struct lws_io_watcher_glib_subclass *sub =
|
||||
(struct lws_io_watcher_glib_subclass *)src;
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_pollfd eventfd;
|
||||
GIOCondition cond;
|
||||
|
||||
cond = g_source_query_unix_fd(src, sub->tag);
|
||||
eventfd.revents = (short)cond;
|
||||
|
||||
/* translate from glib event namespace to platform */
|
||||
|
||||
if (cond & G_IO_IN)
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
if (cond & G_IO_OUT)
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
if (cond & G_IO_ERR)
|
||||
eventfd.revents |= LWS_POLLHUP;
|
||||
if (cond & G_IO_HUP)
|
||||
eventfd.revents |= LWS_POLLHUP;
|
||||
|
||||
eventfd.events = eventfd.revents;
|
||||
eventfd.fd = sub->wsi->desc.sockfd;
|
||||
|
||||
lwsl_wsi_debug(sub->wsi, "fd %d, events %d",
|
||||
eventfd.fd, eventfd.revents);
|
||||
|
||||
pt = &sub->wsi->a.context->pt[(int)sub->wsi->tsi];
|
||||
if (pt->is_destroyed)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
lws_service_fd_tsi(sub->wsi->a.context, &eventfd, sub->wsi->tsi);
|
||||
|
||||
if (!lws_gs_valid(pt_to_priv_glib(pt)->idle))
|
||||
lws_glib_set_idle(pt);
|
||||
|
||||
if (pt->destroy_self)
|
||||
lws_context_destroy(pt->context);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static const GSourceFuncs lws_glib_source_ops = {
|
||||
.prepare = NULL,
|
||||
.check = lws_glib_check,
|
||||
.dispatch = lws_glib_dispatch,
|
||||
.finalize = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the callback for a timer object that is set to the earliest scheduled
|
||||
* lws event... it services any lws scheduled events that are ready, and then
|
||||
* resets the event loop timer to the earliest remaining event, if any.
|
||||
*/
|
||||
|
||||
static gboolean
|
||||
lws_glib_hrtimer_cb(void *p)
|
||||
{
|
||||
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
|
||||
unsigned int ms;
|
||||
lws_usec_t us;
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
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());
|
||||
if (us) {
|
||||
ms = (unsigned int)(us / LWS_US_PER_MS);
|
||||
if (!ms)
|
||||
ms = 1;
|
||||
|
||||
lws_glib_set_timeout(pt, ms);
|
||||
}
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
lws_glib_set_idle(pt);
|
||||
|
||||
return FALSE; /* stop it repeating */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
lws_glib_idle_timer_cb(void *p)
|
||||
{
|
||||
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
|
||||
|
||||
if (pt->is_destroyed)
|
||||
return FALSE;
|
||||
|
||||
lws_service_do_ripe_rxflow(pt);
|
||||
lws_glib_hrtimer_cb(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))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (pt->destroy_self)
|
||||
lws_context_destroy(pt->context);
|
||||
|
||||
/*
|
||||
* For glib, this disables the idle callback. Otherwise we keep
|
||||
* coming back here immediately endlessly.
|
||||
*
|
||||
* We reenable the idle callback on the next network or scheduled event
|
||||
*/
|
||||
|
||||
lws_gs_destroy(pt_to_priv_glib(pt)->idle);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
lws_glib_sigint_cb(void *ctx)
|
||||
{
|
||||
struct lws_context_per_thread *pt = ctx;
|
||||
|
||||
pt->inside_service = 1;
|
||||
|
||||
if (pt->context->eventlib_signal_cb) {
|
||||
pt->context->eventlib_signal_cb(NULL, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
if (!pt->event_loop_foreign)
|
||||
g_main_loop_quit(pt_to_loop(pt));
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_context_glib(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
// int n;
|
||||
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
// for (n = 0; n < context->count_threads; n++)
|
||||
// pt_to_priv_glib(&context->pt[n])->w_sigint.context = context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
wsi_to_subclass(wsi) = (struct lws_io_watcher_glib_subclass *)
|
||||
g_source_new((GSourceFuncs *)&lws_glib_source_ops,
|
||||
sizeof(*wsi_to_subclass(wsi)));
|
||||
if (!wsi_to_subclass(wsi))
|
||||
return 1;
|
||||
|
||||
wsipr->w_read.context = wsi->a.context;
|
||||
wsi_to_subclass(wsi)->wsi = wsi;
|
||||
|
||||
if (wsi->role_ops->file_handle)
|
||||
fd = wsi->desc.filefd;
|
||||
else
|
||||
fd = wsi->desc.sockfd;
|
||||
|
||||
wsi_to_subclass(wsi)->tag = g_source_add_unix_fd(wsi_to_gsource(wsi),
|
||||
fd, (GIOCondition)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);
|
||||
|
||||
g_source_attach(wsi_to_gsource(wsi), pt_to_g_main_context(pt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_init_glib(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
|
||||
elops_accept_glib(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
GMainLoop *loop = (GMainLoop *)_loop;
|
||||
|
||||
if (!loop)
|
||||
loop = g_main_loop_new(NULL, 0);
|
||||
else
|
||||
context->pt[tsi].event_loop_foreign = 1;
|
||||
|
||||
if (!loop) {
|
||||
lwsl_cx_err(context, "creating glib loop failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptpr->loop = loop;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_glib);
|
||||
|
||||
lws_glib_set_idle(pt);
|
||||
|
||||
/* Register the signal watcher unless it's a foreign loop */
|
||||
|
||||
if (pt->event_loop_foreign)
|
||||
return 0;
|
||||
|
||||
ptpr->sigint.tag = g_unix_signal_add(SIGINT,
|
||||
G_SOURCE_FUNC(lws_glib_sigint_cb), pt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are changing the event wait for this guy
|
||||
*/
|
||||
|
||||
static void
|
||||
elops_io_glib(struct lws *wsi, unsigned int flags)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
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)
|
||||
return;
|
||||
|
||||
if (!wsi_to_subclass(wsi))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We are being given individual set / clear operations using
|
||||
* LWS_EV_ common namespace, convert them to glib namespace bitfield
|
||||
*/
|
||||
|
||||
if (flags & LWS_EV_READ) {
|
||||
if (flags & LWS_EV_STOP)
|
||||
cond &= (unsigned int)~(G_IO_IN | G_IO_HUP);
|
||||
else
|
||||
cond |= G_IO_IN | G_IO_HUP;
|
||||
}
|
||||
|
||||
if (flags & LWS_EV_WRITE) {
|
||||
if (flags & LWS_EV_STOP)
|
||||
cond &= (unsigned int)~G_IO_OUT;
|
||||
else
|
||||
cond |= G_IO_OUT;
|
||||
}
|
||||
|
||||
wsipr->w_read.actual_events = (uint8_t)cond;
|
||||
|
||||
lwsl_wsi_debug(wsi, "fd %d, 0x%x/0x%x", wsi->desc.sockfd,
|
||||
flags, (int)cond);
|
||||
|
||||
g_source_modify_unix_fd(wsi_to_gsource(wsi), wsi_to_subclass(wsi)->tag,
|
||||
cond);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_run_pt_glib(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
|
||||
if (pt_to_loop(pt))
|
||||
g_main_loop_run(pt_to_loop(pt));
|
||||
}
|
||||
|
||||
static void
|
||||
elops_destroy_wsi_glib(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;
|
||||
|
||||
if (!wsi_to_gsource(wsi))
|
||||
return;
|
||||
|
||||
if (wsi_to_subclass(wsi)->tag) {
|
||||
g_source_remove_unix_fd(wsi_to_gsource(wsi),
|
||||
wsi_to_subclass(wsi)->tag);
|
||||
wsi_to_subclass(wsi)->tag = NULL;
|
||||
}
|
||||
|
||||
g_source_destroy(wsi_to_gsource(wsi));
|
||||
g_source_unref(wsi_to_gsource(wsi));
|
||||
wsi_to_subclass(wsi) = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_destroy_glib(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
|
||||
elops_destroy_wsi_glib(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!pt_to_loop(pt))
|
||||
return;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_glib);
|
||||
|
||||
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(ptpr->sigint);
|
||||
g_main_loop_unref(pt_to_loop(pt));
|
||||
}
|
||||
|
||||
pt_to_loop(pt) = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_destroy_context2_glib(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
int n;
|
||||
|
||||
for (n = 0; n < (int)context->count_threads; n++) {
|
||||
if (!pt->event_loop_foreign)
|
||||
g_main_loop_quit(pt_to_loop(pt));
|
||||
pt++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_wsi_logical_close_glib(struct lws *wsi)
|
||||
{
|
||||
elops_destroy_wsi_glib(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_event_loop_ops event_loop_ops_glib = {
|
||||
/* name */ "glib",
|
||||
/* init_context */ elops_init_context_glib,
|
||||
/* destroy_context1 */ NULL,
|
||||
/* destroy_context2 */ elops_destroy_context2_glib,
|
||||
/* init_vhost_listen_wsi */ elops_accept_glib,
|
||||
/* init_pt */ elops_init_pt_glib,
|
||||
/* wsi_logical_close */ elops_wsi_logical_close_glib,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ elops_accept_glib,
|
||||
/* io */ elops_io_glib,
|
||||
/* run_pt */ elops_run_pt_glib,
|
||||
/* destroy_pt */ elops_destroy_pt_glib,
|
||||
/* destroy wsi */ elops_destroy_wsi_glib,
|
||||
/* foreign_thread */ NULL,
|
||||
/* fake_POLLIN */ NULL,
|
||||
|
||||
/* 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_BUILD_HASH,
|
||||
LWS_PLUGIN_API_MAGIC
|
||||
},
|
||||
|
||||
.ops = &event_loop_ops_glib
|
||||
};
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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 <glib.h>
|
||||
|
||||
typedef struct lws_glib_tag {
|
||||
GSource *gs;
|
||||
guint tag;
|
||||
} lws_glib_tag_t;
|
||||
|
||||
struct lws_pt_eventlibs_glib {
|
||||
GMainLoop *loop;
|
||||
|
||||
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 {
|
||||
GSource base;
|
||||
struct lws *wsi;
|
||||
gpointer tag;
|
||||
};
|
||||
|
||||
/*
|
||||
* One of these is embedded in each wsi
|
||||
*/
|
||||
|
||||
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_wsi_eventlibs_glib {
|
||||
struct lws_io_watcher_glib w_read;
|
||||
};
|
||||
|
88
Kinc/Sources/kinc/libs/event-libs/libev/CMakeLists.txt
Normal file
88
Kinc/Sources/kinc/libs/event-libs/libev/CMakeLists.txt
Normal file
@ -0,0 +1,88 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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_LIBEV_LIBRARIES CACHE PATH "Path to the libev library")
|
||||
set(LWS_LIBEV_INCLUDE_DIRS CACHE PATH "Path to the libev include directory")
|
||||
|
||||
if (NOT LIBEV_FOUND)
|
||||
find_path(LIBEV_INCLUDE_DIRS NAMES ev.h)
|
||||
find_library(LIBEV_LIBRARIES NAMES ev)
|
||||
endif()
|
||||
message("libev include dir: ${LIBEV_INCLUDE_DIRS}")
|
||||
message("libev libraries: ${LIBEV_LIBRARIES}")
|
||||
include_directories("${LIBEV_INCLUDE_DIRS}")
|
||||
|
||||
if ("${LWS_LIBEV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBEV_INCLUDE_DIRS}" STREQUAL "")
|
||||
else()
|
||||
set(LIBEV_LIBRARIES ${LWS_LIBEV_LIBRARIES})
|
||||
set(LIBEV_INCLUDE_DIRS ${LWS_LIBEV_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
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" )
|
||||
endif()
|
||||
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${LIB_LIST})
|
||||
|
||||
CHECK_C_SOURCE_COMPILES(
|
||||
"#include <ev.h>
|
||||
int main(int argc, char **argv) { return EVBACKEND_LINUXAIO; }
|
||||
" LWS_HAVE_EVBACKEND_LINUXAIO)
|
||||
|
||||
CHECK_C_SOURCE_COMPILES(
|
||||
"#include <ev.h>
|
||||
int main(int argc, char **argv) { return EVBACKEND_IOURING; }
|
||||
" LWS_HAVE_EVBACKEND_IOURING)
|
||||
|
||||
#
|
||||
# Keep explicit parent scope exports at end
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
||||
set(LWS_HAVE_EVBACKEND_LINUXAIO ${LWS_HAVE_EVBACKEND_LINUXAIO} PARENT_SCOPE)
|
||||
set(LWS_HAVE_EVBACKEND_IOURING ${LWS_HAVE_EVBACKEND_IOURING} PARENT_SCOPE)
|
468
Kinc/Sources/kinc/libs/event-libs/libev/libev.c
Normal file
468
Kinc/Sources/kinc/libs/event-libs/libev/libev.c
Normal file
@ -0,0 +1,468 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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-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_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(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
|
||||
ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
|
||||
}
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_ev_idle_cb(struct ev_loop *loop, struct ev_idle *handle, int revents)
|
||||
{
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
reschedule = _lws_plat_service_forced_tsi(pt->context, pt->tid);
|
||||
|
||||
/* 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) {
|
||||
ev_timer_set(&ptpr->hrtimer, ((float)us) / 1000000.0, 0);
|
||||
ev_timer_start(ptpr->io_loop, &ptpr->hrtimer);
|
||||
}
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
/* there is nobody who needs service forcing, shut down idle */
|
||||
if (!reschedule)
|
||||
ev_idle_stop(loop, handle);
|
||||
|
||||
if (pt->destroy_self)
|
||||
lws_context_destroy(pt->context);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
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;
|
||||
int tsi = 0;
|
||||
|
||||
if (revents & EV_ERROR)
|
||||
return;
|
||||
|
||||
eventfd.fd = watcher->fd;
|
||||
eventfd.events = 0;
|
||||
eventfd.revents = EV_NONE;
|
||||
|
||||
if (revents & EV_READ) {
|
||||
eventfd.events |= LWS_POLLIN;
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
}
|
||||
if (revents & EV_WRITE) {
|
||||
eventfd.events |= LWS_POLLOUT;
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
}
|
||||
|
||||
wsi = wsi_from_fd(context, watcher->fd);
|
||||
if (wsi)
|
||||
tsi = (int)wsi->tsi;
|
||||
pt = &context->pt[tsi];
|
||||
ptpr = pt_to_priv_ev(pt);
|
||||
|
||||
lws_service_fd_tsi(context, &eventfd, tsi);
|
||||
|
||||
ev_idle_start(ptpr->io_loop, &ptpr->idle);
|
||||
}
|
||||
|
||||
void
|
||||
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)
|
||||
{
|
||||
struct lws_context *context = watcher->data;
|
||||
|
||||
if (context->eventlib_signal_cb) {
|
||||
context->eventlib_signal_cb((void *)watcher, watcher->signum);
|
||||
|
||||
return;
|
||||
}
|
||||
ev_break(loop, EVBREAK_ALL);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_init_ev(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
struct lws_context *context = (struct lws_context *)user;
|
||||
struct lws_context_per_thread *pt = &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);
|
||||
struct lws_vhost *vh = wsi->a.vhost;
|
||||
|
||||
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, wsi->desc.sockfd, EV_READ);
|
||||
ev_io_start(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
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;
|
||||
const char *backend_name;
|
||||
unsigned int backend;
|
||||
int status = 0;
|
||||
|
||||
lwsl_cx_info(context, "loop %p", _loop);
|
||||
|
||||
ptpr->pt = pt;
|
||||
|
||||
if (!loop)
|
||||
loop = ev_loop_new(0);
|
||||
else
|
||||
context->pt[tsi].event_loop_foreign = 1;
|
||||
|
||||
if (!loop) {
|
||||
lwsl_cx_err(context, "creating event base failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptpr->io_loop = loop;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_ev);
|
||||
|
||||
/* Register the signal watcher unless it's a foreign loop */
|
||||
if (!context->pt[tsi].event_loop_foreign) {
|
||||
ev_signal_init(w_sigint, lws_ev_sigint_cb, SIGINT);
|
||||
w_sigint->data = context;
|
||||
ev_signal_start(loop, w_sigint);
|
||||
}
|
||||
|
||||
backend = ev_backend(loop);
|
||||
switch (backend) {
|
||||
case EVBACKEND_SELECT:
|
||||
backend_name = "select";
|
||||
break;
|
||||
case EVBACKEND_POLL:
|
||||
backend_name = "poll";
|
||||
break;
|
||||
case EVBACKEND_EPOLL:
|
||||
backend_name = "epoll";
|
||||
break;
|
||||
#if defined(LWS_HAVE_EVBACKEND_LINUXAIO)
|
||||
case EVBACKEND_LINUXAIO:
|
||||
backend_name = "Linux AIO";
|
||||
break;
|
||||
#endif
|
||||
#if defined(LWS_HAVE_EVBACKEND_IOURING)
|
||||
case EVBACKEND_IOURING:
|
||||
backend_name = "Linux io_uring";
|
||||
break;
|
||||
#endif
|
||||
case EVBACKEND_KQUEUE:
|
||||
backend_name = "kqueue";
|
||||
break;
|
||||
case EVBACKEND_DEVPOLL:
|
||||
backend_name = "/dev/poll";
|
||||
break;
|
||||
case EVBACKEND_PORT:
|
||||
backend_name = "Solaris 10 \"port\"";
|
||||
break;
|
||||
default:
|
||||
backend_name = "Unknown libev backend";
|
||||
break;
|
||||
}
|
||||
|
||||
lwsl_cx_info(context, " libev backend: %s", backend_name);
|
||||
(void)backend_name;
|
||||
|
||||
ev_timer_init(&ptpr->hrtimer, lws_ev_hrtimer_cb, 0, 0);
|
||||
ptpr->hrtimer.data = pt;
|
||||
|
||||
ev_idle_init(&ptpr->idle, lws_ev_idle_cb);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_destroy_ev(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
struct lws_context *context = (struct lws_context *)user;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws_pt_eventlibs_libev *ptpr = pt_to_priv_ev(pt);
|
||||
struct lws_vhost *vh = wsi->a.vhost;
|
||||
|
||||
ev_io_stop(ptpr->io_loop, &vh_to_priv_ev(vh)->w_accept.watcher);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_ev);
|
||||
|
||||
/* static assets */
|
||||
|
||||
ev_timer_stop(ptpr->io_loop, &ptpr->hrtimer);
|
||||
ev_idle_stop(ptpr->io_loop, &ptpr->idle);
|
||||
|
||||
if (!pt->event_loop_foreign)
|
||||
ev_signal_stop(ptpr->io_loop, &ptpr->w_sigint.watcher);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_context_ev(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
int n;
|
||||
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
pt_to_priv_ev(&context->pt[n])->w_sigint.context = context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_accept_ev(struct lws *wsi)
|
||||
{
|
||||
struct lws_wsi_eventlibs_libev *w = wsi_to_priv_ev(wsi);
|
||||
int fd;
|
||||
|
||||
if (wsi->role_ops->file_handle)
|
||||
fd = wsi->desc.filefd;
|
||||
else
|
||||
fd = wsi->desc.sockfd;
|
||||
|
||||
w->w_read.context = wsi->a.context;
|
||||
w->w_write.context = wsi->a.context;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_io_ev(struct lws *wsi, unsigned 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);
|
||||
|
||||
lwsl_wsi_debug(wsi, "%s flags 0x%x %p %d", 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)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
|
||||
|
||||
if (flags & LWS_EV_START) {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
ev_io_start(ptpr->io_loop, &w->w_write.watcher);
|
||||
if (flags & LWS_EV_READ)
|
||||
ev_io_start(ptpr->io_loop, &w->w_read.watcher);
|
||||
} else {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
|
||||
if (flags & LWS_EV_READ)
|
||||
ev_io_stop(ptpr->io_loop, &w->w_read.watcher);
|
||||
}
|
||||
|
||||
if (pt->destroy_self)
|
||||
lws_context_destroy(pt->context);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_run_pt_ev(struct lws_context *context, int tsi)
|
||||
{
|
||||
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;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
int budget = 1000;
|
||||
|
||||
pt = &context->pt[n];
|
||||
ptpr = pt_to_priv_ev(pt);
|
||||
|
||||
/* only for internal loops... */
|
||||
|
||||
if (pt->event_loop_foreign || !ptpr->io_loop)
|
||||
continue;
|
||||
|
||||
if (!context->evlib_finalize_destroy_after_int_loops_stop) {
|
||||
ev_break(ptpr->io_loop, EVBREAK_ONE);
|
||||
continue;
|
||||
}
|
||||
while (budget-- &&
|
||||
(m = ev_run(ptpr->io_loop, 0)))
|
||||
;
|
||||
|
||||
ev_loop_destroy(ptpr->io_loop);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_vhost_listen_wsi_ev(struct lws *wsi)
|
||||
{
|
||||
struct lws_wsi_eventlibs_libev *w;
|
||||
int fd;
|
||||
|
||||
if (!wsi) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(&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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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(ptpr->io_loop, &w->w_read.watcher);
|
||||
ev_io_stop(ptpr->io_loop, &w->w_write.watcher);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_wsi_logical_close_ev(struct lws *wsi)
|
||||
{
|
||||
elops_destroy_wsi_ev(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_event_loop_ops event_loop_ops_ev = {
|
||||
/* name */ "libev",
|
||||
/* init_context */ elops_init_context_ev,
|
||||
/* destroy_context1 */ NULL,
|
||||
/* destroy_context2 */ elops_destroy_context2_ev,
|
||||
/* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_ev,
|
||||
/* init_pt */ elops_init_pt_ev,
|
||||
/* wsi_logical_close */ elops_wsi_logical_close_ev,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ elops_accept_ev,
|
||||
/* io */ elops_io_ev,
|
||||
/* run_pt */ elops_run_pt_ev,
|
||||
/* destroy_pt */ elops_destroy_pt_ev,
|
||||
/* destroy wsi */ elops_destroy_wsi_ev,
|
||||
/* foreign_thread */ NULL,
|
||||
/* fake_POLLIN */ NULL,
|
||||
|
||||
/* 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_BUILD_HASH,
|
||||
LWS_PLUGIN_API_MAGIC
|
||||
},
|
||||
|
||||
.ops = &event_loop_ops_ev
|
||||
};
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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 <ev.h>
|
||||
|
||||
#define LWS_EV_REFCOUNT_STATIC_HANDLE_NEW(_x, _ctx) \
|
||||
{ (_x)->data = _ctx; \
|
||||
_ctx->count_event_loop_static_asset_handles++; }
|
||||
#define LWS_EV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x) \
|
||||
((struct lws_context *)(_x)->data)))
|
||||
#define LWS_EV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \
|
||||
(--(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_vh_eventlibs_libev {
|
||||
struct lws_io_watcher_libev w_accept;
|
||||
};
|
||||
|
||||
struct lws_wsi_eventlibs_libev {
|
||||
struct lws_io_watcher_libev w_read;
|
||||
struct lws_io_watcher_libev w_write;
|
||||
};
|
||||
|
72
Kinc/Sources/kinc/libs/event-libs/libevent/CMakeLists.txt
Normal file
72
Kinc/Sources/kinc/libs/event-libs/libevent/CMakeLists.txt
Normal file
@ -0,0 +1,72 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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_LIBEVENT_INCLUDE_DIRS CACHE PATH "Path to the libevent include directory")
|
||||
set(LWS_LIBEVENT_LIBRARIES CACHE PATH "Path to the libevent library")
|
||||
|
||||
if (NOT LIBEVENT_FOUND)
|
||||
find_path(LIBEVENT_INCLUDE_DIRS NAMES event2/event.h)
|
||||
find_library(LIBEVENT_LIBRARIES NAMES event)
|
||||
endif()
|
||||
message("libevent include dir: ${LIBEVENT_INCLUDE_DIRS}")
|
||||
message("libevent libraries: ${LIBEVENT_LIBRARIES}")
|
||||
include_directories("${LIBEVENT_INCLUDE_DIRS}")
|
||||
|
||||
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})
|
||||
endif()
|
||||
|
||||
|
||||
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()
|
||||
|
||||
#
|
||||
# Keep explicit parent scope exports at end
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
520
Kinc/Sources/kinc/libs/event-libs/libevent/libevent.c
Normal file
520
Kinc/Sources/kinc/libs/event-libs/libevent/libevent.c
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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-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(evutil_socket_t 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;
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
|
||||
lws_now_usecs());
|
||||
if (us) {
|
||||
#if defined(__APPLE__)
|
||||
tv.tv_sec = (int)(us / LWS_US_PER_SEC);
|
||||
tv.tv_usec = (int)(us - (tv.tv_sec * LWS_US_PER_SEC));
|
||||
#else
|
||||
tv.tv_sec = (long)(us / LWS_US_PER_SEC);
|
||||
tv.tv_usec = (long)(us - (tv.tv_sec * LWS_US_PER_SEC));
|
||||
#endif
|
||||
evtimer_add(ptpr->hrtimer, &tv);
|
||||
}
|
||||
lws_pt_unlock(pt);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_event_idle_timer_cb(evutil_socket_t 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;
|
||||
|
||||
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 */
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000;
|
||||
evtimer_add(ptpr->idle_timer, &tv);
|
||||
|
||||
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) {
|
||||
tv.tv_sec = (suseconds_t)(us / LWS_US_PER_SEC);
|
||||
tv.tv_usec = (suseconds_t)(us - (tv.tv_sec * LWS_US_PER_SEC));
|
||||
evtimer_add(ptpr->hrtimer, &tv);
|
||||
}
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
if (pt->destroy_self)
|
||||
lws_context_destroy(pt->context);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_event_cb(evutil_socket_t sock_fd, short revents, void *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;
|
||||
struct timeval tv;
|
||||
struct lws *wsi;
|
||||
|
||||
if (revents & EV_TIMEOUT)
|
||||
return;
|
||||
|
||||
/* !!! EV_CLOSED doesn't exist in libevent2 */
|
||||
#if LIBEVENT_VERSION_NUMBER < 0x02000000
|
||||
if (revents & EV_CLOSED) {
|
||||
event_del(lws_io->event.watcher);
|
||||
event_free(lws_io->event.watcher);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
eventfd.fd = sock_fd;
|
||||
eventfd.events = 0;
|
||||
eventfd.revents = 0;
|
||||
if (revents & EV_READ) {
|
||||
eventfd.events |= LWS_POLLIN;
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
}
|
||||
if (revents & EV_WRITE) {
|
||||
eventfd.events |= LWS_POLLOUT;
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
}
|
||||
|
||||
wsi = wsi_from_fd(context, sock_fd);
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
pt = &context->pt[(int)wsi->tsi];
|
||||
if (pt->is_destroyed)
|
||||
return;
|
||||
|
||||
lws_service_fd_tsi(context, &eventfd, wsi->tsi);
|
||||
|
||||
if (pt->destroy_self) {
|
||||
lwsl_cx_notice(context, "pt destroy self coming true");
|
||||
lws_context_destroy(pt->context);
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the idle timer for 1ms ahead */
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 1000;
|
||||
evtimer_add(pt_to_priv_event(pt)->idle_timer, &tv);
|
||||
}
|
||||
|
||||
void
|
||||
lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
|
||||
{
|
||||
struct lws_context_per_thread *pt = ctx;
|
||||
struct event *signal = pt_to_priv_event(pt)->w_sigint.watcher;
|
||||
|
||||
if (pt->context->eventlib_signal_cb) {
|
||||
pt->context->eventlib_signal_cb((void *)(lws_intptr_t)sock_fd,
|
||||
event_get_signal(signal));
|
||||
|
||||
return;
|
||||
}
|
||||
if (!pt->event_loop_foreign)
|
||||
event_base_loopbreak(pt_to_priv_event(pt)->io_loop);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_init_event(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
struct lws_context *context = (struct lws_context *)user;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
|
||||
struct lws_io_watcher_libevent *w_read =
|
||||
&(wsi_to_priv_event(wsi)->w_read);
|
||||
|
||||
w_read->context = context;
|
||||
w_read->watcher = event_new(ptpr->io_loop, wsi->desc.sockfd,
|
||||
(EV_READ | EV_PERSIST), lws_event_cb, w_read);
|
||||
event_add(w_read->watcher, NULL);
|
||||
w_read->set = 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_pt_event(struct lws_context *context, void *_loop, int tsi)
|
||||
{
|
||||
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_cx_info(context, "loop %p", _loop);
|
||||
|
||||
if (!loop)
|
||||
loop = event_base_new();
|
||||
else
|
||||
context->pt[tsi].event_loop_foreign = 1;
|
||||
|
||||
if (!loop) {
|
||||
lwsl_cx_err(context, "creating event base failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptpr->io_loop = loop;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_event);
|
||||
|
||||
/* static event loop objects */
|
||||
|
||||
ptpr->hrtimer = event_new(loop, -1, EV_PERSIST,
|
||||
lws_event_hrtimer_cb, pt);
|
||||
|
||||
ptpr->idle_timer = event_new(loop, -1, 0,
|
||||
lws_event_idle_timer_cb, pt);
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = (long)0;
|
||||
tv.tv_usec = (long)1000;
|
||||
evtimer_add(ptpr->hrtimer, &tv);
|
||||
}
|
||||
|
||||
/* Register the signal watcher unless it's a foreign loop */
|
||||
|
||||
if (pt->event_loop_foreign)
|
||||
return 0;
|
||||
|
||||
ptpr->w_sigint.watcher = evsignal_new(loop, SIGINT,
|
||||
lws_event_sigint_cb, pt);
|
||||
event_add(ptpr->w_sigint.watcher, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_context_event(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
int n;
|
||||
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
pt_to_priv_event(&context->pt[n])->w_sigint.context = context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
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);
|
||||
evutil_socket_t fd;
|
||||
|
||||
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 = (evutil_socket_t)(ev_intptr_t) wsi->desc.filefd;
|
||||
else
|
||||
fd = wsi->desc.sockfd;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_io_event(struct lws *wsi, unsigned 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 (!ptpr->io_loop || wsi->a.context->being_destroyed ||
|
||||
pt->is_destroyed)
|
||||
return;
|
||||
|
||||
assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)));
|
||||
|
||||
if (flags & LWS_EV_START) {
|
||||
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) && !wpr->w_read.set) {
|
||||
event_add(wpr->w_read.watcher, NULL);
|
||||
wpr->w_read.set = 1;
|
||||
}
|
||||
} else {
|
||||
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) && wpr->w_read.set) {
|
||||
event_del(wpr->w_read.watcher);
|
||||
wpr->w_read.set = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
elops_run_pt_event(struct lws_context *context, int tsi)
|
||||
{
|
||||
/* Run / Dispatch the event_base loop */
|
||||
if (pt_to_priv_event(&context->pt[tsi])->io_loop)
|
||||
event_base_dispatch(
|
||||
pt_to_priv_event(&context->pt[tsi])->io_loop);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_destroy_event(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
struct lws_wsi_eventlibs_libevent *w = wsi_to_priv_event(wsi);
|
||||
|
||||
event_free(w->w_read.watcher);
|
||||
w->w_read.watcher = NULL;
|
||||
event_free(w->w_write.watcher);
|
||||
w->w_write.watcher = NULL;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!ptpr->io_loop)
|
||||
return;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_event);
|
||||
|
||||
event_free(ptpr->hrtimer);
|
||||
event_free(ptpr->idle_timer);
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
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_cx_notice(context, "set to exit loop");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
elops_destroy_wsi_event(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_wsi_eventlibs_libevent *w;
|
||||
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
if (pt->is_destroyed)
|
||||
return;
|
||||
|
||||
w = wsi_to_priv_event(wsi);
|
||||
|
||||
if (w->w_read.watcher) {
|
||||
event_free(w->w_read.watcher);
|
||||
w->w_read.watcher = NULL;
|
||||
}
|
||||
|
||||
if (w->w_write.watcher) {
|
||||
event_free(w->w_write.watcher);
|
||||
w->w_write.watcher = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
elops_wsi_logical_close_event(struct lws *wsi)
|
||||
{
|
||||
elops_destroy_wsi_event(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
evutil_socket_t fd;
|
||||
|
||||
if (!wsi) {
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 = (evutil_socket_t) wsi->desc.filefd;
|
||||
else
|
||||
fd = wsi->desc.sockfd;
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
int budget = 1000;
|
||||
|
||||
pt = &context->pt[n];
|
||||
ptpr = pt_to_priv_event(pt);
|
||||
|
||||
/* only for internal loops... */
|
||||
|
||||
if (pt->event_loop_foreign || !ptpr->io_loop)
|
||||
continue;
|
||||
|
||||
if (!context->evlib_finalize_destroy_after_int_loops_stop) {
|
||||
event_base_loopexit(ptpr->io_loop, NULL);
|
||||
continue;
|
||||
}
|
||||
while (budget-- &&
|
||||
(m = event_base_loop(ptpr->io_loop, EVLOOP_NONBLOCK)))
|
||||
;
|
||||
|
||||
lwsl_cx_info(context, "event_base_free");
|
||||
|
||||
event_base_free(ptpr->io_loop);
|
||||
ptpr->io_loop = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lws_event_loop_ops event_loop_ops_event = {
|
||||
/* name */ "libevent",
|
||||
/* init_context */ elops_init_context_event,
|
||||
/* destroy_context1 */ NULL,
|
||||
/* destroy_context2 */ elops_destroy_context2_event,
|
||||
/* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_event,
|
||||
/* init_pt */ elops_init_pt_event,
|
||||
/* wsi_logical_close */ elops_wsi_logical_close_event,
|
||||
/* check_client_connect_ok */ NULL,
|
||||
/* close_handle_manually */ NULL,
|
||||
/* accept */ elops_accept_event,
|
||||
/* io */ elops_io_event,
|
||||
/* run_pt */ elops_run_pt_event,
|
||||
/* destroy_pt */ elops_destroy_pt_event,
|
||||
/* destroy wsi */ elops_destroy_wsi_event,
|
||||
/* foreign_thread */ NULL,
|
||||
/* fake_POLLIN */ NULL,
|
||||
|
||||
/* 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_BUILD_HASH,
|
||||
LWS_PLUGIN_API_MAGIC
|
||||
},
|
||||
|
||||
.ops = &event_loop_ops_event
|
||||
};
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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 <event2/event.h>
|
||||
|
||||
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_wsi_eventlibs_libevent {
|
||||
struct lws_io_watcher_libevent w_read;
|
||||
struct lws_io_watcher_libevent w_write;
|
||||
};
|
86
Kinc/Sources/kinc/libs/event-libs/libuv/CMakeLists.txt
Normal file
86
Kinc/Sources/kinc/libs/event-libs/libuv/CMakeLists.txt
Normal file
@ -0,0 +1,86 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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_LIBUV_LIBRARIES CACHE PATH "Path to the libuv library")
|
||||
set(LWS_LIBUV_INCLUDE_DIRS CACHE PATH "Path to the libuv include directory")
|
||||
|
||||
if ("${LWS_LIBUV_LIBRARIES}" STREQUAL "" OR "${LWS_LIBUV_INCLUDE_DIRS}" STREQUAL "")
|
||||
if (NOT LIBUV_FOUND)
|
||||
find_path(LIBUV_INCLUDE_DIRS NAMES uv.h)
|
||||
find_library(LIBUV_LIBRARIES NAMES uv)
|
||||
endif()
|
||||
else()
|
||||
set(LIBUV_LIBRARIES ${LWS_LIBUV_LIBRARIES})
|
||||
set(LIBUV_INCLUDE_DIRS ${LWS_LIBUV_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
message("libuv include dir: ${LIBUV_INCLUDE_DIRS}")
|
||||
message("libuv libraries: ${LIBUV_LIBRARIES}")
|
||||
|
||||
include_directories("${LIBUV_INCLUDE_DIRS}")
|
||||
|
||||
CHECK_INCLUDE_FILE(uv-version.h LWS_HAVE_UV_VERSION_H)
|
||||
# libuv changed the location in 1.21.0. Retain both
|
||||
# checks temporarily to ensure a smooth transition.
|
||||
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)
|
||||
|
||||
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
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
||||
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)
|
||||
set(LIBUV_INCLUDE_DIRS ${LIBUV_INCLUDE_DIRS} PARENT_SCOPE)
|
952
Kinc/Sources/kinc/libs/event-libs/libuv/libuv.c
Normal file
952
Kinc/Sources/kinc/libs/event-libs/libuv/libuv.c
Normal file
@ -0,0 +1,952 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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-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
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(timer,
|
||||
struct lws_pt_eventlibs_libuv, sultimer);
|
||||
struct lws_context_per_thread *pt = ptpr->pt;
|
||||
lws_usec_t us;
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
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_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb,
|
||||
LWS_US_TO_MS((uint64_t)us), 0);
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_uv_idle(uv_idle_t *handle
|
||||
#if UV_VERSION_MAJOR == 0
|
||||
, int status
|
||||
#endif
|
||||
)
|
||||
{ struct lws_pt_eventlibs_libuv *ptpr = lws_container_of(handle,
|
||||
struct lws_pt_eventlibs_libuv, idle);
|
||||
struct lws_context_per_thread *pt = ptpr->pt;
|
||||
lws_usec_t us;
|
||||
|
||||
lws_service_do_ripe_rxflow(pt);
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* account for sultimer */
|
||||
|
||||
us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
|
||||
lws_now_usecs());
|
||||
if (us)
|
||||
uv_timer_start(&pt_to_priv_uv(pt)->sultimer, lws_uv_sultimer_cb,
|
||||
LWS_US_TO_MS((uint64_t)us), 0);
|
||||
|
||||
/* if there is nobody who needs service forcing, shut down idle */
|
||||
if (lws_service_adjust_timeout(pt->context, 1, pt->tid))
|
||||
uv_idle_stop(handle);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_io_cb(uv_poll_t *watcher, int status, int revents)
|
||||
{
|
||||
struct lws *wsi = (struct lws *)((uv_handle_t *)watcher)->data;
|
||||
struct lws_context *context = wsi->a.context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
|
||||
struct lws_pollfd eventfd;
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
if (pt->is_destroyed)
|
||||
goto bail;
|
||||
|
||||
if (!ptpriv->thread_valid) {
|
||||
/* record the thread id that gave us our first event */
|
||||
ptpriv->uv_thread = uv_thread_self();
|
||||
ptpriv->thread_valid = 1;
|
||||
}
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
eventfd.fd = watcher->socket;
|
||||
#else
|
||||
eventfd.fd = watcher->io_watcher.fd;
|
||||
#endif
|
||||
eventfd.events = 0;
|
||||
eventfd.revents = 0;
|
||||
|
||||
if (status < 0) {
|
||||
/*
|
||||
* At this point status will be an UV error, like UV_EBADF,
|
||||
* we treat all errors as LWS_POLLHUP
|
||||
*
|
||||
* You might want to return; instead of servicing the fd in
|
||||
* some cases */
|
||||
if (status == UV_EAGAIN)
|
||||
goto bail;
|
||||
|
||||
eventfd.events |= LWS_POLLHUP;
|
||||
eventfd.revents |= LWS_POLLHUP;
|
||||
} else {
|
||||
if (revents & UV_READABLE) {
|
||||
eventfd.events |= LWS_POLLIN;
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
}
|
||||
if (revents & UV_WRITABLE) {
|
||||
eventfd.events |= LWS_POLLOUT;
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
}
|
||||
}
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
|
||||
lws_service_fd_tsi(context, &eventfd, wsi->tsi);
|
||||
|
||||
if (pt->destroy_self) {
|
||||
lws_context_destroy(pt->context);
|
||||
return;
|
||||
}
|
||||
|
||||
uv_idle_start(&ptpriv->idle, lws_uv_idle);
|
||||
return;
|
||||
|
||||
bail:
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
}
|
||||
|
||||
/*
|
||||
* This does not actually stop the event loop. The reason is we have to pass
|
||||
* libuv handle closures through its event loop. So this tries to close all
|
||||
* wsi, and set a flag; when all the wsi closures are finalized then we
|
||||
* actually stop the libuv event loops.
|
||||
*/
|
||||
static void
|
||||
lws_libuv_stop(struct lws_context *context)
|
||||
{
|
||||
if (context->requested_stop_internal_loops) {
|
||||
lwsl_cx_err(context, "ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
context->requested_stop_internal_loops = 1;
|
||||
lws_context_destroy(context);
|
||||
}
|
||||
|
||||
static void
|
||||
lws_uv_signal_handler(uv_signal_t *watcher, int signum)
|
||||
{
|
||||
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)
|
||||
watcher->data;
|
||||
|
||||
if (pt->context->eventlib_signal_cb) {
|
||||
pt->context->eventlib_signal_cb((void *)watcher, signum);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_cx_err(pt->context, "internal signal handler caught signal %d",
|
||||
signum);
|
||||
lws_libuv_stop(pt->context);
|
||||
}
|
||||
|
||||
static int
|
||||
lws_uv_finalize_pt(struct lws_context_per_thread *pt)
|
||||
{
|
||||
pt->event_loop_pt_unused = 1;
|
||||
|
||||
lwsl_cx_info(pt->context, "thr %d", (int)(pt - pt->context->pt));
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
|
||||
if (!--pt->context->undestroyed_threads) {
|
||||
struct lws_vhost *vh = pt->context->vhost_list;
|
||||
|
||||
/*
|
||||
* eventually, we emptied all the pts...
|
||||
*/
|
||||
|
||||
lwsl_cx_debug(pt->context, "all pts down now");
|
||||
|
||||
/* protocols may have initialized libuv objects */
|
||||
|
||||
while (vh) {
|
||||
lws_vhost_destroy1(vh);
|
||||
vh = vh->vhost_next;
|
||||
}
|
||||
|
||||
if (!pt->count_event_loop_static_asset_handles &&
|
||||
pt->event_loop_foreign) {
|
||||
lwsl_cx_info(pt->context, "resuming context_destroy");
|
||||
lws_context_unlock(pt->context);
|
||||
lws_context_destroy(pt->context);
|
||||
/*
|
||||
* For foreign, we're being called from the foreign
|
||||
* thread context the loop is associated with, we must
|
||||
* return to it cleanly even though we are done with it.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
lwsl_cx_debug(pt->context, "still %d undestroyed",
|
||||
pt->context->undestroyed_threads);
|
||||
|
||||
lws_context_unlock(pt->context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
|
||||
// {
|
||||
// if (!uv_is_closing(handle))
|
||||
// lwsl_err("%s: handle %p still alive on loop\n", __func__, handle);
|
||||
// }
|
||||
|
||||
|
||||
static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };
|
||||
|
||||
/*
|
||||
* Closing Phase 2: Close callback for a static UV asset
|
||||
*/
|
||||
|
||||
static void
|
||||
lws_uv_close_cb_sa(uv_handle_t *handle)
|
||||
{
|
||||
struct lws_context_per_thread *pt =
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(handle);
|
||||
struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
|
||||
struct lws_context *context = pt->context;
|
||||
#if !defined(LWS_WITH_NO_LOGS) && defined(_DEBUG)
|
||||
int tsi = (int)(pt - &context->pt[0]);
|
||||
#endif
|
||||
|
||||
lwsl_cx_info(context, "thr %d: sa left %d: dyn left: %d (rk %d)",
|
||||
tsi,
|
||||
pt->count_event_loop_static_asset_handles - 1,
|
||||
ptpriv->extant_handles,
|
||||
context->requested_stop_internal_loops);
|
||||
|
||||
/* any static assets left? */
|
||||
|
||||
if (LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(handle) ||
|
||||
ptpriv->extant_handles)
|
||||
return;
|
||||
|
||||
/*
|
||||
* So we believe nothing of ours left on the loop. Let's sanity
|
||||
* check it to count what's still on the loop
|
||||
*/
|
||||
|
||||
// uv_walk(pt_to_priv_uv(pt)->io_loop, lws_uv_walk_cb, NULL);
|
||||
|
||||
/*
|
||||
* That's it... all wsi were down, and now every
|
||||
* static asset lws had a UV handle for is down.
|
||||
*
|
||||
* Stop the loop so we can get out of here.
|
||||
*/
|
||||
|
||||
lwsl_cx_info(context, "thr %d: seen final static handle gone", tsi);
|
||||
|
||||
if (!pt->event_loop_foreign)
|
||||
lws_context_destroy(context);
|
||||
|
||||
lws_uv_finalize_pt(pt);
|
||||
|
||||
lwsl_cx_info(context, "all done");
|
||||
}
|
||||
|
||||
/*
|
||||
* These must be called by protocols that want to use libuv objects directly...
|
||||
*
|
||||
* .... when the libuv object is created...
|
||||
*/
|
||||
|
||||
void
|
||||
lws_libuv_static_refcount_add(uv_handle_t *h, struct lws_context *context,
|
||||
int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(h, pt);
|
||||
}
|
||||
|
||||
/*
|
||||
* ... and in the close callback when the object is closed.
|
||||
*/
|
||||
|
||||
void
|
||||
lws_libuv_static_refcount_del(uv_handle_t *h)
|
||||
{
|
||||
lws_uv_close_cb_sa(h);
|
||||
}
|
||||
|
||||
void
|
||||
lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)
|
||||
{
|
||||
if (pt_to_priv_uv(&context->pt[tsi])->io_loop)
|
||||
uv_stop(pt_to_priv_uv(&context->pt[tsi])->io_loop);
|
||||
}
|
||||
|
||||
uv_loop_t *
|
||||
lws_uv_getloop(struct lws_context *context, int tsi)
|
||||
{
|
||||
if (pt_to_priv_uv(&context->pt[tsi])->io_loop)
|
||||
return pt_to_priv_uv(&context->pt[tsi])->io_loop;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_libuv_check_watcher_active(struct lws *wsi)
|
||||
{
|
||||
uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher;
|
||||
|
||||
if (!h)
|
||||
return 0;
|
||||
|
||||
return uv_is_active(h);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_context_uv(struct lws_context *context,
|
||||
const struct lws_context_creation_info *info)
|
||||
{
|
||||
int n;
|
||||
|
||||
context->eventlib_signal_cb = info->signal_cb;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++)
|
||||
pt_to_priv_uv(&context->pt[n])->w_sigint.context = context;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_destroy_context1_uv(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, m = 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
int budget = 10000;
|
||||
pt = &context->pt[n];
|
||||
|
||||
/* only for internal loops... */
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
|
||||
while (budget-- && (m = uv_run(pt_to_priv_uv(pt)->io_loop,
|
||||
UV_RUN_NOWAIT)))
|
||||
;
|
||||
if (m)
|
||||
lwsl_cx_info(context, "tsi %d: unclosed", n);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* call destroy2 if internal loop */
|
||||
return !context->pt[0].event_loop_foreign;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_destroy_context2_uv(struct lws_context *context)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
int n, internal = 0;
|
||||
|
||||
for (n = 0; n < context->count_threads; n++) {
|
||||
pt = &context->pt[n];
|
||||
|
||||
/* only for internal loops... */
|
||||
|
||||
if (!pt->event_loop_foreign && pt_to_priv_uv(pt)->io_loop) {
|
||||
internal = 1;
|
||||
if (!context->evlib_finalize_destroy_after_int_loops_stop)
|
||||
uv_stop(pt_to_priv_uv(pt)->io_loop);
|
||||
else {
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_close(pt_to_priv_uv(pt)->io_loop);
|
||||
#endif
|
||||
lws_free_set_NULL(pt_to_priv_uv(pt)->io_loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return internal;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_wsi_logical_close_uv(struct lws *wsi)
|
||||
{
|
||||
if (!lws_socket_is_valid(wsi->desc.sockfd) &&
|
||||
wsi->role_ops && strcmp(wsi->role_ops->name, "raw-file") &&
|
||||
!wsi_to_priv_uv(wsi)->w_read.pwatcher)
|
||||
return 0;
|
||||
|
||||
if (wsi->listener || wsi->event_pipe) {
|
||||
lwsl_wsi_debug(wsi, "%d %d stop listener / pipe poll",
|
||||
wsi->listener,
|
||||
wsi->event_pipe);
|
||||
if (wsi_to_priv_uv(wsi)->w_read.pwatcher)
|
||||
uv_poll_stop(wsi_to_priv_uv(wsi)->w_read.pwatcher);
|
||||
}
|
||||
lwsl_wsi_debug(wsi, "lws_libuv_closehandle");
|
||||
/*
|
||||
* libuv has to do his own close handle processing asynchronously
|
||||
*/
|
||||
lws_libuv_closehandle(wsi);
|
||||
|
||||
return 1; /* do not complete the wsi close, uv close cb will do it */
|
||||
}
|
||||
|
||||
static int
|
||||
elops_check_client_connect_ok_uv(struct lws *wsi)
|
||||
{
|
||||
if (lws_libuv_check_watcher_active(wsi)) {
|
||||
lwsl_wsi_warn(wsi, "Waiting for libuv watcher to close");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_libuv_closewsi_m(uv_handle_t* handle)
|
||||
{
|
||||
lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data;
|
||||
|
||||
lwsl_debug("%s: sockfd %d\n", __func__, sockfd);
|
||||
compatible_close(sockfd);
|
||||
lws_free(handle);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_close_handle_manually_uv(struct lws *wsi)
|
||||
{
|
||||
uv_handle_t *h = (uv_handle_t *)wsi_to_priv_uv(wsi)->w_read.pwatcher;
|
||||
|
||||
lwsl_wsi_debug(wsi, "lws_libuv_closehandle");
|
||||
|
||||
/*
|
||||
* the "manual" variant only closes the handle itself and the
|
||||
* related fd. handle->data is the fd.
|
||||
*/
|
||||
h->data = (void *)(lws_intptr_t)wsi->desc.sockfd;
|
||||
|
||||
/*
|
||||
* We take responsibility to close / destroy these now.
|
||||
* Remove any trace from the wsi.
|
||||
*/
|
||||
|
||||
wsi->desc.sockfd = LWS_SOCK_INVALID;
|
||||
wsi_to_priv_uv(wsi)->w_read.pwatcher = NULL;
|
||||
wsi->told_event_loop_closed = 1;
|
||||
|
||||
uv_close(h, lws_libuv_closewsi_m);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_accept_uv(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
|
||||
struct lws_io_watcher_libuv *w_read = &wsi_to_priv_uv(wsi)->w_read;
|
||||
int n;
|
||||
|
||||
if (!ptpriv->thread_valid) {
|
||||
/* record the thread id that gave us our first event */
|
||||
ptpriv->uv_thread = uv_thread_self();
|
||||
ptpriv->thread_valid = 1;
|
||||
}
|
||||
|
||||
w_read->context = wsi->a.context;
|
||||
|
||||
w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh");
|
||||
if (!w_read->pwatcher)
|
||||
return -1;
|
||||
|
||||
if (wsi->role_ops->file_handle)
|
||||
n = uv_poll_init(pt_to_priv_uv(pt)->io_loop, w_read->pwatcher,
|
||||
(int)(lws_intptr_t)wsi->desc.filefd);
|
||||
else
|
||||
n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop,
|
||||
w_read->pwatcher, wsi->desc.sockfd);
|
||||
|
||||
if (n) {
|
||||
lwsl_wsi_err(wsi, "uv_poll_init failed %d, sockfd=%p", n,
|
||||
(void *)(lws_intptr_t)wsi->desc.sockfd);
|
||||
lws_free(w_read->pwatcher);
|
||||
w_read->pwatcher = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi;
|
||||
|
||||
ptpriv->extant_handles++;
|
||||
|
||||
lwsl_wsi_debug(wsi, "thr %d: sa left %d: dyn left: %d",
|
||||
(int)(pt - &pt->context->pt[0]),
|
||||
pt->count_event_loop_static_asset_handles,
|
||||
ptpriv->extant_handles);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_io_uv(struct lws *wsi, unsigned int flags)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
struct lws_io_watcher_libuv *w = &(wsi_to_priv_uv(wsi)->w_read);
|
||||
int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
|
||||
|
||||
lwsl_wsi_debug(wsi, "%d", flags);
|
||||
|
||||
/* w->context is set after the loop is initialized */
|
||||
|
||||
if (!pt_to_priv_uv(pt)->io_loop || !w->context) {
|
||||
lwsl_wsi_info(wsi, "no io loop yet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
|
||||
lwsl_wsi_err(wsi, "assert: flags %d", flags);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (!w->pwatcher || wsi->told_event_loop_closed) {
|
||||
lwsl_wsi_info(wsi, "no watcher");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & LWS_EV_START) {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
current_events |= UV_WRITABLE;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
current_events |= UV_READABLE;
|
||||
|
||||
uv_poll_start(w->pwatcher, current_events, lws_io_cb);
|
||||
} else {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
current_events &= ~UV_WRITABLE;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
current_events &= ~UV_READABLE;
|
||||
|
||||
if (!(current_events & (UV_READABLE | UV_WRITABLE)))
|
||||
uv_poll_stop(w->pwatcher);
|
||||
else
|
||||
uv_poll_start(w->pwatcher, current_events, lws_io_cb);
|
||||
}
|
||||
|
||||
w->actual_events = (uint8_t)current_events;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_vhost_listen_wsi_uv(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
struct lws_pt_eventlibs_libuv *ptpriv;
|
||||
struct lws_io_watcher_libuv *w_read;
|
||||
int n;
|
||||
|
||||
if (!wsi)
|
||||
return 0;
|
||||
|
||||
w_read = &wsi_to_priv_uv(wsi)->w_read;
|
||||
|
||||
if (w_read->context)
|
||||
return 0;
|
||||
|
||||
pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
ptpriv = pt_to_priv_uv(pt);
|
||||
if (!ptpriv->io_loop)
|
||||
return 0;
|
||||
|
||||
w_read->context = wsi->a.context;
|
||||
|
||||
w_read->pwatcher = lws_malloc(sizeof(*w_read->pwatcher), "uvh");
|
||||
if (!w_read->pwatcher)
|
||||
return -1;
|
||||
|
||||
n = uv_poll_init_socket(pt_to_priv_uv(pt)->io_loop,
|
||||
w_read->pwatcher, wsi->desc.sockfd);
|
||||
if (n) {
|
||||
lwsl_wsi_err(wsi, "uv_poll_init failed %d, sockfd=%p", n,
|
||||
(void *)(lws_intptr_t)wsi->desc.sockfd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptpriv->extant_handles++;
|
||||
|
||||
lwsl_wsi_debug(wsi, "thr %d: sa left %d: dyn left: %d",
|
||||
(int)(pt - &pt->context->pt[0]),
|
||||
pt->count_event_loop_static_asset_handles,
|
||||
ptpriv->extant_handles);
|
||||
|
||||
((uv_handle_t *)w_read->pwatcher)->data = (void *)wsi;
|
||||
|
||||
elops_io_uv(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
elops_run_pt_uv(struct lws_context *context, int tsi)
|
||||
{
|
||||
if (pt_to_priv_uv(&context->pt[tsi])->io_loop)
|
||||
uv_run(pt_to_priv_uv(&context->pt[tsi])->io_loop, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
elops_destroy_pt_uv(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
|
||||
int m, ns;
|
||||
|
||||
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
|
||||
return;
|
||||
|
||||
if (!ptpriv->io_loop)
|
||||
return;
|
||||
|
||||
if (pt->event_loop_destroy_processing_done) {
|
||||
if (!pt->event_loop_foreign) {
|
||||
lwsl_warn("%s: stopping event loop\n", __func__);
|
||||
uv_stop(pt_to_priv_uv(pt)->io_loop);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
pt->event_loop_destroy_processing_done = 1;
|
||||
// lwsl_cx_debug(context, "%d", tsi);
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
|
||||
uv_signal_stop(&pt_to_priv_uv(pt)->w_sigint.watcher);
|
||||
|
||||
ns = LWS_ARRAY_SIZE(sigs);
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
|
||||
ns = 2;
|
||||
|
||||
for (m = 0; m < ns; 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_cx_debug(context, "not closing pt signals");
|
||||
|
||||
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_to_priv_uv(pt)->idle);
|
||||
uv_close((uv_handle_t *)&pt_to_priv_uv(pt)->idle, lws_uv_close_cb_sa);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_init_uv(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
|
||||
if (elops_init_vhost_listen_wsi_uv(wsi) == -1)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This needs to be called after vhosts have been defined.
|
||||
*
|
||||
* If later, after server start, another vhost is added, this must be
|
||||
* called again to bind the vhost
|
||||
*/
|
||||
|
||||
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);
|
||||
int status = 0, n, ns, first = 1;
|
||||
uv_loop_t *loop = (uv_loop_t *)_loop;
|
||||
|
||||
ptpriv->pt = pt;
|
||||
|
||||
if (!ptpriv->io_loop) {
|
||||
if (!loop) {
|
||||
loop = lws_malloc(sizeof(*loop), "libuv loop");
|
||||
if (!loop) {
|
||||
lwsl_cx_err(context, "OOM");
|
||||
return -1;
|
||||
}
|
||||
#if UV_VERSION_MAJOR > 0
|
||||
uv_loop_init(loop);
|
||||
#else
|
||||
lwsl_cx_err(context, "This libuv is too old to work...");
|
||||
return 1;
|
||||
#endif
|
||||
pt->event_loop_foreign = 0;
|
||||
} else {
|
||||
lwsl_cx_notice(context, " Using foreign event loop...");
|
||||
pt->event_loop_foreign = 1;
|
||||
}
|
||||
|
||||
ptpriv->io_loop = loop;
|
||||
uv_idle_init(loop, &ptpriv->idle);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->idle, pt);
|
||||
uv_idle_start(&ptpriv->idle, lws_uv_idle);
|
||||
|
||||
ns = LWS_ARRAY_SIZE(sigs);
|
||||
if (lws_check_opt(context->options,
|
||||
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
|
||||
ns = 2;
|
||||
|
||||
if (!pt->event_loop_foreign) {
|
||||
assert(ns <= (int)LWS_ARRAY_SIZE(ptpriv->signals));
|
||||
for (n = 0; n < ns; n++) {
|
||||
uv_signal_init(loop, &ptpriv->signals[n]);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(
|
||||
&ptpriv->signals[n], pt);
|
||||
ptpriv->signals[n].data = pt;
|
||||
uv_signal_start(&ptpriv->signals[n],
|
||||
lws_uv_signal_handler, sigs[n]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
first = 0;
|
||||
|
||||
/*
|
||||
* Initialize the accept wsi read watcher with all the listening sockets
|
||||
* and register a callback for read operations
|
||||
*
|
||||
* We have to do it here because the uv loop(s) are not
|
||||
* initialized until after context creation.
|
||||
*/
|
||||
lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_uv);
|
||||
|
||||
if (!first)
|
||||
return status;
|
||||
|
||||
uv_timer_init(ptpriv->io_loop, &ptpriv->sultimer);
|
||||
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&ptpriv->sultimer, pt);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
lws_libuv_closewsi(uv_handle_t* handle)
|
||||
{
|
||||
struct lws *wsi = (struct lws *)handle->data;
|
||||
struct lws_context *context = lws_get_context(wsi);
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
int lspd = 0;
|
||||
#endif
|
||||
|
||||
// lwsl_wsi_notice(wsi, "in");
|
||||
|
||||
lws_context_lock(context, __func__);
|
||||
|
||||
/*
|
||||
* We get called back here for every wsi that closes
|
||||
*/
|
||||
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
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)
|
||||
lspd = 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
lwsl_wsi_info(wsi, "thr %d: sa left %d: dyn left: %d (rk %d)",
|
||||
(int)(pt - &pt->context->pt[0]),
|
||||
pt->count_event_loop_static_asset_handles,
|
||||
ptpriv->extant_handles - 1,
|
||||
context->requested_stop_internal_loops);
|
||||
|
||||
__lws_close_free_wsi_final(wsi);
|
||||
assert(ptpriv->extant_handles);
|
||||
ptpriv->extant_handles--;
|
||||
lws_pt_unlock(pt);
|
||||
|
||||
/* it's our job to close the handle finally */
|
||||
lws_free(handle);
|
||||
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
if (lspd == 2 && context->deprecation_cb) {
|
||||
lwsl_cx_notice(context, "calling deprecation callback");
|
||||
context->deprecation_cb();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* eventually, we closed all the wsi...
|
||||
*/
|
||||
|
||||
if (context->requested_stop_internal_loops &&
|
||||
!ptpriv->extant_handles &&
|
||||
!pt->count_event_loop_static_asset_handles) {
|
||||
|
||||
/*
|
||||
* we closed everything on this pt
|
||||
*/
|
||||
|
||||
lws_context_unlock(context);
|
||||
lws_uv_finalize_pt(pt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lws_context_unlock(context);
|
||||
}
|
||||
|
||||
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 (!w_read->pwatcher)
|
||||
return;
|
||||
|
||||
if (wsi->told_event_loop_closed)
|
||||
return;
|
||||
|
||||
// lwsl_wsi_debug(wsi, "in");
|
||||
|
||||
wsi->told_event_loop_closed = 1;
|
||||
|
||||
/*
|
||||
* The normal close path attaches the related wsi as the
|
||||
* handle->data.
|
||||
*/
|
||||
|
||||
handle = (uv_handle_t *)w_read->pwatcher;
|
||||
|
||||
/* ensure we can only do this once */
|
||||
|
||||
w_read->pwatcher = NULL;
|
||||
|
||||
uv_close(handle, lws_libuv_closewsi);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_foreign_thread_uv(struct lws_context *cx, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &cx->pt[tsi];
|
||||
struct lws_pt_eventlibs_libuv *ptpriv = pt_to_priv_uv(pt);
|
||||
uv_thread_t th = uv_thread_self();
|
||||
|
||||
if (!ptpriv->thread_valid)
|
||||
/*
|
||||
* We can't judge it until we get the first event from the loop
|
||||
*/
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* This is the same thread that gave us the first event on this loop?
|
||||
* Return 0 if so.
|
||||
*/
|
||||
|
||||
return !uv_thread_equal(&th, &ptpriv->uv_thread);
|
||||
}
|
||||
|
||||
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,
|
||||
/* destroy_context2 */ elops_destroy_context2_uv,
|
||||
/* init_vhost_listen_wsi */ elops_init_vhost_listen_wsi_uv,
|
||||
/* init_pt */ elops_init_pt_uv,
|
||||
/* wsi_logical_close */ elops_wsi_logical_close_uv,
|
||||
/* check_client_connect_ok */ elops_check_client_connect_ok_uv,
|
||||
/* close_handle_manually */ elops_close_handle_manually_uv,
|
||||
/* accept */ elops_accept_uv,
|
||||
/* io */ elops_io_uv,
|
||||
/* run_pt */ elops_run_pt_uv,
|
||||
/* destroy_pt */ elops_destroy_pt_uv,
|
||||
/* destroy wsi */ NULL,
|
||||
/* foreign_thread */ elops_foreign_thread_uv,
|
||||
/* fake_POLLIN */ 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_BUILD_HASH,
|
||||
LWS_PLUGIN_API_MAGIC
|
||||
},
|
||||
|
||||
.ops = &event_loop_ops_uv
|
||||
};
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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 <uv.h>
|
||||
|
||||
/*
|
||||
* libuv's async destroy cb means that asking to close something doesn't mean
|
||||
* you can destroy it or parent things until after the close completes.
|
||||
*
|
||||
* So we must reference-count creation and close completions with libuv.
|
||||
*
|
||||
* All "static" (per-pt or per-context) uv handles must
|
||||
*
|
||||
* - have their .data set to point to the context
|
||||
*
|
||||
* - contribute to context->uv_count_static_asset_handles
|
||||
* counting
|
||||
*/
|
||||
#define LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(_x, _pt) \
|
||||
{ uv_handle_t *_uht = (uv_handle_t *)(_x); _uht->data = _pt; \
|
||||
_pt->count_event_loop_static_asset_handles++; }
|
||||
#define LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(_x) \
|
||||
((struct lws_context_per_thread *)((uv_handle_t *)((_x)->data)))
|
||||
#define LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \
|
||||
(--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_PT(_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;
|
||||
struct lws_context_per_thread *pt;
|
||||
uv_signal_t signals[8];
|
||||
uv_timer_t sultimer;
|
||||
uv_idle_t idle;
|
||||
|
||||
uv_thread_t uv_thread;
|
||||
|
||||
struct lws_signal_watcher_libuv w_sigint;
|
||||
int extant_handles;
|
||||
|
||||
char thread_valid;
|
||||
};
|
||||
|
||||
struct lws_context_eventlibs_libuv {
|
||||
uv_loop_t loop;
|
||||
};
|
||||
|
||||
struct lws_io_watcher_libuv {
|
||||
uv_poll_t *pwatcher;
|
||||
struct lws_context *context;
|
||||
uint8_t actual_events;
|
||||
};
|
||||
|
||||
struct lws_wsi_eventlibs_libuv {
|
||||
struct lws_io_watcher_libuv w_read;
|
||||
};
|
||||
|
||||
uv_loop_t *
|
||||
lws_uv_getloop(struct lws_context *context, int tsi);
|
||||
|
||||
int
|
||||
lws_uv_plugins_init(struct lws_context *context, const char * const *d);
|
||||
|
||||
int
|
||||
lws_uv_plugins_destroy(struct lws_context *context);
|
42
Kinc/Sources/kinc/libs/event-libs/poll/CMakeLists.txt
Normal file
42
Kinc/Sources/kinc/libs/event-libs/poll/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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(../poll)
|
||||
|
||||
if (LWS_WITH_NETWORK)
|
||||
list(APPEND SOURCES
|
||||
event-libs/poll/poll.c)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Keep explicit parent scope exports at end
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
62
Kinc/Sources/kinc/libs/event-libs/poll/poll.c
Normal file
62
Kinc/Sources/kinc/libs/event-libs/poll/poll.c
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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-poll.h"
|
||||
|
||||
static int
|
||||
elops_foreign_thread_poll(struct lws_context *cx, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &cx->pt[tsi];
|
||||
volatile struct lws_context_per_thread *vpt =
|
||||
(volatile struct lws_context_per_thread *)pt;
|
||||
|
||||
/*
|
||||
* To avoid mandating a specific threading library, we can check
|
||||
* probabilistically by seeing if the lws default wait is still asleep
|
||||
* at the time we are checking, if it is then we cannot be being called
|
||||
* by the event loop loop thread.
|
||||
*/
|
||||
|
||||
return vpt->inside_poll;
|
||||
}
|
||||
|
||||
struct lws_event_loop_ops event_loop_ops_poll = {
|
||||
.name = "poll",
|
||||
|
||||
.foreign_thread = elops_foreign_thread_poll,
|
||||
|
||||
.flags = LELOF_ISPOLL,
|
||||
};
|
||||
|
||||
const lws_plugin_evlib_t evlib_poll = {
|
||||
.hdr = {
|
||||
"poll",
|
||||
"lws_evlib_plugin",
|
||||
"n/a",
|
||||
LWS_PLUGIN_API_MAGIC
|
||||
},
|
||||
|
||||
.ops = &event_loop_ops_poll
|
||||
};
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern struct lws_event_loop_ops event_loop_ops_poll;
|
27
Kinc/Sources/kinc/libs/event-libs/private-lib-event-libs.h
Normal file
27
Kinc/Sources/kinc/libs/event-libs/private-lib-event-libs.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This is included from private-lib-core.h
|
||||
*/
|
||||
|
||||
|
44
Kinc/Sources/kinc/libs/event-libs/sdevent/CMakeLists.txt
Normal file
44
Kinc/Sources/kinc/libs/event-libs/sdevent/CMakeLists.txt
Normal file
@ -0,0 +1,44 @@
|
||||
# The strategy is to only export to PARENT_SCOPE
|
||||
#
|
||||
# - changes to LIB_LIST
|
||||
# - includes via include_directories
|
||||
#
|
||||
# and keep everything else private
|
||||
|
||||
include_directories(.)
|
||||
|
||||
# configure or find systemd library
|
||||
set(LIB_SYSTEMD_LIBRARIES CACHE PATH "Path to the libsystemd library")
|
||||
if ("${LWS_SYSTEMD_LIBRARIES}" STREQUAL "")
|
||||
if (NOT LIB_SYSTEMD_FOUND)
|
||||
find_path(LIBSYSTEMD_INCLUDE_DIRS NAMES systemd/sd-event.h)
|
||||
find_library(LIBSYSTEMD_LIBRARIES NAMES systemd)
|
||||
endif()
|
||||
else()
|
||||
set(LIBSYSTEMD_LIBRARIES ${LWS_SYSTEMD_LIBRARIES})
|
||||
set(LIBSYSTEMD_INCLUDE_DIRS ${LWS_LIBSYSTEMD_INCLUDE_DIRS})
|
||||
endif()
|
||||
message("libsystemd include dir: ${LIBSYSTEMD_INCLUDE_DIRS}")
|
||||
message("libsystemd libraries: ${LIBSYSTEMD_LIBRARIES}")
|
||||
|
||||
if (LWS_WITH_EVLIB_PLUGINS)
|
||||
|
||||
create_evlib_plugin(
|
||||
evlib_sd
|
||||
sdevent.c
|
||||
private-lib-event-libs-sdevent.h
|
||||
${LIBSYSTEMD_LIBRARIES}
|
||||
)
|
||||
|
||||
else()
|
||||
|
||||
list(APPEND LIB_LIST ${LIBSYSTEMD_LIBRARIES})
|
||||
list(APPEND SOURCES event-libs/sdevent/sdevent.c)
|
||||
|
||||
endif()
|
||||
|
||||
#
|
||||
# Keep explicit parent scope exports at end
|
||||
#
|
||||
|
||||
exports_to_parent_scope()
|
@ -0,0 +1,3 @@
|
||||
#include <private-lib-core.h>
|
||||
|
||||
extern const struct lws_event_loop_ops event_loop_ops_sdevent;
|
446
Kinc/Sources/kinc/libs/event-libs/sdevent/sdevent.c
Normal file
446
Kinc/Sources/kinc/libs/event-libs/sdevent/sdevent.c
Normal file
@ -0,0 +1,446 @@
|
||||
#include <systemd/sd-event.h>
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-event-libs-sdevent.h"
|
||||
|
||||
#define pt_to_priv_sd(_pt) ((struct lws_pt_eventlibs_sdevent *)(_pt)->evlib_pt)
|
||||
#define wsi_to_priv_sd(_w) ((struct lws_wsi_watcher_sdevent *)(_w)->evlib_wsi)
|
||||
|
||||
struct lws_pt_eventlibs_sdevent {
|
||||
struct lws_context_per_thread *pt;
|
||||
struct sd_event *io_loop;
|
||||
struct sd_event_source *sultimer;
|
||||
struct sd_event_source *idletimer;
|
||||
};
|
||||
|
||||
struct lws_wsi_watcher_sdevent {
|
||||
struct sd_event_source *source;
|
||||
uint32_t events;
|
||||
};
|
||||
|
||||
static int
|
||||
sultimer_handler(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
{
|
||||
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)userdata;
|
||||
|
||||
lws_usec_t us;
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
|
||||
lws_now_usecs());
|
||||
if (us) {
|
||||
uint64_t at;
|
||||
|
||||
sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &at);
|
||||
at += (uint64_t)us;
|
||||
sd_event_source_set_time(pt_to_priv_sd(pt)->sultimer, at);
|
||||
sd_event_source_set_enabled(pt_to_priv_sd(pt)->sultimer,
|
||||
SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
idle_handler(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
{
|
||||
struct lws_context_per_thread *pt = (struct lws_context_per_thread *)userdata;
|
||||
|
||||
lws_usec_t us;
|
||||
|
||||
lws_service_do_ripe_rxflow(pt);
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/* account for sultimer */
|
||||
|
||||
us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
|
||||
lws_now_usecs());
|
||||
|
||||
if (us) {
|
||||
uint64_t at;
|
||||
|
||||
sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &at);
|
||||
at += (uint64_t)us;
|
||||
sd_event_source_set_time(pt_to_priv_sd(pt)->sultimer, at);
|
||||
sd_event_source_set_enabled(pt_to_priv_sd(pt)->sultimer,
|
||||
SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
sd_event_source_set_enabled(pt_to_priv_sd(pt)->idletimer, SD_EVENT_OFF);
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sock_accept_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata)
|
||||
{
|
||||
struct lws *wsi = (struct lws *)userdata;
|
||||
struct lws_context *context = wsi->a.context;
|
||||
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
|
||||
struct sd_event_source *idletimer, *watcher;
|
||||
struct lws_pollfd eventfd;
|
||||
|
||||
lws_context_lock(pt->context, __func__);
|
||||
lws_pt_lock(pt, __func__);
|
||||
|
||||
if (pt->is_destroyed)
|
||||
goto bail;
|
||||
|
||||
eventfd.fd = fd;
|
||||
eventfd.events = 0;
|
||||
eventfd.revents = 0;
|
||||
|
||||
if (revents & EPOLLIN) {
|
||||
eventfd.events |= LWS_POLLIN;
|
||||
eventfd.revents |= LWS_POLLIN;
|
||||
}
|
||||
|
||||
if (revents & EPOLLOUT) {
|
||||
eventfd.events |= LWS_POLLOUT;
|
||||
eventfd.revents |= LWS_POLLOUT;
|
||||
}
|
||||
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
|
||||
lws_service_fd_tsi(context, &eventfd, wsi->tsi);
|
||||
|
||||
if (pt->destroy_self) {
|
||||
lws_context_destroy(pt->context);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* fire idle handler */
|
||||
idletimer = pt_to_priv_sd(pt)->idletimer;
|
||||
if (idletimer) {
|
||||
sd_event_source_set_time(idletimer, (uint64_t) 0);
|
||||
sd_event_source_set_enabled(idletimer, SD_EVENT_ON);
|
||||
}
|
||||
|
||||
/*
|
||||
* allow further events
|
||||
*
|
||||
* Note:
|
||||
* do not move the assignment up, lws_service_fd_tsi may invalidate it!
|
||||
*/
|
||||
watcher = wsi_to_priv_sd(wsi)->source;
|
||||
if (watcher)
|
||||
sd_event_source_set_enabled(watcher, SD_EVENT_ONESHOT);
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
lws_pt_unlock(pt);
|
||||
lws_context_unlock(pt->context);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
io_sd(struct lws *wsi, unsigned int flags)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
|
||||
/*
|
||||
* Only manipulate if there is an event source, and if
|
||||
* the pt is still alive
|
||||
*/
|
||||
if (!pt_to_priv_sd(pt)->io_loop ||
|
||||
!wsi_to_priv_sd(wsi)->source ||
|
||||
pt->is_destroyed)
|
||||
return;
|
||||
|
||||
// assert that the requested flags do not contain anything unexpected
|
||||
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
|
||||
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
|
||||
lwsl_wsi_err(wsi, "assert: flags %d", flags);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
// we are overdoing a bit here, so it resembles the structure in libuv.c
|
||||
if (flags & LWS_EV_START) {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
wsi_to_priv_sd(wsi)->events |= EPOLLOUT;
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
wsi_to_priv_sd(wsi)->events |= EPOLLIN;
|
||||
|
||||
sd_event_source_set_io_events(wsi_to_priv_sd(wsi)->source,
|
||||
wsi_to_priv_sd(wsi)->events);
|
||||
sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
|
||||
SD_EVENT_ONESHOT);
|
||||
} else {
|
||||
if (flags & LWS_EV_WRITE)
|
||||
wsi_to_priv_sd(wsi)->events =
|
||||
wsi_to_priv_sd(wsi)->events &
|
||||
(uint32_t)(~EPOLLOUT);
|
||||
|
||||
if (flags & LWS_EV_READ)
|
||||
wsi_to_priv_sd(wsi)->events =
|
||||
wsi_to_priv_sd(wsi)->events &
|
||||
(uint32_t)(~EPOLLIN);
|
||||
|
||||
sd_event_source_set_io_events(wsi_to_priv_sd(wsi)->source,
|
||||
wsi_to_priv_sd(wsi)->events);
|
||||
|
||||
if (!(wsi_to_priv_sd(wsi)->events & (EPOLLIN | EPOLLOUT)))
|
||||
sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
|
||||
SD_EVENT_ONESHOT);
|
||||
else
|
||||
sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
|
||||
SD_EVENT_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
init_vhost_listen_wsi_sd(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt;
|
||||
|
||||
if (!wsi)
|
||||
return 0;
|
||||
|
||||
pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
|
||||
sd_event_add_io(pt_to_priv_sd(pt)->io_loop,
|
||||
&wsi_to_priv_sd(wsi)->source,
|
||||
wsi->desc.sockfd,
|
||||
wsi_to_priv_sd(wsi)->events,
|
||||
sock_accept_handler,
|
||||
wsi);
|
||||
|
||||
io_sd(wsi, LWS_EV_START | LWS_EV_READ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_init_sdevent(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
|
||||
if (init_vhost_listen_wsi_sd(wsi) == -1)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
init_pt_sd(struct lws_context *context, void *_loop, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt);
|
||||
struct sd_event *loop = (struct sd_event *)_loop;
|
||||
int first = 1; /* first to create and initialize the loop */
|
||||
|
||||
ptpriv->pt = pt;
|
||||
|
||||
/* make sure we have an event loop */
|
||||
if (!ptpriv->io_loop) {
|
||||
if (!loop) {
|
||||
if (sd_event_default(&loop) < 0) {
|
||||
lwsl_cx_err(context, "sd_event_default failed");
|
||||
|
||||
return -1;
|
||||
}
|
||||
pt->event_loop_foreign = 0;
|
||||
} else {
|
||||
sd_event_ref(loop);
|
||||
pt->event_loop_foreign = 1;
|
||||
}
|
||||
|
||||
ptpriv->io_loop = loop;
|
||||
} else
|
||||
/*
|
||||
* If the loop was initialized before, we do not need to
|
||||
* do full initialization
|
||||
*/
|
||||
first = 0;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_sdevent);
|
||||
|
||||
if (first) {
|
||||
|
||||
if (0 > sd_event_add_time(loop,
|
||||
&ptpriv->sultimer,
|
||||
CLOCK_MONOTONIC,
|
||||
UINT64_MAX,
|
||||
0,
|
||||
sultimer_handler,
|
||||
(void*) pt
|
||||
))
|
||||
return -1;
|
||||
|
||||
if (0 > sd_event_add_time(loop,
|
||||
&ptpriv->idletimer,
|
||||
CLOCK_MONOTONIC,
|
||||
0,
|
||||
0,
|
||||
idle_handler,
|
||||
(void *)pt))
|
||||
return -1;
|
||||
|
||||
sd_event_source_set_enabled(ptpriv->idletimer, SD_EVENT_ON);
|
||||
|
||||
if (0 > sd_event_source_set_priority(ptpriv->idletimer,
|
||||
SD_EVENT_PRIORITY_IDLE))
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
wsi_destroy_sd(struct lws *wsi)
|
||||
{
|
||||
if (!wsi)
|
||||
return;
|
||||
|
||||
io_sd(wsi, LWS_EV_STOP | (LWS_EV_READ | LWS_EV_WRITE));
|
||||
|
||||
if (wsi_to_priv_sd(wsi)->source) {
|
||||
sd_event_source_set_enabled(wsi_to_priv_sd(wsi)->source,
|
||||
SD_EVENT_OFF);
|
||||
sd_event_source_unref(wsi_to_priv_sd(wsi)->source);
|
||||
wsi_to_priv_sd(wsi)->source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
wsi_logical_close_sd(struct lws *wsi)
|
||||
{
|
||||
wsi_destroy_sd(wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sock_accept_sd(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
|
||||
|
||||
if (wsi->role_ops->file_handle)
|
||||
sd_event_add_io(pt_to_priv_sd(pt)->io_loop,
|
||||
&wsi_to_priv_sd(wsi)->source,
|
||||
wsi->desc.filefd,
|
||||
wsi_to_priv_sd(wsi)->events,
|
||||
sock_accept_handler,
|
||||
wsi);
|
||||
else
|
||||
sd_event_add_io(pt_to_priv_sd(pt)->io_loop,
|
||||
&wsi_to_priv_sd(wsi)->source,
|
||||
wsi->desc.sockfd,
|
||||
wsi_to_priv_sd(wsi)->events,
|
||||
sock_accept_handler,
|
||||
wsi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
run_pt_sd(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt);
|
||||
|
||||
if (ptpriv->io_loop)
|
||||
sd_event_run(ptpriv->io_loop, (uint64_t) -1);
|
||||
}
|
||||
|
||||
static int
|
||||
elops_listen_destroy_sdevent(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
|
||||
wsi_logical_close_sd(wsi);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_pt_sd(struct lws_context *context, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_pt_eventlibs_sdevent *ptpriv = pt_to_priv_sd(pt);
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_sdevent);
|
||||
|
||||
if (ptpriv->sultimer) {
|
||||
sd_event_source_set_enabled(ptpriv->sultimer,
|
||||
SD_EVENT_OFF);
|
||||
sd_event_source_unref(ptpriv->sultimer);
|
||||
ptpriv->sultimer = NULL;
|
||||
}
|
||||
|
||||
if (ptpriv->idletimer) {
|
||||
sd_event_source_set_enabled(ptpriv->idletimer,
|
||||
SD_EVENT_OFF);
|
||||
sd_event_source_unref(ptpriv->idletimer);
|
||||
ptpriv->idletimer = NULL;
|
||||
}
|
||||
|
||||
if (ptpriv->io_loop) {
|
||||
sd_event_unref(ptpriv->io_loop);
|
||||
ptpriv->io_loop = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct lws_event_loop_ops event_loop_ops_sdevent = {
|
||||
.name = "sdevent",
|
||||
.init_context = NULL,
|
||||
.destroy_context1 = NULL,
|
||||
.destroy_context2 = NULL,
|
||||
.init_vhost_listen_wsi = init_vhost_listen_wsi_sd,
|
||||
.init_pt = init_pt_sd,
|
||||
.wsi_logical_close = wsi_logical_close_sd,
|
||||
.check_client_connect_ok = NULL,
|
||||
.close_handle_manually = NULL,
|
||||
.sock_accept = sock_accept_sd,
|
||||
.io = io_sd,
|
||||
.run_pt = run_pt_sd,
|
||||
.destroy_pt = destroy_pt_sd,
|
||||
.destroy_wsi = wsi_destroy_sd,
|
||||
|
||||
.flags = 0,
|
||||
|
||||
.evlib_size_ctx = 0,
|
||||
.evlib_size_pt = sizeof(struct lws_pt_eventlibs_sdevent),
|
||||
.evlib_size_vh = 0,
|
||||
.evlib_size_wsi = sizeof(struct lws_wsi_watcher_sdevent),
|
||||
};
|
||||
|
||||
#if defined(LWS_WITH_EVLIB_PLUGINS)
|
||||
LWS_VISIBLE
|
||||
#endif
|
||||
const lws_plugin_evlib_t evlib_sd = {
|
||||
.hdr = {
|
||||
"systemd event loop",
|
||||
"lws_evlib_plugin",
|
||||
LWS_BUILD_HASH,
|
||||
LWS_PLUGIN_API_MAGIC
|
||||
},
|
||||
|
||||
.ops = &event_loop_ops_sdevent
|
||||
};
|
72
Kinc/Sources/kinc/libs/event-libs/uloop/CMakeLists.txt
Normal file
72
Kinc/Sources/kinc/libs/event-libs/uloop/CMakeLists.txt
Normal file
@ -0,0 +1,72 @@
|
||||
#
|
||||
# libwebsockets - small server side websockets and web server implementation
|
||||
#
|
||||
# Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
#
|
||||
# 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()
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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 <libubox/uloop.h>
|
||||
|
||||
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;
|
||||
};
|
326
Kinc/Sources/kinc/libs/event-libs/uloop/uloop.c
Normal file
326
Kinc/Sources/kinc/libs/event-libs/uloop/uloop.c
Normal file
@ -0,0 +1,326 @@
|
||||
/*
|
||||
* libwebsockets - small server side websockets and web server implementation
|
||||
*
|
||||
* Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* 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_cx_notice(context, "pt destroy self coming true");
|
||||
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_listen_init_uloop(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
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;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
elops_init_pt_uloop(struct lws_context *context, void *v, int tsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &context->pt[tsi];
|
||||
struct lws_pt_eventlibs_uloop *ptpr = pt_to_priv_uloop(pt);
|
||||
|
||||
ptpr->pt = pt;
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_init_uloop);
|
||||
|
||||
/* 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 int
|
||||
elops_listen_destroy_uloop(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
#if defined(LWS_WITH_SERVER)
|
||||
struct lws *wsi = lws_container_of(d, struct lws, listen_list);
|
||||
struct lws_wsi_eventlibs_uloop *wu = wsi_to_priv_uloop(wsi);
|
||||
|
||||
uloop_fd_delete(&wu->fd);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
lws_vhost_foreach_listen_wsi(context, NULL, elops_listen_destroy_uloop);
|
||||
|
||||
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,
|
||||
/* foreign_thread */ NULL,
|
||||
/* fake_POLLIN */ NULL,
|
||||
|
||||
/* 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
|
||||
};
|
Reference in New Issue
Block a user