refactor: apply ops structs to event loop handlers

This commit is contained in:
Andy Green 2018-04-29 10:44:36 +08:00
parent d05b408cde
commit d37b383edc
38 changed files with 1470 additions and 1147 deletions

10
.gitignore vendored
View file

@ -1,4 +1,12 @@
#Ignore build files
CMakeCache.txt
CMakeFiles
build
cmake_install.cmake
lws-minimal*
Makefile
.cproject
.project
config.h
config.log
config.status
@ -38,4 +46,4 @@ ar-lib
libwebsockets.pc
build/
*.swp
doc
doc

View file

@ -11,6 +11,7 @@ if(WIN32)
endif()
set(LWS_ROLE_RAW 1)
set(LWS_WITH_POLL 1)
#
# Select features recommended for PC distro packaging
@ -947,9 +948,9 @@ if (LWS_WITH_HTTP_PROXY)
lib/roles/http/server/rewrite.c)
endif()
if (LWS_WITH_LIBEV)
if (LWS_WITH_POLL)
list(APPEND SOURCES
lib/event-libs/libev/libev.c)
lib/event-libs/poll/poll.c)
endif()
if (LWS_WITH_LIBUV)
@ -962,6 +963,11 @@ if (LWS_WITH_LIBEVENT)
lib/event-libs/libevent/libevent.c)
endif()
if (LWS_WITH_LIBEV)
list(APPEND SOURCES
lib/event-libs/libev/libev.c)
endif()
if (LWS_WITH_LEJP)
list(APPEND SOURCES
lib/misc/lejp.c)

View file

@ -817,7 +817,7 @@ lws_create_vhost(struct lws_context *context,
goto bail1;
}
lws_context_lock(context);
n = _lws_context_init_server(info, vh);
n = _lws_vhost_init_server(info, vh);
lws_context_unlock(context);
if (n < 0) {
lwsl_err("init server failed\n");
@ -926,26 +926,34 @@ lws_create_event_pipes(struct lws_context *context)
context->pt[n].pipe_wsi = wsi;
lws_libuv_accept(wsi, wsi->desc);
lws_libev_accept(wsi, wsi->desc);
lws_libevent_accept(wsi, wsi->desc);
if (context->event_loop_ops->accept)
context->event_loop_ops->accept(wsi);
if (__insert_wsi_socket_into_fds(context, wsi))
return 1;
lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
//lws_change_pollfd(context->pt[n].pipe_wsi, 0, LWS_POLLIN);
context->count_wsi_allocated++;
}
return 0;
}
static void
void
lws_destroy_event_pipe(struct lws *wsi)
{
lws_plat_pipe_close(wsi);
lwsl_info("%s\n", __func__);
__remove_wsi_socket_from_fds(wsi);
lws_libevent_destroy(wsi);
if (wsi->context->event_loop_ops->wsi_logical_close) {
wsi->context->event_loop_ops->wsi_logical_close(wsi);
lws_plat_pipe_close(wsi);
return;
}
if (wsi->context->event_loop_ops->destroy_wsi)
wsi->context->event_loop_ops->destroy_wsi(wsi);
lws_plat_pipe_close(wsi);
wsi->context->count_wsi_allocated--;
lws_free(wsi);
}
@ -1056,6 +1064,7 @@ lws_create_context(const struct lws_context_creation_info *info)
info->external_baggage_free_on_destroy;
context->time_up = time(NULL);
context->pcontext_finalize = info->pcontext;
context->simultaneous_ssl_restriction =
info->simultaneous_ssl_restriction;
@ -1089,6 +1098,40 @@ lws_create_context(const struct lws_context_creation_info *info)
context->options = info->options;
/*
* set the context event loops ops struct
*
* after this, all event_loop actions use the generic ops
*/
#if defined(LWS_WITH_POLL)
context->event_loop_ops = &event_loop_ops_poll;
#endif
#if defined(LWS_WITH_LIBUV)
if (LWS_LIBUV_ENABLED(context)) {
context->event_loop_ops = &event_loop_ops_uv;
}
#endif
#if defined(LWS_WITH_LIBEV)
if (LWS_LIBEV_ENABLED(context)) {
context->event_loop_ops = &event_loop_ops_ev;
}
#endif
#if defined(LWS_WITH_LIBEVENT)
if (LWS_LIBEVENT_ENABLED(context)) {
context->event_loop_ops = &event_loop_ops_event;
}
#endif
if (!context->event_loop_ops) {
lwsl_err("no event loop possible\n");
goto bail;
}
lwsl_info("Using event loop: %s\n", context->event_loop_ops->name);
#if defined(LWS_WITH_TLS)
if (info->alpn)
context->alpn_default = info->alpn;
@ -1135,6 +1178,12 @@ lws_create_context(const struct lws_context_creation_info *info)
else
context->max_http_header_pool = context->max_fds;
if (info->fd_limit_per_thread)
context->fd_limit_per_thread = info->fd_limit_per_thread;
else
context->fd_limit_per_thread = context->max_fds /
context->count_threads;
/*
* Allocate the per-thread storage for scratchpad buffers,
* and header data pool
@ -1147,10 +1196,9 @@ lws_create_context(const struct lws_context_creation_info *info)
return NULL;
}
#ifdef LWS_WITH_LIBUV
context->pt[n].context = context;
#endif
context->pt[n].tid = n;
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
context->pt[n].http.ah_list = NULL;
context->pt[n].http.ah_pool_length = 0;
@ -1158,12 +1206,6 @@ lws_create_context(const struct lws_context_creation_info *info)
lws_pt_mutex_init(&context->pt[n]);
}
if (info->fd_limit_per_thread)
context->fd_limit_per_thread = info->fd_limit_per_thread;
else
context->fd_limit_per_thread = context->max_fds /
context->count_threads;
lwsl_info(" Threads: %d each %d fds\n", context->count_threads,
context->fd_limit_per_thread);
@ -1172,24 +1214,6 @@ lws_create_context(const struct lws_context_creation_info *info)
return NULL;
}
#ifdef LWS_WITH_LIBEV
if (LWS_LIBEV_ENABLED(context)) {
context->use_event_loop_sigint = 1;
context->ev.sigint_cb = &lws_ev_sigint_cb;
}
#endif /* LWS_WITH_LIBEV */
#ifdef LWS_WITH_LIBUV
if (LWS_LIBUV_ENABLED(context)) {
context->use_event_loop_sigint = 1;
context->uv.sigint_cb = &lws_uv_sigint_cb;
}
#endif
#ifdef LWS_WITH_LIBEVENT
if (LWS_LIBEVENT_ENABLED(context)) {
context->use_event_loop_sigint = 1;
context->event.sigint_cb = &lws_event_sigint_cb;
}
#endif /* LWS_WITH_LIBEVENT */
#if defined(LWS_WITH_PEER_LIMITS)
/* scale the peer hash table according to the max fds for the process,
@ -1245,6 +1269,25 @@ lws_create_context(const struct lws_context_creation_info *info)
if (lws_plat_init(context, info))
goto bail;
if (context->event_loop_ops->init_context)
if (context->event_loop_ops->init_context(context, info))
goto bail;
if (context->event_loop_ops->init_pt)
for (n = 0; n < context->count_threads; n++) {
void *lp = NULL;
if (info->foreign_loops)
lp = info->foreign_loops[n];
if (context->event_loop_ops->init_pt(context, lp, n))
goto bail;
}
if (lws_create_event_pipes(context))
goto bail;
lws_context_init_ssl_library(info);
context->user_space = info->user;
@ -1283,16 +1326,6 @@ lws_create_context(const struct lws_context_creation_info *info)
context->count_caps = info->count_caps;
#endif
/*
* The event libs handle doing this when their event loop starts,
* if we are using the default poll() service, do it here
*/
if (!LWS_LIBEV_ENABLED(context) &&
!LWS_LIBUV_ENABLED(context) &&
!LWS_LIBEVENT_ENABLED(context) && lws_create_event_pipes(context))
goto bail;
/*
* drop any root privs for this process
* to listen on port < 1023 we would have needed root, but now we are
@ -1365,10 +1398,6 @@ lws_context_is_deprecated(struct lws_context *context)
return context->deprecated;
}
LWS_VISIBLE void
lws_context_destroy2(struct lws_context *context);
void
lws_vhost_destroy1(struct lws_vhost *vh)
{
@ -1540,16 +1569,10 @@ lws_vhost_destroy2(struct lws_vhost *vh)
lws_free(vh->protocol_vh_privs);
lws_ssl_SSL_CTX_destroy(vh);
lws_free(vh->same_vh_protocol_list);
#ifdef LWS_WITH_PLUGINS
if (LWS_LIBUV_ENABLED(context)) {
if (context->plugin_list)
lws_free((void *)vh->protocols);
} else
#endif
{
if (context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS)
lws_free((void *)vh->protocols);
}
if (context->plugin_list ||
(context->options & LWS_SERVER_OPTION_EXPLICIT_VHOSTS))
lws_free((void *)vh->protocols);
LWS_FOR_EVERY_AVAILABLE_ROLE_START(ar)
if (ar->destroy_vhost)
@ -1628,6 +1651,106 @@ lws_vhost_destroy(struct lws_vhost *vh)
vh->context->deferred_free_list = df;
}
/*
* When using an event loop, the context destruction is in three separate
* parts. This is to cover both internal and foreign event loops cleanly.
*
* - lws_context_destroy() simply starts a soft close of all wsi and
* related allocations. The event loop continues.
*
* As the closes complete in the event loop, reference counting is used
* to determine when everything is closed. It then calls
* lws_context_destroy2().
*
* - lws_context_destroy2() cleans up the rest of the higher-level logical
* lws pieces like vhosts. If the loop was foreign, it then proceeds to
* lws_context_destroy3(). If it the loop is internal, it stops the
* internal loops and waits for lws_context_destroy() to be called again
* outside the event loop (since we cannot destroy the loop from
* within the loop). That will cause lws_context_destroy3() to run
* directly.
*
* - lws_context_destroy3() destroys any internal event loops and then
* destroys the context itself, setting what was info.pcontext to NULL.
*/
static void
lws_context_destroy3(struct lws_context *context)
{
struct lws_context **pcontext_finalize = context->pcontext_finalize;
lws_free(context);
lwsl_info("%s: ctx %p freed\n", __func__, context);
if (pcontext_finalize)
*pcontext_finalize = NULL;
}
void
lws_context_destroy2(struct lws_context *context)
{
struct lws_vhost *vh = NULL, *vh1;
#if defined(LWS_WITH_PEER_LIMITS)
uint32_t n;
#endif
lwsl_info("%s: ctx %p\n", __func__, context);
/*
* free all the per-vhost allocations
*/
vh = context->vhost_list;
while (vh) {
vh1 = vh->vhost_next;
lws_vhost_destroy2(vh);
vh = vh1;
}
/* remove ourselves from the pending destruction list */
while (context->vhost_pending_destruction_list)
/* removes itself from list */
lws_vhost_destroy2(context->vhost_pending_destruction_list);
lws_stats_log_dump(context);
lws_ssl_context_destroy(context);
lws_plat_context_late_destroy(context);
#if defined(LWS_WITH_PEER_LIMITS)
for (n = 0; n < context->pl_hash_elements; n++) {
lws_start_foreach_llp(struct lws_peer **, peer,
context->pl_hash_table[n]) {
struct lws_peer *df = *peer;
*peer = df->next;
lws_free(df);
continue;
} lws_end_foreach_llp(peer, next);
}
lws_free(context->pl_hash_table);
#endif
if (context->external_baggage_free_on_destroy)
free(context->external_baggage_free_on_destroy);
lws_check_deferred_free(context, 1);
#if LWS_MAX_SMP > 1
pthread_mutex_destroy(&context->lock);
#endif
if (context->event_loop_ops->destroy_context2)
if (context->event_loop_ops->destroy_context2(context)) {
context->finalize_destroy_after_internal_loops_stopped = 1;
return;
}
lws_context_destroy3(context);
}
LWS_VISIBLE void
lws_context_destroy(struct lws_context *context)
{
@ -1642,8 +1765,18 @@ lws_context_destroy(struct lws_context *context)
lwsl_notice("%s: ctx %p\n", __func__, context);
return;
}
if (context->finalize_destroy_after_internal_loops_stopped) {
if (context->event_loop_ops->destroy_context2)
context->event_loop_ops->destroy_context2(context);
lws_context_destroy3(context);
return;
}
if (context->being_destroyed1) {
lwsl_notice("%s: ctx %p: already being destroyed\n",
lwsl_info("%s: ctx %p: already being destroyed\n",
__func__, context);
return;
}
@ -1653,6 +1786,7 @@ lws_context_destroy(struct lws_context *context)
m = context->count_threads;
context->being_destroyed = 1;
context->being_destroyed1 = 1;
context->requested_kill = 1;
memset(&wsi, 0, sizeof(wsi));
wsi.context = context;
@ -1708,9 +1842,8 @@ lws_context_destroy(struct lws_context *context)
for (n = 0; n < context->count_threads; n++) {
pt = &context->pt[n];
lws_libev_destroyloop(context, n);
lws_libuv_destroyloop(context, n);
lws_libevent_destroyloop(context, n);
if (context->event_loop_ops->destroy_pt)
context->event_loop_ops->destroy_pt(context, n);
lws_free_set_NULL(context->pt[n].serv_buf);
@ -1721,84 +1854,14 @@ lws_context_destroy(struct lws_context *context)
}
lws_plat_context_early_destroy(context);
#if defined(LWS_WITH_LIBUV)
if (LWS_LIBUV_ENABLED(context))
for (n = 0; n < context->count_threads; n++) {
pt = &context->pt[n];
if (!pt->event_loop_foreign) {
#if UV_VERSION_MAJOR > 0
uv_loop_close(pt->uv.io_loop);
#endif
lws_free_set_NULL(pt->uv.io_loop);
}
}
#endif
if (context->pt[0].fds)
lws_free_set_NULL(context->pt[0].fds);
if (!LWS_LIBUV_ENABLED(context))
lws_context_destroy2(context);
}
if (context->event_loop_ops->destroy_context1) {
context->event_loop_ops->destroy_context1(context);
/*
* call the second one after the event loop has been shut down cleanly
*/
LWS_VISIBLE void
lws_context_destroy2(struct lws_context *context)
{
struct lws_vhost *vh = NULL, *vh1;
#if defined(LWS_WITH_PEER_LIMITS)
uint32_t n;
#endif
lwsl_info("%s: ctx %p\n", __func__, context);
/*
* free all the per-vhost allocations
*/
vh = context->vhost_list;
while (vh) {
vh1 = vh->vhost_next;
lws_vhost_destroy2(vh);
vh = vh1;
return;
}
/* remove ourselves from the pending destruction list */
while (context->vhost_pending_destruction_list)
/* removes itself from list */
lws_vhost_destroy2(context->vhost_pending_destruction_list);
lws_stats_log_dump(context);
lws_ssl_context_destroy(context);
lws_plat_context_late_destroy(context);
#if defined(LWS_WITH_PEER_LIMITS)
for (n = 0; n < context->pl_hash_elements; n++) {
lws_start_foreach_llp(struct lws_peer **, peer,
context->pl_hash_table[n]) {
struct lws_peer *df = *peer;
*peer = df->next;
lws_free(df);
continue;
} lws_end_foreach_llp(peer, next);
}
lws_free(context->pl_hash_table);
#endif
if (context->external_baggage_free_on_destroy)
free(context->external_baggage_free_on_destroy);
lws_check_deferred_free(context, 1);
#if LWS_MAX_SMP > 1
pthread_mutex_destroy(&context->lock);
#endif
lws_free(context);
lws_context_destroy2(context);
}

View file

@ -61,28 +61,23 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
LWS_VISIBLE 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);
}
LWS_VISIBLE int
lws_ev_sigint_cfg(struct lws_context *context, int use_event_loop_sigint,
lws_ev_signal_cb_t *cb)
{
context->use_event_loop_sigint = use_event_loop_sigint;
if (cb)
context->ev.sigint_cb = cb;
else
context->ev.sigint_cb = &lws_ev_sigint_cb;
return 0;
}
LWS_VISIBLE int
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
static int
elops_init_pt_ev(struct lws_context *context, void *_loop, int tsi)
{
struct ev_signal *w_sigint = &context->pt[tsi].w_sigint.ev.watcher;
struct lws_vhost *vh = context->vhost_list;
const char *backend_name;
struct ev_loop *loop = (struct ev_loop *)_loop;
int status = 0;
int backend;
@ -93,9 +88,6 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
context->pt[tsi].ev.io_loop = loop;
if (lws_create_event_pipes(context))
return -1;
/*
* Initialize the accept w_accept with all the listening sockets
* and register a callback for read operations
@ -113,9 +105,10 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
vh = vh->vhost_next;
}
/* Register the signal watcher unless the user says not to */
if (context->use_event_loop_sigint) {
ev_signal_init(w_sigint, context->ev.sigint_cb, SIGINT);
/* 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);
}
@ -150,8 +143,8 @@ lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi)
return status;
}
void
lws_libev_destroyloop(struct lws_context *context, int tsi)
static void
elops_destroy_pt_ev(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
@ -167,44 +160,50 @@ lws_libev_destroyloop(struct lws_context *context, int tsi)
ev_io_stop(pt->ev.io_loop, &vh->w_accept.ev.watcher);
vh = vh->vhost_next;
}
if (context->use_event_loop_sigint)
ev_signal_stop(pt->ev.io_loop,
&pt->w_sigint.ev.watcher);
if (!pt->event_loop_foreign)
ev_signal_stop(pt->ev.io_loop, &pt->w_sigint.ev.watcher);
if (!pt->event_loop_foreign)
ev_loop_destroy(pt->ev.io_loop);
}
LWS_VISIBLE void
lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
static int
elops_init_context_ev(struct lws_context *context,
const struct lws_context_creation_info *info)
{
struct lws_context *context = lws_get_context(new_wsi);
struct ev_io *r = &new_wsi->w_read.ev.watcher;
struct ev_io *w = &new_wsi->w_write.ev.watcher;
int n;
context->eventlib_signal_cb = info->signal_cb;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
return 0;
}
static void
elops_accept_ev(struct lws *wsi)
{
struct lws_context *context = lws_get_context(wsi);
struct ev_io *r = &wsi->w_read.ev.watcher;
struct ev_io *w = &wsi->w_write.ev.watcher;
int fd;
if (!LWS_LIBEV_ENABLED(context))
return;
if (new_wsi->role_ops == &role_ops_raw_file)
fd = desc.filefd;
if (wsi->role_ops->file_handle)
fd = wsi->desc.filefd;
else
fd = desc.sockfd;
fd = wsi->desc.sockfd;
new_wsi->w_read.context = context;
new_wsi->w_write.context = context;
wsi->w_read.context = context;
wsi->w_write.context = context;
ev_io_init(r, lws_accept_cb, fd, EV_READ);
ev_io_init(w, lws_accept_cb, fd, EV_WRITE);
}
LWS_VISIBLE void
lws_libev_io(struct lws *wsi, int flags)
static void
elops_io_ev(struct lws *wsi, int flags)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
if (!LWS_LIBEV_ENABLED(context))
return;
if (!pt->ev.io_loop)
return;
@ -224,23 +223,28 @@ lws_libev_io(struct lws *wsi, int flags)
}
}
LWS_VISIBLE int
lws_libev_init_fd_table(struct lws_context *context)
{
int n;
if (!LWS_LIBEV_ENABLED(context))
return 0;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
return 1;
}
LWS_VISIBLE void
lws_libev_run(const struct lws_context *context, int tsi)
static void
elops_run_pt_ev(struct lws_context *context, int tsi)
{
if (context->pt[tsi].ev.io_loop && LWS_LIBEV_ENABLED(context))
ev_run(context->pt[tsi].ev.io_loop, 0);
}
struct lws_event_loop_ops event_loop_ops_ev = {
/* name */ "libev",
/* init_context */ elops_init_context_ev,
/* destroy_context1 */ NULL,
/* destroy_context2 */ NULL,
/* init_vhost_listen_wsi */ NULL,
/* init_pt */ elops_init_pt_ev,
/* wsi_logical_close */ NULL,
/* 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 */ NULL,
/* periodic_events_available */ 0,
};

View file

@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* This is included from private-libwebsockets.h if LWS_ROLE_WS
* This is included from private-libwebsockets.h if LWS_WITH_LIBEV
*/
#include <ev.h>
@ -36,18 +36,15 @@ struct lws_signal_watcher_libev {
};
struct lws_context_eventlibs_libev {
lws_ev_signal_cb_t *sigint_cb;
int placeholder;
};
LWS_EXTERN void
lws_libev_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
LWS_EXTERN void
lws_libev_io(struct lws *wsi, int flags);
LWS_EXTERN int
lws_libev_init_fd_table(struct lws_context *context);
LWS_EXTERN void
lws_libev_destroyloop(struct lws_context *context, int tsi);
#define LWS_LIBEV_ENABLED(context) lws_check_opt(context->options, \
LWS_SERVER_OPTION_LIBEV)
extern struct lws_event_loop_ops event_loop_ops_ev;
LWS_EXTERN void
lws_libev_run(const struct lws_context *context, int tsi);
#define LWS_LIBEV_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEV)
LWS_EXTERN void lws_feature_status_libev(const struct lws_context_creation_info *info);
LWS_EXTERN void
lws_feature_status_libev(const struct lws_context_creation_info *info);

View file

@ -68,28 +68,22 @@ lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
{
struct lws_context_per_thread *pt = ctx;
if (pt->context->eventlib_signal_cb) {
pt->context->eventlib_signal_cb(
(void *)(lws_intptr_t)sock_fd, revents);
return;
}
if (!pt->event_loop_foreign)
event_base_loopbreak(pt->event.io_loop);
}
LWS_VISIBLE int
lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
lws_event_signal_cb_t *cb)
{
context->use_event_loop_sigint = use_event_sigint;
if (cb)
context->event.sigint_cb = cb;
else
context->event.sigint_cb = &lws_event_sigint_cb;
return 0;
}
LWS_VISIBLE int
lws_event_initloop(struct lws_context *context, struct event_base *loop,
int tsi)
static int
elops_init_pt_event(struct lws_context *context, void *_loop, int tsi)
{
struct lws_vhost *vh = context->vhost_list;
struct event_base *loop = (struct event_base *)_loop;
if (!loop)
context->pt[tsi].event.io_loop = event_base_new();
@ -98,9 +92,6 @@ int tsi)
context->pt[tsi].event.io_loop = loop;
}
if (lws_create_event_pipes(context))
return 1;
/*
* Initialize all events with the listening sockets
* and register a callback for read operations
@ -118,95 +109,61 @@ int tsi)
vh = vh->vhost_next;
}
/* Register the signal watcher unless the user says not to */
if (!context->use_event_loop_sigint)
/* Register the signal watcher unless it's a foreign loop */
if (context->pt[tsi].event_loop_foreign)
return 0;
context->pt[tsi].w_sigint.event.watcher = evsignal_new(loop, SIGINT,
context->event.sigint_cb, &context->pt[tsi]);
lws_event_sigint_cb, &context->pt[tsi]);
event_add(context->pt[tsi].w_sigint.event.watcher, NULL);
return 0;
}
void
lws_libevent_destroyloop(struct lws_context *context, int tsi)
static int
elops_init_context_event(struct lws_context *context,
const struct lws_context_creation_info *info)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
int n;
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
return;
context->eventlib_signal_cb = info->signal_cb;
if (!pt->event.io_loop)
return;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
/*
* Free all events with the listening sockets
*/
while (vh) {
if (vh->lserv_wsi) {
event_free(vh->lserv_wsi->w_read.event.watcher);
vh->lserv_wsi->w_read.event.watcher = NULL;
}
vh = vh->vhost_next;
}
if (context->use_event_loop_sigint)
event_free(pt->w_sigint.event.watcher);
if (!pt->event_loop_foreign)
event_base_free(pt->event.io_loop);
return 0;
}
LWS_VISIBLE void
lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc)
static void
elops_accept_event(struct lws *wsi)
{
struct lws_context *context = lws_get_context(new_wsi);
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt;
int fd;
if (!LWS_LIBEVENT_ENABLED(context))
return;
new_wsi->w_read.context = context;
new_wsi->w_write.context = context;
wsi->w_read.context = context;
wsi->w_write.context = context;
// Initialize the event
pt = &context->pt[(int)new_wsi->tsi];
pt = &context->pt[(int)wsi->tsi];
if (new_wsi->role_ops == &role_ops_raw_file)
fd = desc.filefd;
if (wsi->role_ops->file_handle)
fd = wsi->desc.filefd;
else
fd = desc.sockfd;
fd = wsi->desc.sockfd;
new_wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd,
(EV_READ | EV_PERSIST), lws_event_cb, &new_wsi->w_read);
new_wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd,
(EV_WRITE | EV_PERSIST), lws_event_cb, &new_wsi->w_write);
wsi->w_read.event.watcher = event_new(pt->event.io_loop, fd,
(EV_READ | EV_PERSIST), lws_event_cb, &wsi->w_read);
wsi->w_write.event.watcher = event_new(pt->event.io_loop, fd,
(EV_WRITE | EV_PERSIST), lws_event_cb, &wsi->w_write);
}
LWS_VISIBLE void
lws_libevent_destroy(struct lws *wsi)
{
if (!wsi)
return;
if(wsi->w_read.event.watcher)
event_free(wsi->w_read.event.watcher);
if(wsi->w_write.event.watcher)
event_free(wsi->w_write.event.watcher);
}
LWS_VISIBLE void
lws_libevent_io(struct lws *wsi, int flags)
static void
elops_io_event(struct lws *wsi, int flags)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
if (!LWS_LIBEVENT_ENABLED(context))
return;
if (!pt->event.io_loop || context->being_destroyed)
return;
@ -227,25 +184,73 @@ lws_libevent_io(struct lws *wsi, int flags)
}
}
LWS_VISIBLE int
lws_libevent_init_fd_table(struct lws_context *context)
{
int n;
if (!LWS_LIBEVENT_ENABLED(context))
return 0;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
return 1;
}
LWS_VISIBLE void
lws_libevent_run(const struct lws_context *context, int tsi)
static void
elops_run_pt_event(struct lws_context *context, int tsi)
{
/* Run / Dispatch the event_base loop */
if (context->pt[tsi].event.io_loop &&
LWS_LIBEVENT_ENABLED(context))
event_base_dispatch(context->pt[tsi].event.io_loop);
}
static void
elops_destroy_pt_event(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
return;
if (!pt->event.io_loop)
return;
/*
* Free all events with the listening sockets
*/
while (vh) {
if (vh->lserv_wsi) {
event_free(vh->lserv_wsi->w_read.event.watcher);
vh->lserv_wsi->w_read.event.watcher = NULL;
}
vh = vh->vhost_next;
}
if (!pt->event_loop_foreign)
event_free(pt->w_sigint.event.watcher);
if (!pt->event_loop_foreign)
event_base_free(pt->event.io_loop);
}
static void
elops_destroy_wsi_event(struct lws *wsi)
{
if (!wsi)
return;
if(wsi->w_read.event.watcher)
event_free(wsi->w_read.event.watcher);
if(wsi->w_write.event.watcher)
event_free(wsi->w_write.event.watcher);
}
struct lws_event_loop_ops event_loop_ops_event = {
/* name */ "libevent",
/* init_context */ elops_init_context_event,
/* destroy_context1 */ NULL,
/* destroy_context2 */ NULL,
/* init_vhost_listen_wsi */ NULL,
/* init_pt */ elops_init_pt_event,
/* wsi_logical_close */ NULL,
/* 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,
/* periodic_events_available */ 0,
};

View file

@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* This is included from private-libwebsockets.h if LWS_ROLE_WS
* This is included from private-libwebsockets.h if LWS_WITH_LIBEVENT
*/
#include <event2/event.h>
@ -36,25 +36,14 @@ struct lws_signal_watcher_libevent {
};
struct lws_context_eventlibs_libevent {
#if defined(LWS_HIDE_LIBEVENT)
void * sigint_cb;
#else
lws_event_signal_cb_t *sigint_cb;
#endif
int placeholder;
};
LWS_EXTERN void
lws_libevent_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
LWS_VISIBLE void
lws_libevent_destroy(struct lws *wsi);
LWS_EXTERN void
lws_libevent_io(struct lws *wsi, int flags);
LWS_EXTERN int
lws_libevent_init_fd_table(struct lws_context *context);
LWS_EXTERN void
lws_libevent_destroyloop(struct lws_context *context, int tsi);
LWS_EXTERN void
lws_libevent_run(const struct lws_context *context, int tsi);
#define LWS_LIBEVENT_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT)
LWS_EXTERN void lws_feature_status_libevent(const struct lws_context_creation_info *info);
#define LWS_LIBEVENT_ENABLED(context) lws_check_opt(context->options, \
LWS_SERVER_OPTION_LIBEVENT)
extern struct lws_event_loop_ops event_loop_ops_event;
LWS_EXTERN void
lws_feature_status_libevent(const struct lws_context_creation_info *info);

View file

@ -134,24 +134,73 @@ lws_io_cb(uv_poll_t *watcher, int status, int revents)
uv_idle_start(&pt->uv.idle, lws_uv_idle);
}
LWS_VISIBLE void
lws_uv_sigint_cb(uv_signal_t *watcher, int signum)
/*
* 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.
*/
LWS_VISIBLE LWS_EXTERN void
lws_libuv_stop(struct lws_context *context)
{
lwsl_err("internal signal handler caught signal %d\n", signum);
lws_libuv_stop(watcher->data);
struct lws_context_per_thread *pt;
int n, m;
lwsl_err("%s\n", __func__);
if (context->requested_kill) {
lwsl_err("%s: ignoring\n", __func__);
return;
}
context->requested_kill = 1;
m = context->count_threads;
context->being_destroyed = 1;
/*
* Phase 1: start the close of every dynamic uv handle
*/
while (m--) {
pt = &context->pt[m];
if (pt->pipe_wsi) {
uv_poll_stop(&pt->pipe_wsi->w_read.uv.watcher);
lws_destroy_event_pipe(pt->pipe_wsi);
pt->pipe_wsi = NULL;
}
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
if (!wsi)
continue;
lws_close_free_wsi(wsi,
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY, __func__
/* no protocol close */);
n--;
}
}
lwsl_info("%s: started closing all wsi\n", __func__);
/* we cannot have completed... there are at least the cancel pipes */
}
LWS_VISIBLE int
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
uv_signal_cb cb)
static void
lws_uv_signal_handler(uv_signal_t *watcher, int signum)
{
context->use_event_loop_sigint = use_uv_sigint;
if (cb)
context->uv.sigint_cb = cb;
else
context->uv.sigint_cb = &lws_uv_sigint_cb;
struct lws_context *context = watcher->data;
return 0;
if (context->eventlib_signal_cb) {
context->eventlib_signal_cb((void *)watcher, signum);
return;
}
lwsl_err("internal signal handler caught signal %d\n", signum);
lws_libuv_stop(watcher->data);
}
static void
@ -174,127 +223,6 @@ lws_uv_timeout_cb(uv_timer_t *timer
static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE, SIGHUP };
int
lws_uv_initvhost(struct lws_vhost* vh, struct lws* wsi)
{
struct lws_context_per_thread *pt;
int n;
if (!LWS_LIBUV_ENABLED(vh->context))
return 0;
if (!wsi)
wsi = vh->lserv_wsi;
if (!wsi)
return 0;
if (wsi->w_read.context)
return 0;
pt = &vh->context->pt[(int)wsi->tsi];
if (!pt->uv.io_loop)
return 0;
wsi->w_read.context = vh->context;
n = uv_poll_init_socket(pt->uv.io_loop,
&wsi->w_read.uv.watcher, wsi->desc.sockfd);
if (n) {
lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
n, (void *)(lws_intptr_t)wsi->desc.sockfd);
return -1;
}
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
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
*/
LWS_VISIBLE int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
int status = 0, n, ns, first = 1;
if (!pt->uv.io_loop) {
if (!loop) {
loop = lws_malloc(sizeof(*loop), "libuv loop");
if (!loop) {
lwsl_err("OOM\n");
return -1;
}
#if UV_VERSION_MAJOR > 0
uv_loop_init(loop);
#else
lwsl_err("This libuv is too old to work...\n");
return 1;
#endif
pt->event_loop_foreign = 0;
} else {
lwsl_notice(" Using foreign event loop...\n");
pt->event_loop_foreign = 1;
}
pt->uv.io_loop = loop;
uv_idle_init(loop, &pt->uv.idle);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.idle, context);
ns = ARRAY_SIZE(sigs);
if (lws_check_opt(context->options,
LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
ns = 2;
if (pt->context->use_event_loop_sigint) {
assert(ns <= (int)ARRAY_SIZE(pt->uv.signals));
for (n = 0; n < ns; n++) {
uv_signal_init(loop, &pt->uv.signals[n]);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.signals[n],
context);
pt->uv.signals[n].data = pt->context;
uv_signal_start(&pt->uv.signals[n],
context->uv.sigint_cb, sigs[n]);
}
}
} else
first = 0;
if (lws_create_event_pipes(context))
goto bail;
/*
* 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.
*/
while (vh) {
if (lws_uv_initvhost(vh, vh->lserv_wsi) == -1)
return -1;
vh = vh->vhost_next;
}
if (!first)
return status;
uv_timer_init(pt->uv.io_loop, &pt->uv.timeout_watcher);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.timeout_watcher, context);
uv_timer_start(&pt->uv.timeout_watcher, lws_uv_timeout_cb, 10, 1000);
uv_timer_init(pt->uv.io_loop, &pt->uv.hrtimer);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.hrtimer, context);
return status;
bail:
return -1;
}
/*
* Closing Phase 2: Close callback for a static UV asset
*/
@ -326,17 +254,16 @@ lws_uv_close_cb_sa(uv_handle_t *handle)
for (n = 0; n < context->count_threads; n++) {
struct lws_context_per_thread *pt = &context->pt[n];
if (!pt->uv.io_loop || !LWS_LIBUV_ENABLED(context))
continue;
uv_stop(pt->uv.io_loop);
/*
* we can't delete non-foreign loop here, because
* the uv_stop() hasn't got us out of the uv_run()
* yet. So we do it in context destroy.
*/
if (pt->uv.io_loop && !pt->event_loop_foreign)
uv_stop(pt->uv.io_loop);
}
if (!context->pt[0].event_loop_foreign) {
lwsl_info("%s: calling lws_context_destroy2\n", __func__);
lws_context_destroy2(context);
}
lwsl_info("%s: all done\n", __func__);
}
/*
@ -378,136 +305,6 @@ lws_close_all_handles_in_loop(uv_loop_t *loop)
uv_walk(loop, lws_uv_walk_cb, NULL);
}
void
lws_libuv_destroyloop(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
int m, /* budget = 100, */ ns;
lwsl_info("%s: %d\n", __func__, tsi);
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
return;
if (!pt->uv.io_loop)
return;
if (pt->event_loop_destroy_processing_done)
return;
pt->event_loop_destroy_processing_done = 1;
if (context->use_event_loop_sigint) {
uv_signal_stop(&pt->w_sigint.uv.watcher);
ns = 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->uv.signals[m]);
uv_close((uv_handle_t *)&pt->uv.signals[m],
lws_uv_close_cb_sa);
}
}
uv_timer_stop(&pt->uv.timeout_watcher);
uv_close((uv_handle_t *)&pt->uv.timeout_watcher, lws_uv_close_cb_sa);
uv_timer_stop(&pt->uv.hrtimer);
uv_close((uv_handle_t *)&pt->uv.hrtimer, lws_uv_close_cb_sa);
uv_idle_stop(&pt->uv.idle);
uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
}
void
lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
if (!LWS_LIBUV_ENABLED(context))
return;
wsi->w_read.context = context;
if (wsi->role_ops == &role_ops_raw_file || wsi->event_pipe)
uv_poll_init(pt->uv.io_loop, &wsi->w_read.uv.watcher,
(int)(long long)desc.filefd);
else
uv_poll_init_socket(pt->uv.io_loop, &wsi->w_read.uv.watcher,
desc.sockfd);
}
void
lws_libuv_io(struct lws *wsi, int flags)
{
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
struct lws_io_watcher *w = &wsi->w_read;
int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
if (!LWS_LIBUV_ENABLED(context))
return;
/* w->context is set after the loop is initialized */
if (!pt->uv.io_loop || !w->context) {
lwsl_info("%s: no io loop yet\n", __func__);
return;
}
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
lwsl_err("%s: assert: flags %d", __func__, flags);
assert(0);
}
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->uv.watcher, 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->uv.watcher);
else
uv_poll_start(&w->uv.watcher, current_events,
lws_io_cb);
}
w->actual_events = current_events;
}
int
lws_libuv_init_fd_table(struct lws_context *context)
{
int n;
if (!LWS_LIBUV_ENABLED(context))
return 0;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
return 1;
}
LWS_VISIBLE void
lws_libuv_run(const struct lws_context *context, int tsi)
{
if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
uv_run(context->pt[tsi].uv.io_loop, 0);
}
LWS_VISIBLE void
lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)
@ -527,123 +324,6 @@ lws_uv_getloop(struct lws_context *context, int tsi)
return NULL;
}
static void
lws_libuv_closewsi(uv_handle_t* handle)
{
struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
(char *)(&n->w_read.uv.watcher));
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
int lspd = 0, m;
/*
* We get called back here for every wsi that closes
*/
if (wsi->role_ops == &role_ops_listen && wsi->context->deprecated) {
lspd = 1;
context->deprecation_pending_listen_close_count--;
if (!context->deprecation_pending_listen_close_count)
lspd = 2;
}
lws_pt_lock(pt, __func__);
__lws_close_free_wsi_final(wsi);
lws_pt_unlock(pt);
if (lspd == 2 && context->deprecation_cb) {
lwsl_notice("calling deprecation callback\n");
context->deprecation_cb();
}
lwsl_info("%s: sa left %d: dyn left: %d\n", __func__,
context->count_event_loop_static_asset_handles,
context->count_wsi_allocated);
/*
* eventually, we closed all the wsi...
*/
if (context->requested_kill && !context->count_wsi_allocated) {
struct lws_vhost *vh = context->vhost_list;
/*
* Start Closing Phase 2: close of static handles
*/
lwsl_info("%s: all lws dynamic handles down, closing static\n",
__func__);
for (m = 0; m < context->count_threads; m++)
lws_libuv_destroyloop(context, m);
/* protocols may have initialized libuv objects */
while (vh) {
lws_vhost_destroy1(vh);
vh = vh->vhost_next;
}
}
}
/*
* 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.
*/
LWS_VISIBLE void
lws_libuv_stop(struct lws_context *context)
{
struct lws_context_per_thread *pt;
int n, m;
if (context->requested_kill)
return;
context->requested_kill = 1;
m = context->count_threads;
context->being_destroyed = 1;
/*
* Phase 1: start the close of every dynamic uv handle
*/
while (m--) {
pt = &context->pt[m];
for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
if (!wsi)
continue;
lws_close_free_wsi(wsi,
LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY, __func__
/* no protocol close */);
n--;
}
}
lwsl_info("%s: started closing all wsi\n", __func__);
/* we cannot have completed... there are at least the cancel pipes */
}
void
lws_libuv_closehandle(struct lws *wsi)
{
if (wsi->told_event_loop_closed) {
assert(0);
return;
}
wsi->told_event_loop_closed = 1;
/* required to defer actual deletion until libuv has processed it */
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi);
}
static void
lws_libuv_closewsi_m(uv_handle_t* handle)
{
@ -652,16 +332,6 @@ lws_libuv_closewsi_m(uv_handle_t* handle)
compatible_close(sockfd);
}
void
lws_libuv_closehandle_manually(struct lws *wsi)
{
uv_handle_t *h = (void *)&wsi->w_read.uv.watcher;
h->data = (void *)(lws_intptr_t)wsi->desc.sockfd;
/* required to defer actual deletion until libuv has processed it */
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi_m);
}
int
lws_libuv_check_watcher_active(struct lws *wsi)
{
@ -833,3 +503,441 @@ lws_plat_plugins_destroy(struct lws_context *context)
#endif
static int
elops_init_context_uv(struct lws_context *context,
const struct lws_context_creation_info *info)
{
int n;
context->eventlib_signal_cb = info->signal_cb;
for (n = 0; n < context->count_threads; n++)
context->pt[n].w_sigint.context = context;
return 0;
}
static int
elops_destroy_context1_uv(struct lws_context *context)
{
struct lws_context_per_thread *pt;
int n, m;
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->uv.io_loop,
UV_RUN_NOWAIT)))
;
if (m)
lwsl_err("%s: tsi %d: failed to close everything\n", __func__, 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->uv.io_loop) {
internal = 1;
if (!context->finalize_destroy_after_internal_loops_stopped)
uv_stop(pt->uv.io_loop);
else {
#if UV_VERSION_MAJOR > 0
uv_loop_close(pt->uv.io_loop);
#endif
lws_free_set_NULL(pt->uv.io_loop);
}
}
}
return internal;
}
static int
elops_wsi_logical_close_uv(struct lws *wsi)
{
if (wsi->parent_carries_io || !lws_sockfd_valid(wsi->desc.sockfd))
return 0;
if (wsi->listener || wsi->event_pipe) {
lwsl_debug("%s: %p: %d %d stop listener / pipe poll\n",
__func__, wsi, wsi->listener, wsi->event_pipe);
uv_poll_stop(&wsi->w_read.uv.watcher);
}
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
/*
* 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_warn("Waiting for libuv watcher to close\n");
return 1;
}
return 0;
}
static void
elops_close_handle_manually_uv(struct lws *wsi)
{
uv_handle_t *h = (void *)&wsi->w_read.uv.watcher;
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
h->data = (void *)(lws_intptr_t)wsi->desc.sockfd;
/* required to defer actual deletion until libuv has processed it */
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi_m);
}
static void
elops_accept_uv(struct lws *wsi)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
wsi->w_read.context = wsi->context;
if (wsi->role_ops->file_handle)
uv_poll_init(pt->uv.io_loop, &wsi->w_read.uv.watcher,
(int)(long long)wsi->desc.filefd);
else
uv_poll_init_socket(pt->uv.io_loop, &wsi->w_read.uv.watcher,
wsi->desc.sockfd);
}
static void
elops_io_uv(struct lws *wsi, int flags)
{
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
struct lws_io_watcher *w = &wsi->w_read;
int current_events = w->actual_events & (UV_READABLE | UV_WRITABLE);
lwsl_debug("%s: %p: %d\n", __func__, wsi, flags);
/* w->context is set after the loop is initialized */
if (!pt->uv.io_loop || !w->context) {
lwsl_info("%s: no io loop yet\n", __func__);
return;
}
if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
(flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
lwsl_err("%s: assert: flags %d", __func__, flags);
assert(0);
}
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->uv.watcher, 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->uv.watcher);
else
uv_poll_start(&w->uv.watcher, current_events,
lws_io_cb);
}
w->actual_events = current_events;
}
static int
elops_init_vhost_listen_wsi_uv(struct lws *wsi)
{
struct lws_context_per_thread *pt;
struct lws_vhost *vh = wsi->vhost;
int n;
if (!wsi)
wsi = vh->lserv_wsi;
if (!wsi)
return 0;
if (wsi->w_read.context)
return 0;
pt = &vh->context->pt[(int)wsi->tsi];
if (!pt->uv.io_loop)
return 0;
wsi->w_read.context = vh->context;
n = uv_poll_init_socket(pt->uv.io_loop,
&wsi->w_read.uv.watcher, wsi->desc.sockfd);
if (n) {
lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
n, (void *)(lws_intptr_t)wsi->desc.sockfd);
return -1;
}
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 (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
uv_run(context->pt[tsi].uv.io_loop, 0);
}
static void
elops_destroy_pt_uv(struct lws_context *context, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
int m, ns;
lwsl_info("%s: %d\n", __func__, tsi);
if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
return;
if (!pt->uv.io_loop)
return;
if (pt->event_loop_destroy_processing_done)
return;
pt->event_loop_destroy_processing_done = 1;
if (!pt->event_loop_foreign) {
uv_signal_stop(&pt->w_sigint.uv.watcher);
ns = 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->uv.signals[m]);
uv_close((uv_handle_t *)&pt->uv.signals[m],
lws_uv_close_cb_sa);
}
} else
lwsl_debug("%s: not closing pt signals\n", __func__);
uv_timer_stop(&pt->uv.timeout_watcher);
uv_close((uv_handle_t *)&pt->uv.timeout_watcher, lws_uv_close_cb_sa);
uv_timer_stop(&pt->uv.hrtimer);
uv_close((uv_handle_t *)&pt->uv.hrtimer, lws_uv_close_cb_sa);
uv_idle_stop(&pt->uv.idle);
uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
}
/*
* 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
*/
LWS_VISIBLE int
elops_init_pt_uv(struct lws_context *context, void *_loop, int tsi)
{
struct lws_context_per_thread *pt = &context->pt[tsi];
struct lws_vhost *vh = context->vhost_list;
int status = 0, n, ns, first = 1;
uv_loop_t *loop = (uv_loop_t *)_loop;
if (!pt->uv.io_loop) {
if (!loop) {
loop = lws_malloc(sizeof(*loop), "libuv loop");
if (!loop) {
lwsl_err("OOM\n");
return -1;
}
#if UV_VERSION_MAJOR > 0
uv_loop_init(loop);
#else
lwsl_err("This libuv is too old to work...\n");
return 1;
#endif
pt->event_loop_foreign = 0;
} else {
lwsl_notice(" Using foreign event loop...\n");
pt->event_loop_foreign = 1;
}
pt->uv.io_loop = loop;
uv_idle_init(loop, &pt->uv.idle);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.idle, context);
ns = 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)ARRAY_SIZE(pt->uv.signals));
for (n = 0; n < ns; n++) {
uv_signal_init(loop, &pt->uv.signals[n]);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.signals[n],
context);
pt->uv.signals[n].data = pt->context;
uv_signal_start(&pt->uv.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.
*/
while (vh) {
if (elops_init_vhost_listen_wsi_uv(vh->lserv_wsi) == -1)
return -1;
vh = vh->vhost_next;
}
if (!first)
return status;
uv_timer_init(pt->uv.io_loop, &pt->uv.timeout_watcher);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.timeout_watcher, context);
uv_timer_start(&pt->uv.timeout_watcher, lws_uv_timeout_cb, 10, 1000);
uv_timer_init(pt->uv.io_loop, &pt->uv.hrtimer);
LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(&pt->uv.hrtimer, context);
return status;
}
static void
lws_libuv_closewsi(uv_handle_t* handle)
{
struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
(char *)(&n->w_read.uv.watcher));
struct lws_context *context = lws_get_context(wsi);
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
int lspd = 0, m;
lwsl_info("%s: %p\n", __func__, wsi);
/*
* We get called back here for every wsi that closes
*/
if (wsi->role_ops == &role_ops_listen && wsi->context->deprecated) {
lspd = 1;
context->deprecation_pending_listen_close_count--;
if (!context->deprecation_pending_listen_close_count)
lspd = 2;
}
lws_pt_lock(pt, __func__);
__lws_close_free_wsi_final(wsi);
lws_pt_unlock(pt);
if (lspd == 2 && context->deprecation_cb) {
lwsl_notice("calling deprecation callback\n");
context->deprecation_cb();
}
lwsl_info("%s: sa left %d: dyn left: %d (rk %d)\n", __func__,
context->count_event_loop_static_asset_handles,
context->count_wsi_allocated, context->requested_kill);
/*
* eventually, we closed all the wsi...
*/
if (context->requested_kill && !context->count_wsi_allocated) {
struct lws_vhost *vh = context->vhost_list;
/*
* Start Closing Phase 2: close of static handles
*/
lwsl_info("%s: all lws dynamic handles down, closing static\n",
__func__);
for (m = 0; m < context->count_threads; m++)
elops_destroy_pt_uv(context, m);
/* protocols may have initialized libuv objects */
while (vh) {
lws_vhost_destroy1(vh);
vh = vh->vhost_next;
}
if (context->pt[0].event_loop_foreign) {
lwsl_info("%s: calling lws_context_destroy2\n", __func__);
lws_context_destroy2(context);
}
}
}
void
lws_libuv_closehandle(struct lws *wsi)
{
if (wsi->told_event_loop_closed) {
assert(0);
return;
}
lwsl_debug("%s: %p\n", __func__, wsi);
wsi->told_event_loop_closed = 1;
/* required to defer actual deletion until libuv has processed it */
uv_close((uv_handle_t*)&wsi->w_read.uv.watcher, lws_libuv_closewsi);
}
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,
/* periodic_events_available */ 0,
};

View file

@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* This is included from private-libwebsockets.h if LWS_ROLE_WS
* This is included from private-libwebsockets.h if LWS_WITH_LIBUV
*/
#include <uv.h>
@ -49,7 +49,6 @@ struct lws_pt_eventlibs_libuv {
};
struct lws_context_eventlibs_libuv {
uv_signal_cb sigint_cb;
uv_loop_t pu_loop;
};
@ -61,17 +60,11 @@ struct lws_signal_watcher_libuv {
uv_signal_t watcher;
};
#define LWS_LIBUV_ENABLED(context) lws_check_opt(context->options, \
LWS_SERVER_OPTION_LIBUV)
extern struct lws_event_loop_ops event_loop_ops_uv;
LWS_EXTERN void
lws_libuv_accept(struct lws *new_wsi, lws_sock_file_fd_type desc);
LWS_EXTERN void
lws_libuv_io(struct lws *wsi, int flags);
LWS_EXTERN int
lws_libuv_init_fd_table(struct lws_context *context);
LWS_EXTERN void
lws_libuv_run(const struct lws_context *context, int tsi);
LWS_EXTERN void
lws_libuv_destroyloop(struct lws_context *context, int tsi);
LWS_EXTERN int
lws_uv_initvhost(struct lws_vhost* vh, struct lws*);
#define LWS_LIBUV_ENABLED(context) lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV)
LWS_EXTERN void lws_feature_status_libuv(const struct lws_context_creation_info *info);
lws_feature_status_libuv(const struct lws_context_creation_info *info);

View file

@ -0,0 +1,43 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* This is included from private-libwebsockets.h if LWS_ROLE_WS
*/
#include <private-libwebsockets.h>
struct lws_event_loop_ops event_loop_ops_poll = {
/* name */ "poll",
/* init_context */ NULL,
/* destroy_context1 */ NULL,
/* destroy_context2 */ NULL,
/* init_vhost_listen_wsi */ NULL,
/* init_pt */ NULL,
/* wsi_logical_close */ NULL,
/* check_client_connect_ok */ NULL,
/* close_handle_manually */ NULL,
/* accept */ NULL,
/* io */ NULL,
/* run */ NULL,
/* destroy_pt */ NULL,
/* destroy wsi */ NULL,
/* periodic_events_available */ 1,
};

View file

@ -0,0 +1,23 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2018 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*
*/
extern struct lws_event_loop_ops event_loop_ops_poll;

View file

@ -152,7 +152,8 @@ __lws_free_wsi(struct lws *wsi)
#endif
__lws_remove_from_timeout_list(wsi);
lws_libevent_destroy(wsi);
if (wsi->context->event_loop_ops->destroy_wsi)
wsi->context->event_loop_ops->destroy_wsi(wsi);
wsi->context->count_wsi_allocated--;
lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi,
@ -796,11 +797,11 @@ just_kill_connection:
if (!wsi->socket_is_permanently_unusable &&
lws_sockfd_valid(wsi->desc.sockfd) &&
lwsi_state(wsi) != LRS_SHUTDOWN &&
!LWS_LIBUV_ENABLED(context)) {
context->event_loop_ops->periodic_events_available) {
__lws_change_pollfd(wsi, LWS_POLLOUT, LWS_POLLIN);
lwsi_set_state(wsi, LRS_SHUTDOWN);
__lws_set_timeout(wsi, PENDING_TIMEOUT_SHUTDOWN_FLUSH,
context->timeout_secs);
context->timeout_secs);
return;
}
@ -860,24 +861,9 @@ just_kill_connection:
async_close:
wsi->socket_is_permanently_unusable = 1;
#ifdef LWS_WITH_LIBUV
if (!wsi->parent_carries_io && lws_sockfd_valid(wsi->desc.sockfd))
if (LWS_LIBUV_ENABLED(context)) {
if (wsi->listener) {
lwsl_debug("%s: stop listener poll\n", __func__);
uv_poll_stop(&wsi->w_read.uv.watcher);
}
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n",
__func__, wsi);
/*
* libuv has to do his own close handle processing
* asynchronously
*/
lws_libuv_closehandle(wsi);
if (wsi->context->event_loop_ops->wsi_logical_close)
if (wsi->context->event_loop_ops->wsi_logical_close(wsi))
return;
}
#endif
__lws_close_free_wsi_final(wsi);
}

View file

@ -855,37 +855,6 @@ struct lws_context;
/* needed even with extensions disabled for create context */
struct lws_extension;
/*! \defgroup lwsmeta lws-meta
*
* ##lws-meta protocol
*
* The protocol wraps other muxed connections inside one tcp connection.
*
* Commands are assigned from 0x41 up (so they are valid unicode)
*/
///@{
enum lws_meta_commands {
LWS_META_CMD_OPEN_SUBCHANNEL = 'A',
/**< Client requests to open new subchannel
*/
LWS_META_CMD_OPEN_RESULT,
/**< Result of client request to open new subchannel */
LWS_META_CMD_CLOSE_NOTIFY,
/**< Notification of subchannel closure */
LWS_META_CMD_CLOSE_RQ,
/**< client requests to close a subchannel */
LWS_META_CMD_WRITE,
/**< connection writes something to specific channel index */
/****** add new things just above ---^ ******/
};
/* channel numbers are transported offset by 0x20 so they are valid unicode */
#define LWS_META_TRANSPORT_OFFSET 0x20
///@}
/*! \defgroup usercb User Callback
*
@ -2990,6 +2959,26 @@ struct lws_context_creation_info {
* VHOST: If non-NULL, per-vhost list of advertised alpn, comma-
* separated
*/
void **foreign_loops;
/**< CONTEXT: This is ignored if the context is not being started with
* an event loop, ie, .options has a flag like
* LWS_SERVER_OPTION_LIBUV.
*
* NULL indicates lws should start its own even loop for
* each service thread, and deal with closing the loops
* when the context is destroyed.
*
* Non-NULL means it points to an array of external
* ("foreign") event loops that are to be used in turn for
* each service thread. In the default case of 1 service
* thread, it can just point to one foreign event loop.
*/
void (*signal_cb)(void *event_lib_handle, int signum);
/**< CONTEXT: NULL: default signal handling. Otherwise this receives
* the signal handler callback. event_lib_handle is the
* native event library signal handle, eg uv_signal_t *
* for libuv.
*/
/* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility
@ -2998,6 +2987,12 @@ struct lws_context_creation_info {
* members added above will see 0 (default) even if the app
* was not built against the newer headers.
*/
struct lws_context **pcontext;
/**< CONTEXT: if non-NULL, at the end of context destroy processing,
* the pointer pointed to by pcontext is written with NULL. You can
* use this to let foreign event loops know that lws context destruction
* is fully completed.
*/
void *_unused[4]; /**< dummy */
};
@ -3039,6 +3034,7 @@ struct lws_context_creation_info {
LWS_VISIBLE LWS_EXTERN struct lws_context *
lws_create_context(const struct lws_context_creation_info *info);
/**
* lws_context_destroy() - Destroy the websocket context
* \param context: Websocket context
@ -3050,9 +3046,6 @@ lws_create_context(const struct lws_context_creation_info *info);
LWS_VISIBLE LWS_EXTERN void
lws_context_destroy(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_context_destroy2(struct lws_context *context);
typedef int (*lws_reload_func)(void);
/**
@ -4591,30 +4584,6 @@ LWS_VISIBLE LWS_EXTERN int
lws_plat_recommended_rsa_bits(void);
///@}
/*! \defgroup ev libev helpers
*
* ##libev helpers
*
* APIs specific to libev event loop itegration
*/
///@{
#if defined(LWS_WITH_LIBEV)
typedef void (lws_ev_signal_cb_t)(EV_P_ struct ev_signal *w, int revents);
LWS_VISIBLE LWS_EXTERN int
lws_ev_sigint_cfg(struct lws_context *context, int use_event_loop_sigint,
lws_ev_signal_cb_t *cb);
LWS_VISIBLE LWS_EXTERN int
lws_ev_initloop(struct lws_context *context, struct ev_loop *loop, int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
#endif /* LWS_WITH_LIBEV */
///@}
/*! \defgroup uv libuv helpers
*
* ##libuv helpers
@ -4623,33 +4592,8 @@ lws_ev_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);
*/
///@{
#ifdef LWS_WITH_LIBUV
LWS_VISIBLE LWS_EXTERN int
lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
uv_signal_cb cb);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_run(const struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_stop(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_stop_without_kill(const struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN int
lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi);
LWS_VISIBLE LWS_EXTERN uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_uv_sigint_cb(uv_signal_t *watcher, int signum);
LWS_VISIBLE LWS_EXTERN void
lws_close_all_handles_in_loop(uv_loop_t *loop);
/*
* Any direct libuv allocations in protocol handlers must participate in the
* Any direct libuv allocations in lws protocol handlers must participate in the
* lws reference counting scheme. Two apis are provided:
*
* - lws_libuv_static_refcount_add(handle, context) to mark the handle with
@ -4658,12 +4602,16 @@ lws_close_all_handles_in_loop(uv_loop_t *loop);
* - lws_libuv_static_refcount_del() which should be used as the close callback
* for your own libuv objects declared in the protocol scope.
*
* See the dumb increment plugin for an example of how to use them.
*
* Using the apis allows lws to detach itself from a libuv loop completely
* cleanly and at the moment all of its libuv objects have completed close.
*/
LWS_VISIBLE uv_loop_t *
lws_uv_getloop(struct lws_context *context, int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_stop(struct lws_context *context);
LWS_VISIBLE LWS_EXTERN void
lws_libuv_static_refcount_add(uv_handle_t *, struct lws_context *context);
@ -4678,32 +4626,6 @@ lws_libuv_static_refcount_del(uv_handle_t *);
#endif
///@}
/*! \defgroup event libevent helpers
*
* ##libevent helpers
*
* APIs specific to libevent event loop itegration
*/
///@{
#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT)
typedef void (lws_event_signal_cb_t) (evutil_socket_t sock_fd, short revents,
void *ctx);
LWS_VISIBLE LWS_EXTERN int
lws_event_sigint_cfg(struct lws_context *context, int use_event_sigint,
lws_event_signal_cb_t cb);
LWS_VISIBLE LWS_EXTERN int
lws_event_initloop(struct lws_context *context, struct event_base *loop,
int tsi);
LWS_VISIBLE LWS_EXTERN void
lws_event_sigint_cb(evutil_socket_t sock_fd, short revents,
void *ctx);
#endif /* LWS_WITH_LIBEVENT */
///@}
/*! \defgroup timeout Connection timeouts

View file

@ -176,9 +176,8 @@ _lws_plat_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
if (timeout_ms < 0)
goto faked_service;
lws_libev_run(context, tsi);
lws_libuv_run(context, tsi);
lws_libevent_run(context, tsi);
if (context->event_loop_ops->run_pt)
context->event_loop_ops->run_pt(context, tsi);
if (!context->service_tid_detected) {
struct lws _lws;
@ -738,9 +737,8 @@ lws_plat_insert_socket_into_fds(struct lws_context *context, struct lws *wsi)
{
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);
if (context->event_loop_ops->io)
context->event_loop_ops->io(wsi, LWS_EV_START | LWS_EV_READ);
pt->fds[pt->fds_count++].revents = 0;
}
@ -751,9 +749,9 @@ lws_plat_delete_socket_from_fds(struct lws_context *context,
{
struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
if (context->event_loop_ops->io)
context->event_loop_ops->io(wsi,
LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
pt->fds_count--;
}
@ -915,10 +913,6 @@ lws_plat_init(struct lws_context *context,
return 1;
}
(void)lws_libev_init_fd_table(context);
(void)lws_libuv_init_fd_table(context);
(void)lws_libevent_init_fd_table(context);
#ifdef LWS_WITH_PLUGINS
if (info->plugin_dirs)
lws_plat_plugins_init(context, info->plugin_dirs);

View file

@ -144,25 +144,22 @@ _lws_change_pollfd(struct lws *wsi, int _and, int _or, struct lws_pollargs *pa)
goto bail;
}
if (_and & LWS_POLLIN) {
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ);
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_READ);
}
if (_or & LWS_POLLIN) {
lws_libev_io(wsi, LWS_EV_START | LWS_EV_READ);
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_READ);
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_READ);
}
if (_and & LWS_POLLOUT) {
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
lws_libevent_io(wsi, LWS_EV_STOP | LWS_EV_WRITE);
}
if (_or & LWS_POLLOUT) {
lws_libev_io(wsi, LWS_EV_START | LWS_EV_WRITE);
lws_libuv_io(wsi, LWS_EV_START | LWS_EV_WRITE);
lws_libevent_io(wsi, LWS_EV_START | LWS_EV_WRITE);
if (context->event_loop_ops->io) {
if (_and & LWS_POLLIN)
context->event_loop_ops->io(wsi,
LWS_EV_STOP | LWS_EV_READ);
if (_or & LWS_POLLIN)
context->event_loop_ops->io(wsi,
LWS_EV_START | LWS_EV_READ);
if (_and & LWS_POLLOUT)
context->event_loop_ops->io(wsi,
LWS_EV_STOP | LWS_EV_WRITE);
if (_or & LWS_POLLOUT)
context->event_loop_ops->io(wsi,
LWS_EV_START | LWS_EV_WRITE);
}
/*
@ -319,10 +316,10 @@ __remove_wsi_socket_from_fds(struct lws *wsi)
/* the guy who is to be deleted's slot index in pt->fds */
m = wsi->position_in_fds_table;
lws_libev_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
LWS_EV_PREPARE_DELETION);
lws_libuv_io(wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
LWS_EV_PREPARE_DELETION);
if (context->event_loop_ops->io)
context->event_loop_ops->io(wsi,
LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE |
LWS_EV_PREPARE_DELETION);
lwsl_debug("%s: wsi=%p, sock=%d, fds pos=%d, end guy pos=%d, endfd=%d\n",
__func__, wsi, wsi->desc.sockfd, wsi->position_in_fds_table,

View file

@ -199,16 +199,6 @@
#include "libwebsockets.h"
#if defined(LWS_WITH_LIBEV)
#include "event-libs/libev/private.h"
#endif
#ifdef LWS_WITH_LIBUV
#include "event-libs/libuv/private.h"
#endif
#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT)
#include "event-libs/libevent/private.h"
#endif
#if defined(LWS_WITH_TLS)
#include "tls/private.h"
#endif
@ -382,6 +372,12 @@ enum lws_ssl_capable_status {
#define lws_memory_barrier()
#endif
/*
*
* ------ role ------
*
*/
typedef uint32_t lws_wsi_state_t;
/*
@ -579,6 +575,8 @@ struct lws_role_ops {
* (just client applies if no concept of client or server)
*/
uint16_t close_cb[2];
unsigned int file_handle:1; /* role operates on files not sockets */
};
/* null-terminated array of pointers to roles lws built with */
@ -641,6 +639,60 @@ enum {
LWS_UPG_RET_BAIL
};
/*
*
* ------ event_loop ops ------
*
*/
struct lws_event_loop_ops {
const char *name;
/* event loop-specific context init during context creation */
int (*init_context)(struct lws_context *context,
const struct lws_context_creation_info *info);
/* called during lws_destroy_context */
int (*destroy_context1)(struct lws_context *context);
/* called during lws_destroy_context2 */
int (*destroy_context2)(struct lws_context *context);
/* init vhost listening wsi */
int (*init_vhost_listen_wsi)(struct lws *wsi);
/* init the event loop for a pt */
int (*init_pt)(struct lws_context *context, void *_loop, int tsi);
/* called at end of first phase of close_free_wsi() */
int (*wsi_logical_close)(struct lws *wsi);
/* return nonzero if client connect not allowed */
int (*check_client_connect_ok)(struct lws *wsi);
/* close handle manually */
void (*close_handle_manually)(struct lws *wsi);
/* event loop accept processing */
void (*accept)(struct lws *wsi);
/* control wsi active events */
void (*io)(struct lws *wsi, int flags);
/* run the event loop for a pt */
void (*run_pt)(struct lws_context *context, int tsi);
/* called before pt is destroyed */
void (*destroy_pt)(struct lws_context *context, int tsi);
/* called just before wsi is freed */
void (*destroy_wsi)(struct lws *wsi);
unsigned int periodic_events_available:1;
};
#if defined(LWS_WITH_POLL)
#include "event-libs/poll/private.h"
#endif
#if defined(LWS_WITH_LIBEV)
#include "event-libs/libev/private.h"
#endif
#if defined(LWS_WITH_LIBUV)
#include "event-libs/libuv/private.h"
#endif
#if defined(LWS_WITH_LIBEVENT) && !defined(LWS_HIDE_LIBEVENT)
#include "event-libs/libevent/private.h"
#endif
/* enums of socks version */
enum socks_version {
SOCKS_VERSION_4 = 4,
@ -1031,6 +1083,7 @@ struct lws_context {
time_t time_fixup;
const struct lws_plat_file_ops *fops;
struct lws_plat_file_ops fops_platform;
struct lws_context **pcontext_finalize;
#if defined(LWS_WITH_HTTP2)
struct http2_settings set;
#endif
@ -1067,6 +1120,7 @@ struct lws_context {
const struct lws_protocol_vhost_options *reject_service_keywords;
const char *alpn_default;
lws_reload_func deprecation_cb;
void (*eventlib_signal_cb)(void *event_lib_handle, int signum);
#if defined(LWS_HAVE_SYS_CAPABILITY_H) && defined(LWS_HAVE_LIBCAP)
cap_value_t caps[4];
@ -1082,6 +1136,9 @@ struct lws_context {
#if defined(LWS_WITH_LIBEVENT)
struct lws_context_eventlibs_libevent event;
#endif
struct lws_event_loop_ops *event_loop_ops;
char canonical_hostname[128];
#ifdef LWS_LATENCY
unsigned long worst_latency;
@ -1099,10 +1156,7 @@ struct lws_context {
#endif
int max_fds;
#if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || defined(LWS_WITH_LIBEVENT)
int use_event_loop_sigint;
int count_event_loop_static_asset_handles;
#endif
int started_with_parent;
int uid, gid;
@ -1129,8 +1183,9 @@ struct lws_context {
unsigned int requested_kill:1;
unsigned int protocol_init_done:1;
unsigned int ssl_gate_accepts:1;
unsigned int doing_protocol_init;
unsigned int done_protocol_destroy_cb;
unsigned int doing_protocol_init:1;
unsigned int done_protocol_destroy_cb:1;
unsigned int finalize_destroy_after_internal_loops_stopped:1;
/*
* set to the Thread ID that's doing the service loop just before entry
* to poll indicates service thread likely idling in poll()
@ -1161,8 +1216,6 @@ LWS_EXTERN void
__lws_close_free_wsi_final(struct lws *wsi);
LWS_EXTERN void
lws_libuv_closehandle(struct lws *wsi);
LWS_EXTERN void
lws_libuv_closehandle_manually(struct lws *wsi);
LWS_EXTERN int
lws_libuv_check_watcher_active(struct lws *wsi);
@ -1194,11 +1247,6 @@ enum {
};
#if !defined(LWS_WITH_LIBEV)
#define lws_libev_accept(_a, _b) ((void) 0)
#define lws_libev_io(_a, _b) ((void) 0)
#define lws_libev_init_fd_table(_a) (0)
#define lws_libev_run(_a, _b) ((void) 0)
#define lws_libev_destroyloop(_a, _b) ((void) 0)
#define LWS_LIBEV_ENABLED(context) (0)
#if !defined(LWS_WITH_ESP32)
#define lws_feature_status_libev(_a) \
@ -1209,11 +1257,6 @@ enum {
#endif
#if !defined(LWS_WITH_LIBUV)
#define lws_libuv_accept(_a, _b) ((void) 0)
#define lws_libuv_io(_a, _b) ((void) 0)
#define lws_libuv_init_fd_table(_a) (0)
#define lws_libuv_run(_a, _b) ((void) 0)
#define lws_libuv_destroyloop(_a, _b) ((void) 0)
#define LWS_LIBUV_ENABLED(context) (0)
#if !defined(LWS_WITH_ESP32)
#define lws_feature_status_libuv(_a) \
@ -1224,11 +1267,6 @@ enum {
#endif
#if !defined(LWS_WITH_LIBEVENT)
#define lws_libevent_accept(_a, _b) ((void) 0)
#define lws_libevent_destroy(_a) ((void) 0)
#define lws_libevent_io(_a, _b) ((void) 0)
#define lws_libevent_init_fd_table(_a) (0)
#define lws_libevent_run(_a, _b) ((void) 0)
#define lws_libevent_destroyloop(_a, _b) ((void) 0)
#define LWS_LIBEVENT_ENABLED(context) (0)
#if !defined(LWS_WITH_ESP32)
@ -1675,7 +1713,7 @@ LWS_EXTERN int
lws_change_pollfd(struct lws *wsi, int _and, int _or);
#ifndef LWS_NO_SERVER
int _lws_context_init_server(const struct lws_context_creation_info *info,
int _lws_vhost_init_server(const struct lws_context_creation_info *info,
struct lws_vhost *vhost);
LWS_EXTERN struct lws_vhost *
lws_select_vhost(struct lws_context *context, int port, const char *servername);
@ -1685,7 +1723,7 @@ lws_change_pollfd(struct lws *wsi, int _and, int _or);
lws_server_get_canonical_hostname(struct lws_context *context,
const struct lws_context_creation_info *info);
#else
#define _lws_context_init_server(_a, _b) (0)
#define _lws_vhost_init_server(_a, _b) (0)
#define lws_parse_ws(_a, _b, _c) (0)
#define lws_server_get_canonical_hostname(_a, _b)
#endif
@ -2045,6 +2083,10 @@ lws_tls_server_conn_alpn(struct lws *wsi);
int
lws_ws_client_rx_sm_block(struct lws *wsi, unsigned char **buf, size_t len);
void
lws_destroy_event_pipe(struct lws *wsi);
void
lws_context_destroy2(struct lws_context *context);
#ifdef __cplusplus
};

View file

@ -163,7 +163,9 @@ lws_cgi(struct lws *wsi, const char * const *exec_array, int script_uri_path_len
}
for (n = 0; n < 3; n++) {
lws_libuv_accept(cgi->stdwsi[n], cgi->stdwsi[n]->desc);
if (wsi->context->event_loop_ops->accept)
wsi->context->event_loop_ops->accept(cgi->stdwsi[n]);
if (__insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
goto bail3;
cgi->stdwsi[n]->parent = wsi;

View file

@ -98,4 +98,5 @@ struct lws_role_ops role_ops_cgi = {
/* destroy_role */ NULL,
/* writeable cb clnt, srv */ { 0, 0 },
/* close cb clnt, srv */ { 0, 0 },
/* file_handle */ 0,
};

View file

@ -635,4 +635,5 @@ struct lws_role_ops role_ops_h1 = {
LWS_CALLBACK_HTTP_WRITEABLE },
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
LWS_CALLBACK_CLOSED_HTTP },
/* file_handle */ 0,
};

View file

@ -1052,4 +1052,5 @@ struct lws_role_ops role_ops_h2 = {
LWS_CALLBACK_HTTP_WRITEABLE },
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
LWS_CALLBACK_CLOSED_HTTP },
/* file_handle */ 0,
};

View file

@ -338,14 +338,11 @@ create_new_conn:
if (!lws_socket_is_valid(wsi->desc.sockfd)) {
#if defined(LWS_WITH_LIBUV)
if (LWS_LIBUV_ENABLED(wsi->context))
if (lws_libuv_check_watcher_active(wsi)) {
lwsl_warn("Waiting for libuv watcher to close\n");
cce = "waiting for libuv watcher to close";
goto oom4;
}
#endif
if (wsi->context->event_loop_ops->check_client_connect_ok &&
wsi->context->event_loop_ops->check_client_connect_ok(wsi)) {
cce = "waiting for event loop watcher to close";
goto oom4;
}
#ifdef LWS_WITH_IPV6
if (wsi->ipv6)
@ -369,9 +366,8 @@ create_new_conn:
lwsi_set_state(wsi, LRS_WAITING_CONNECT);
lws_libev_accept(wsi, wsi->desc);
lws_libuv_accept(wsi, wsi->desc);
lws_libevent_accept(wsi, wsi->desc);
if (wsi->context->event_loop_ops->accept)
wsi->context->event_loop_ops->accept(wsi);
if (__insert_wsi_socket_into_fds(wsi->context, wsi)) {
compatible_close(wsi->desc.sockfd);
@ -650,21 +646,10 @@ lws_client_reset(struct lws **pwsi, int ssl, const char *address, int port,
lws_ssl_close(wsi);
#endif
#ifdef LWS_WITH_LIBUV
if (LWS_LIBUV_ENABLED(wsi->context)) {
lwsl_debug("%s: lws_libuv_closehandle: wsi %p\n", __func__, wsi);
/*
* libuv has to do his own close handle processing asynchronously
* but once it starts we can do everything else synchronously,
* including trash wsi->desc.sockfd since it took a copy.
*
* When it completes it will call compatible_close()
*/
lws_libuv_closehandle_manually(wsi);
} else
#else
compatible_close(wsi->desc.sockfd);
#endif
if (wsi->context->event_loop_ops->close_handle_manually)
wsi->context->event_loop_ops->close_handle_manually(wsi);
else
compatible_close(wsi->desc.sockfd);
__remove_wsi_socket_from_fds(wsi);

View file

@ -37,7 +37,7 @@ const char * const method_names[] = {
*/
int
_lws_context_init_server(const struct lws_context_creation_info *info,
_lws_vhost_init_server(const struct lws_context_creation_info *info,
struct lws_vhost *vhost)
{
int n, opt = 1, limit = 1;
@ -240,10 +240,8 @@ done_list:
wsi->vhost = vhost;
wsi->listener = 1;
#ifdef LWS_WITH_LIBUV
if (LWS_LIBUV_ENABLED(vhost->context))
lws_uv_initvhost(vhost, wsi);
#endif
if (wsi->context->event_loop_ops->init_vhost_listen_wsi)
wsi->context->event_loop_ops->init_vhost_listen_wsi(wsi);
if (__insert_wsi_socket_into_fds(vhost->context, wsi)) {
lwsl_notice("inserting wsi socket into fds failed\n");
@ -1353,7 +1351,8 @@ deal_body:
if (m < 0)
return -1;
lws_buflist_aware_consume(wsi, &ebuf, m, 1);
if (lws_buflist_aware_consume(wsi, &ebuf, m, 1))
return -1;
}
}
}
@ -1988,9 +1987,8 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
lwsl_debug("new wsi wsistate 0x%x\n", new_wsi->wsistate);
lws_libev_accept(new_wsi, new_wsi->desc);
lws_libuv_accept(new_wsi, new_wsi->desc);
lws_libevent_accept(new_wsi, new_wsi->desc);
if (context->event_loop_ops->accept)
context->event_loop_ops->accept(new_wsi);
if (!ssl) {
lws_pt_lock(pt, __func__);

View file

@ -172,4 +172,5 @@ struct lws_role_ops role_ops_listen = {
/* destroy_role */ NULL,
/* writeable cb clnt, srv */ { 0, 0 },
/* close cb clnt, srv */ { 0, 0 },
/* file_handle */ 0,
};

View file

@ -77,4 +77,5 @@ struct lws_role_ops role_ops_pipe = {
/* destroy_role */ NULL,
/* writeable cb clnt, srv */ { 0, 0 },
/* close cb clnt, srv */ { 0, 0 },
/* file_handle */ 1,
};

View file

@ -186,6 +186,7 @@ struct lws_role_ops role_ops_raw_skt = {
/* destroy_role */ NULL,
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE, 0 },
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE, 0 },
/* file_handle */ 0,
};
@ -213,4 +214,5 @@ struct lws_role_ops role_ops_raw_file = {
/* destroy_role */ NULL,
/* writeable cb clnt, srv */ { LWS_CALLBACK_RAW_WRITEABLE_FILE, 0 },
/* close cb clnt, srv */ { LWS_CALLBACK_RAW_CLOSE_FILE, 0 },
/* file_handle */ 1,
};

View file

@ -750,7 +750,7 @@ lws_service_periodic_checks(struct lws_context *context,
context->no_listener_vhost_list) {
struct lws_vhost *v = *pv;
lwsl_debug("deferred iface: checking if on vh %s\n", (*pv)->name);
if (_lws_context_init_server(NULL, *pv) == 0) {
if (_lws_vhost_init_server(NULL, *pv) == 0) {
/* became happy */
lwsl_notice("vh %s: became connected\n", v->name);
*pv = v->no_listener_vhost_list;
@ -899,12 +899,24 @@ lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd)
LWS_VISIBLE int
lws_service(struct lws_context *context, int timeout_ms)
{
if (context->event_loop_ops->run_pt) {
/* we are configured for an event loop */
context->event_loop_ops->run_pt(context, 0);
return 1;
}
return lws_plat_service(context, timeout_ms);
}
LWS_VISIBLE int
lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi)
{
if (context->event_loop_ops->run_pt) {
/* we are configured for an event loop */
context->event_loop_ops->run_pt(context, tsi);
return 1;
}
return _lws_plat_service_tsi(context, timeout_ms, tsi);
}

View file

@ -1,7 +1,7 @@
/*
* libwebsockets web server application
*
* Copyright (C) 2010-2017 Andy Green <andy@warmcat.com>
* Copyright (C) 2010-2018 Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
@ -36,6 +36,7 @@
#else
#include <io.h>
#include "gettimeofday.h"
#include <uv.h>
int fork(void)
{
@ -52,7 +53,7 @@ static struct lws_context *context;
static char config_dir[128];
static int opts = 0, do_reload = 1;
static uv_loop_t loop;
static uv_signal_t signal_outer;
static uv_signal_t signal_outer[2];
static int pids[32];
void lwsl_emit_stderr(int level, const char *line);
@ -101,7 +102,9 @@ void signal_cb(uv_signal_t *watcher, int signum)
break;
}
lwsl_err("Signal %d caught\n", watcher->signum);
lws_libuv_stop(context);
uv_signal_stop(watcher);
uv_signal_stop(&signal_outer[1]);
lws_context_destroy(context);
}
static int
@ -110,6 +113,7 @@ context_creation(void)
int cs_len = LWSWS_CONFIG_STRING_SIZE - 1;
struct lws_context_creation_info info;
char *cs, *config_strings;
void *foreign_loops[1];
cs = config_strings = malloc(LWSWS_CONFIG_STRING_SIZE);
if (!config_strings) {
@ -120,7 +124,6 @@ context_creation(void)
memset(&info, 0, sizeof(info));
info.external_baggage_free_on_destroy = config_strings;
info.max_http_header_pool = 1024;
info.pt_serv_buf_size = 8192;
info.options = opts | LWS_SERVER_OPTION_VALIDATE_UTF8 |
LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
@ -135,15 +138,16 @@ context_creation(void)
if (lwsws_get_config_globals(&info, config_dir, &cs, &cs_len))
goto init_failed;
foreign_loops[0] = &loop;
info.foreign_loops = foreign_loops;
info.pcontext = &context;
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
goto init_failed;
}
lws_uv_sigint_cfg(context, 1, signal_cb);
lws_uv_initloop(context, &loop, 0);
/*
* then create the vhosts... protocols are entirely coming from
* plugins, so we leave it NULL
@ -151,8 +155,7 @@ context_creation(void)
info.extensions = exts;
if (lwsws_get_config_vhosts(context, &info, config_dir,
&cs, &cs_len))
if (lwsws_get_config_vhosts(context, &info, config_dir, &cs, &cs_len))
return 1;
return 0;
@ -190,6 +193,8 @@ reload_handler(int signum)
case SIGINT:
case SIGTERM:
case SIGKILL:
fprintf(stderr, "master process waiting 2s...\n");
sleep(2); /* give children a chance to deal with the signal */
fprintf(stderr, "killing service processes\n");
for (m = 0; m < (int)ARRAY_SIZE(pids); m++)
if (pids[m])
@ -203,7 +208,7 @@ reload_handler(int signum)
int main(int argc, char **argv)
{
int n = 0, debug_level = 7;
int n = 0, budget = 100, debug_level = 7;
#ifndef _WIN32
int m;
int status, syslog_options = LOG_PID | LOG_PERROR;
@ -283,7 +288,7 @@ int main(int argc, char **argv)
lws_set_log_level(debug_level, lwsl_emit_syslog);
lwsl_notice("lwsws libwebsockets web server - license CC0 + LGPL2.1\n");
lwsl_notice("(C) Copyright 2010-2016 Andy Green <andy@warmcat.com>\n");
lwsl_notice("(C) Copyright 2010-2018 Andy Green <andy@warmcat.com>\n");
#if (UV_VERSION_MAJOR > 0) // Travis...
uv_loop_init(&loop);
@ -291,30 +296,31 @@ int main(int argc, char **argv)
fprintf(stderr, "Your libuv is too old!\n");
return 0;
#endif
uv_signal_init(&loop, &signal_outer);
uv_signal_start(&signal_outer, signal_cb, SIGINT);
uv_signal_start(&signal_outer, signal_cb, SIGHUP);
uv_signal_init(&loop, &signal_outer[0]);
uv_signal_start(&signal_outer[0], signal_cb, SIGINT);
uv_signal_init(&loop, &signal_outer[1]);
uv_signal_start(&signal_outer[1], signal_cb, SIGHUP);
if (context_creation()) {
lwsl_err("Context creation failed\n");
return 1;
}
lws_libuv_run(context, 0);
lws_service(context, 0);
lwsl_err("%s: closing\n", __func__);
for (n = 0; n < 2; n++) {
uv_signal_stop(&signal_outer[n]);
uv_close((uv_handle_t *)&signal_outer[n], NULL);
}
uv_signal_stop(&signal_outer);
lws_context_destroy(context);
#if (UV_VERSION_MAJOR > 0) // Travis...
lws_close_all_handles_in_loop(&loop);
n = 0;
while (n++ < 4096 && uv_loop_close(&loop))
uv_run(&loop, UV_RUN_NOWAIT);
#endif
while ((n = uv_loop_close(&loop)) && --budget)
uv_run(&loop, UV_RUN_ONCE);
lws_context_destroy2(context);
fprintf(stderr, "lwsws exited cleanly\n");
fprintf(stderr, "lwsws exited cleanly: %d\n", n);
#ifndef _WIN32
closelog();

View file

@ -3,7 +3,19 @@
This demonstrates having lws take part in a libuv loop owned by
something else, with its own objects running in the loop.
Lws can join the loop, and clean up perfectly after itself.
Lws can join the loop, and clean up perfectly after itself without
leaving anything behind or making trouble in the larger loop, which
does not need to stop during lws creation or destruction.
First the foreign loop is created with a 1s timer, and runs alone for 5s.
Then the lws context is created inside the timer callback and runs for 10s...
during this period you can visit http://localhost:7681 for normal lws
service using the foreign loop.
After the 10s are up, the lws context is destroyed inside the foreign loop
timer. The foreign loop runs alone again for a further 5s and then
exits itself.
## build

View file

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
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
e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=
-----END CERTIFICATE-----

View file

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCjYtuWaICCY0tJ
PubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8Di3DAmHK
nSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTekLWcfI5ZZ
toGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnHKT/m6DSU
0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6jzhNyMBT
J1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQUjy5N8pS
Np7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAzTK4l2pHN
uC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBKIzv9cgi9
fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0nPN1IMSn
zXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzoGMTvP/Au
ehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9psNcjTMaB
QLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABAoICAFWe8MQZb37k2gdAV3Y6aq8f
qokKQqbCNLd3giGFwYkezHXoJfg6Di7oZxNcKyw35LFEghkgtQqErQqo35VPIoH+
vXUpWOjnCmM4muFA9/cX6mYMc8TmJsg0ewLdBCOZVw+wPABlaqz+0UOiSMMftpk9
fz9JwGd8ERyBsT+tk3Qi6D0vPZVsC1KqxxL/cwIFd3Hf2ZBtJXe0KBn1pktWht5A
Kqx9mld2Ovl7NjgiC1Fx9r+fZw/iOabFFwQA4dr+R8mEMK/7bd4VXfQ1o/QGGbMT
G+ulFrsiDyP+rBIAaGC0i7gDjLAIBQeDhP409ZhswIEc/GBtODU372a2CQK/u4Q/
HBQvuBtKFNkGUooLgCCbFxzgNUGc83GB/6IwbEM7R5uXqsFiE71LpmroDyjKTlQ8
YZkpIcLNVLw0usoGYHFm2rvCyEVlfsE3Ub8cFyTFk50SeOcF2QL2xzKmmbZEpXgl
xBHR0hjgon0IKJDGfor4bHO7Nt+1Ece8u2oTEKvpz5aIn44OeC5mApRGy83/0bvs
esnWjDE/bGpoT8qFuy+0urDEPNId44XcJm1IRIlG56ErxC3l0s11wrIpTmXXckqw
zFR9s2z7f0zjeyxqZg4NTPI7wkM3M8BXlvp2GTBIeoxrWB4V3YArwu8QF80QBgVz
mgHl24nTg00UH1OjZsABAoIBAQDOxftSDbSqGytcWqPYP3SZHAWDA0O4ACEM+eCw
au9ASutl0IDlNDMJ8nC2ph25BMe5hHDWp2cGQJog7pZ/3qQogQho2gUniKDifN77
40QdykllTzTVROqmP8+efreIvqlzHmuqaGfGs5oTkZaWj5su+B+bT+9rIwZcwfs5
YRINhQRx17qa++xh5mfE25c+M9fiIBTiNSo4lTxWMBShnK8xrGaMEmN7W0qTMbFH
PgQz5FcxRjCCqwHilwNBeLDTp/ZECEB7y34khVh531mBE2mNzSVIQcGZP1I/DvXj
W7UUNdgFwii/GW+6M0uUDy23UVQpbFzcV8o1C2nZc4Fb4zwBAoIBAQDKSJkFwwuR
naVJS6WxOKjX8MCu9/cKPnwBv2mmI2jgGxHTw5sr3ahmF5eTb8Zo19BowytN+tr6
2ZFoIBA9Ubc9esEAU8l3fggdfM82cuR9sGcfQVoCh8tMg6BP8IBLOmbSUhN3PG2m
39I802u0fFNVQCJKhx1m1MFFLOu7lVcDS9JN+oYVPb6MDfBLm5jOiPuYkFZ4gH79
J7gXI0/YKhaJ7yXthYVkdrSF6Eooer4RZgma62Dd1VNzSq3JBo6rYjF7Lvd+RwDC
R1thHrmf/IXplxpNVkoMVxtzbrrbgnC25QmvRYc0rlS/kvM4yQhMH3eA7IycDZMp
Y+0xm7I7jTT7AoIBAGKzKIMDXdCxBWKhNYJ8z7hiItNl1IZZMW2TPUiY0rl6yaCh
BVXjM9W0r07QPnHZsUiByqb743adkbTUjmxdJzjaVtxN7ZXwZvOVrY7I7fPWYnCE
fXCr4+IVpZI/ZHZWpGX6CGSgT6EOjCZ5IUufIvEpqVSmtF8MqfXO9o9uIYLokrWQ
x1dBl5UnuTLDqw8bChq7O5y6yfuWaOWvL7nxI8NvSsfj4y635gIa/0dFeBYZEfHI
UlGdNVomwXwYEzgE/c19ruIowX7HU/NgxMWTMZhpazlxgesXybel+YNcfDQ4e3RM
OMz3ZFiaMaJsGGNf4++d9TmMgk4Ns6oDs6Tb9AECggEBAJYzd+SOYo26iBu3nw3L
65uEeh6xou8pXH0Tu4gQrPQTRZZ/nT3iNgOwqu1gRuxcq7TOjt41UdqIKO8vN7/A
aJavCpaKoIMowy/aGCbvAvjNPpU3unU8jdl/t08EXs79S5IKPcgAx87sTTi7KDN5
SYt4tr2uPEe53NTXuSatilG5QCyExIELOuzWAMKzg7CAiIlNS9foWeLyVkBgCQ6S
me/L8ta+mUDy37K6vC34jh9vK9yrwF6X44ItRoOJafCaVfGI+175q/eWcqTX4q+I
G4tKls4sL4mgOJLq+ra50aYMxbcuommctPMXU6CrrYyQpPTHMNVDQy2ttFdsq9iK
TncCggEBAMmt/8yvPflS+xv3kg/ZBvR9JB1In2n3rUCYYD47ReKFqJ03Vmq5C9nY
56s9w7OUO8perBXlJYmKZQhO4293lvxZD2Iq4NcZbVSCMoHAUzhzY3brdgtSIxa2
gGveGAezZ38qKIU26dkz7deECY4vrsRkwhpTW0LGVCpjcQoaKvymAoCmAs8V2oMr
Ziw1YQ9uOUoWwOqm1wZqmVcOXvPIS2gWAs3fQlWjH9hkcQTMsUaXQDOD0aqkSY3E
NqOvbCV1/oUpRi3076khCoAXI1bKSn/AvR3KDP14B5toHI/F5OTSEiGhhHesgRrs
fBrpEY1IATtPq1taBZZogRqI3rOkkPk=
-----END PRIVATE KEY-----

View file

@ -20,6 +20,17 @@
#include <signal.h>
static struct lws_context *context;
static uv_loop_t loop;
static int lifetime = 5, reported;
struct lws_context_creation_info info;
enum {
TEST_STATE_CREATE_LWS_CONTEXT,
TEST_STATE_DESTROY_LWS_CONTEXT,
TEST_STATE_EXIT
};
static int sequence = TEST_STATE_CREATE_LWS_CONTEXT;
static const struct lws_http_mount mount = {
/* .mount_next */ NULL, /* linked-list "next" */
@ -54,32 +65,66 @@ void signal_cb(uv_signal_t *watcher, int signum)
abort();
break;
}
lws_libuv_stop(context);
if (context)
lws_context_destroy(context);
}
/* this logs once a second to show that the foreign loop assets are working */
static void timer_cb(uv_timer_t *t)
static void
timer_cb(uv_timer_t *t)
{
void *foreign_loops[1];
foreign_loops[0] = &loop;
info.foreign_loops = foreign_loops;
lwsl_user("Foreign 1Hz timer\n");
if (sequence == TEST_STATE_EXIT && !context && !reported) {
/*
* at this point the lws_context_destroy() we did earlier
* has completed and the entire context is wholly destroyed
*/
lwsl_user("lws_destroy_context() completed, continuing for 5s\n");
reported = 1;
}
if (--lifetime)
return;
switch (sequence++) {
case TEST_STATE_CREATE_LWS_CONTEXT:
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return;
}
lwsl_user("LWS Context created and active for 10s\n");
lifetime = 11;
break;
case TEST_STATE_DESTROY_LWS_CONTEXT:
/* cleanup the lws part */
lwsl_user("Destroying lws context and continuing loop for 5s\n");
lws_context_destroy(context);
lifetime = 6;
break;
case TEST_STATE_EXIT:
lwsl_user("Deciding to exit foreign loop too\n");
uv_stop(&loop);
break;
default:
break;
}
}
static void lws_uv_close_cb(uv_handle_t *handle)
{
}
static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
{
lwsl_info("%s: closing foreign loop asset: %p (type %d)\n",
__func__, handle, handle->type);
uv_close(handle, lws_uv_close_cb);
}
int main(int argc, const char **argv)
{
struct lws_context_creation_info info;
uv_timer_t timer_outer;
uv_loop_t loop;
uv_signal_t sighandler;
const char *p;
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
/* for LLL_ verbosity above NOTICE to be built into lws,
@ -96,61 +141,58 @@ int main(int argc, const char **argv)
lwsl_user("LWS minimal http server libuv + foreign loop |"
" visit http://localhost:7681\n");
/*
* We prepare the info here, but don't use it until later in the
* timer callback, to demonstrate the independence of the foreign loop
* and lws.
*/
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.port = 7681;
info.mounts = &mount;
info.error_document_404 = "/404.html";
info.options = LWS_SERVER_OPTION_LIBUV;
info.pcontext = &context;
if (lws_cmdline_option(argc, argv, "-s")) {
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.ssl_cert_filepath = "localhost-100y.cert";
info.ssl_private_key_filepath = "localhost-100y.key";
}
info.pcontext = &context;
lwsl_user(" This app creates a uv loop with a timer + signalhandler, and\n");
lwsl_user(" performs a test in three phases:\n");
lwsl_user("\n");
lwsl_user(" 1) 5s: Runs the loop with just the timer\n");
lwsl_user(" 2) 10s: create an lws context serving on localhost:7681\n");
lwsl_user(" using the same uv loop. Destroy it after 10s.\n");
lwsl_user(" 3) 5s: Run the loop again with just the timer\n");
lwsl_user("\n");
lwsl_user(" Finally close only the timer and signalhandler and\n");
lwsl_user(" exit the loop cleanly\n");
/* we create and start our "foreign loop" */
uv_loop_init(&loop);
uv_signal_init(&loop, &sighandler);
uv_signal_start(&sighandler, signal_cb, SIGINT);
uv_timer_init(&loop, &timer_outer);
uv_timer_start(&timer_outer, timer_cb, 0, 1000);
context = lws_create_context(&info);
if (!context) {
lwsl_err("lws init failed\n");
return 1;
}
lws_uv_sigint_cfg(context, 1, signal_cb);
if (lws_uv_initloop(context, &loop, 0)) {
lwsl_err("lws_uv_initloop failed\n");
goto bail;
}
lws_libuv_run(context, 0);
bail:
lwsl_user("%s: starting exit cleanup...\n", __func__);
/* cleanup the lws part */
lws_context_destroy(context);
lws_context_destroy2(context);
/* cleanup the foreign loop part */
lwsl_user("%s: lws context destroyed: cleaning the foreign loop\n",
__func__);
/*
* Instead of walking to close all the foreign assets, it's also
* fine to close them individually instead as below
*/
// uv_timer_stop(&timer_outer);
// uv_close((uv_handle_t*)&timer_outer, NULL);
/* close every foreign loop asset unconditionally */
uv_walk(&loop, lws_uv_walk_cb, NULL);
/* let it run until everything completed close */
uv_run(&loop, UV_RUN_DEFAULT);
/* nothing left in the foreign loop, destroy it */
/* in the case we hit ^C while lws still exists */
lws_context_destroy(context);
/* cleanup the foreign loop assets */
uv_timer_stop(&timer_outer);
uv_close((uv_handle_t*)&timer_outer, NULL);
uv_signal_stop(&sighandler);
uv_close((uv_handle_t *)&sighandler, NULL);
uv_run(&loop, UV_RUN_DEFAULT);
uv_loop_close(&loop);
lwsl_user("%s: exiting...\n", __func__);

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.8)
include(CheckCSourceCompiles)
set(SAMP lws-minimal-http-server-libuv)
set(SRCS minimal-http-server.c)
set(SRCS minimal-http-server-libuv.c)
# If we are being built as part of lws, confirm current build config supports
# reqconfig, else skip building ourselves.
@ -76,4 +76,4 @@ if (requirements)
else()
target_link_libraries(${SAMP} websockets)
endif()
endif()
endif()

View file

@ -6,7 +6,8 @@
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* This demonstrates the most minimal http server you can make with lws.
* This demonstrates the most minimal http server you can make with lws using
* the libuv event loop.
*
* To keep it simple, it serves stuff from the subdirectory
* "./mount-origin" of the directory it was started in.
@ -39,8 +40,10 @@ static const struct lws_http_mount mount = {
/* .basic_auth_login_file */ NULL,
};
void signal_cb(uv_signal_t *watcher, int signum)
void signal_cb(void *handle, int signum)
{
uv_signal_t *watcher = (uv_signal_t *)handle;
lwsl_notice("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
@ -52,7 +55,7 @@ void signal_cb(uv_signal_t *watcher, int signum)
abort();
break;
}
lws_libuv_stop(context);
lws_context_destroy(context);
}
int main(int argc, const char **argv)
@ -83,6 +86,7 @@ int main(int argc, const char **argv)
info.ssl_private_key_filepath = "localhost-100y.key";
}
info.options |= LWS_SERVER_OPTION_LIBUV;
info.signal_cb = signal_cb;
context = lws_create_context(&info);
if (!context) {
@ -90,19 +94,9 @@ int main(int argc, const char **argv)
return 1;
}
lws_uv_sigint_cfg(context, 1, signal_cb);
lws_service(context, 0);
if (lws_uv_initloop(context, NULL, 0)) {
lwsl_err("lws_uv_initloop failed\n");
goto bail;
}
lws_libuv_run(context, 0);
bail:
lws_context_destroy(context);
lws_context_destroy2(context);
return 0;
}

View file

@ -52,10 +52,10 @@ struct per_session_data__server_status {
};
struct per_vhost_data__lws_server_status {
uv_timer_t timeout_watcher;
struct lws_context *context;
int hide_vhosts;
int tow_flag;
int period_us;
struct lws_ss_dumps d;
struct lws_ss_filepath *fp;
};
@ -63,15 +63,8 @@ struct per_vhost_data__lws_server_status {
static const struct lws_protocols protocols[1];
static void
uv_timeout_cb_server_status(uv_timer_t *w
#if UV_VERSION_MAJOR == 0
, int status
#endif
)
update(struct per_vhost_data__lws_server_status *v)
{
struct per_vhost_data__lws_server_status *v = lws_container_of(w,
struct per_vhost_data__lws_server_status,
timeout_watcher);
struct lws_ss_filepath *fp;
char *p = v->d.buf + LWS_PRE, contents[256], pure[256];
int n, l, first = 1, fd;
@ -135,12 +128,13 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
lws_protocol_vh_priv_get(lws_get_vhost(wsi),
lws_get_protocol(wsi));
struct lws_ss_filepath *fp, *fp1, **fp_old;
int m, period = 1000;
int m;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__);
lws_set_timer_usecs(wsi, v->period_us);
lws_callback_on_writable(wsi);
break;
@ -161,7 +155,9 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
if (!strcmp(pvo->name, "hide-vhosts"))
v->hide_vhosts = atoi(pvo->value);
if (!strcmp(pvo->name, "update-ms"))
period = atoi(pvo->value);
v->period_us = atoi(pvo->value) * 1000;
else
v->period_us = 5 * 1000 * 1000;
if (!strcmp(pvo->name, "filepath")) {
fp = malloc(sizeof(*fp));
fp->next = NULL;
@ -174,17 +170,12 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
pvo = pvo->next;
}
v->context = lws_get_context(wsi);
uv_timer_init(lws_uv_getloop(v->context, 0),
&v->timeout_watcher);
uv_timer_start(&v->timeout_watcher,
uv_timeout_cb_server_status, 2000, period);
break;
case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */
if (!v)
break;
uv_timer_stop(&v->timeout_watcher);
uv_close((uv_handle_t *)&v->timeout_watcher, NULL);
fp = v->fp;
while (fp) {
fp1= fp->next;
@ -200,6 +191,12 @@ callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason,
return -1;
break;
case LWS_CALLBACK_TIMER:
lws_set_timer_usecs(wsi, v->period_us);
update(v);
lws_callback_on_writable(wsi);
break;
default:
break;
}

View file

@ -198,6 +198,7 @@ int main(int argc, char **argv)
struct lws_context_creation_info info;
char interface_name[128] = "";
const char *iface = NULL;
void *foreign_loops[1];
char cert_path[1024];
char key_path[1024];
int use_ssl = 0;
@ -319,6 +320,9 @@ int main(int argc, char **argv)
info.uid = -1;
info.options = opts | LWS_SERVER_OPTION_LIBEV;
foreign_loops[0] = &loop;
info.foreign_loops = foreign_loops;
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
@ -335,8 +339,7 @@ int main(int argc, char **argv)
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
lws_ev_initloop(context, loop, 0);
ev_run(loop, 0);
lws_service(context, 0);
lws_context_destroy(context);

View file

@ -192,6 +192,7 @@ int main(int argc, char **argv)
struct event_base *event_base_loop = event_base_new();
struct lws_context_creation_info info;
char interface_name[128] = "";
void *foreign_loops[1];
const char *iface = NULL;
char cert_path[1024];
char key_path[1024];
@ -273,7 +274,8 @@ int main(int argc, char **argv)
#endif
for (n = 0; n < (int)ARRAY_SIZE(sigs); n++) {
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb, event_base_loop);
signals[n] = evsignal_new(event_base_loop, sigs[n], signal_cb,
event_base_loop);
evsignal_add(signals[n], NULL);
}
@ -315,9 +317,11 @@ int main(int argc, char **argv)
}
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 1;
info.options = opts | LWS_SERVER_OPTION_LIBEVENT;
foreign_loops[0] = event_base_loop;
info.foreign_loops = foreign_loops;
context = lws_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
@ -334,13 +338,11 @@ int main(int argc, char **argv)
/* override the active fops */
lws_get_fops(context)->open = test_server_fops_open;
// Don't use the default Signal Event Watcher & Handler
lws_event_sigint_cfg(context, 0, NULL);
// Initialize the LWS with libevent loop
lws_event_initloop(context, event_base_loop, 0);
event_base_dispatch(event_base_loop);
for (n = 0; n < (int)ARRAY_SIZE(sigs); n++)
event_free(signals[n]);
lws_context_destroy(context);
lwsl_notice("libwebsockets-test-server exited cleanly\n");

View file

@ -82,8 +82,10 @@ static const struct lws_extension exts[] = {
{ NULL, NULL, NULL /* terminator */ }
};
void signal_cb(uv_signal_t *watcher, int signum)
void signal_cb(void *handle, int signum)
{
uv_signal_t *watcher = (uv_signal_t *)handle;
lwsl_err("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
case SIGTERM:
@ -94,7 +96,7 @@ void signal_cb(uv_signal_t *watcher, int signum)
abort();
break;
}
lws_libuv_stop(context);
lws_context_destroy(context);
}
/*
@ -228,6 +230,11 @@ static void timer_close_cb(uv_handle_t *h)
h, h->loop->active_handles);
}
static void walk_cb(uv_handle_t *h, void *arg)
{
lwsl_err("%s: handle %p: type %d\n", __func__, h, h->type);
}
void outer_signal_cb(uv_signal_t *s, int signum)
{
lwsl_notice("Foreign loop got signal %d\n", signum);
@ -255,6 +262,7 @@ int main(int argc, char **argv)
const char *iface = NULL;
char cert_path[1024];
char key_path[1024];
void *foreign_loops[1];
int use_ssl = 0;
int opts = 0;
int n = 0;
@ -351,6 +359,7 @@ int main(int argc, char **argv)
info.protocols = protocols;
info.extensions = exts;
info.mounts = &mount;
info.pcontext = &context;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
@ -375,7 +384,6 @@ int main(int argc, char **argv)
}
info.gid = -1;
info.uid = -1;
info.max_http_header_pool = 16;
info.timeout_secs = 5;
info.options = opts | LWS_SERVER_OPTION_LIBUV;
@ -403,7 +411,11 @@ int main(int argc, char **argv)
uv_run(&loop, UV_RUN_DEFAULT);
/* timer will stop loop and we will get here */
}
foreign_loops[0] = &loop;
info.foreign_loops = foreign_loops;
} else
info.signal_cb = signal_cb;
#endif
context = lws_create_context(&info);
@ -412,25 +424,6 @@ int main(int argc, char **argv)
return -1;
}
lws_uv_sigint_cfg(context, 1, signal_cb);
#if UV_VERSION_MAJOR > 0
if (foreign_libuv_loop) {
/* we have our own uv loop outside of lws */
lws_uv_initloop(context, &loop, 0);
} else
#endif
{
/*
* lws will create his own libuv loop in the context
*/
if (lws_uv_initloop(context, NULL, 0)) {
lwsl_err("lws_uv_initloop failed\n");
goto bail;
}
}
#if UV_VERSION_MAJOR > 0
if (foreign_libuv_loop) {
/*
@ -462,7 +455,6 @@ int main(int argc, char **argv)
/* detach lws */
lws_context_destroy(context);
lws_context_destroy2(context);
lwsl_notice("Please wait while the outer libuv test continues for 10s\n");
@ -478,10 +470,13 @@ int main(int argc, char **argv)
* outside of lws */
uv_timer_stop(&timer_outer);
uv_timer_stop(&timer_test_cancel);
uv_close((uv_handle_t*)&timer_outer, timer_close_cb);
uv_timer_stop(&timer_test_cancel);
uv_close((uv_handle_t*)&timer_test_cancel, timer_close_cb);
uv_timer_stop(&timer_inner);
uv_close((uv_handle_t*)&timer_inner, timer_close_cb);
uv_signal_stop(&signal_outer);
uv_close((uv_handle_t*)&signal_outer, NULL);
e = 100;
while (e--)
@ -490,17 +485,21 @@ int main(int argc, char **argv)
/* PHASE 2: close the UV loop itself */
e = uv_loop_close(&loop);
lwsl_notice("uv loop close rc %s\n",
e ? uv_strerror(e) : "ok");
if (e) {
lwsl_notice("uv loop close rc %s\n", e ? uv_strerror(e) : "ok");
uv_walk(&loop, walk_cb, NULL);
}
} else
#endif
{
lws_libuv_run(context, 0);
lws_service(context, 0);
bail:
/*
* we can't destroy the internal loops while they are running
*/
lws_context_destroy(context);
lws_context_destroy2(context);
}
lwsl_notice("libwebsockets-test-server exited cleanly\n");

View file

@ -265,8 +265,10 @@ static const struct lws_protocol_vhost_options pvo = {
""
};
static void signal_cb(uv_signal_t *watcher, int signum)
static void signal_cb(void *handle, int signum)
{
uv_signal_t *watcher = (uv_signal_t *)handle;
lwsl_err("Signal %d caught, exiting...\n", watcher->signum);
switch (watcher->signum) {
case SIGTERM:
@ -277,7 +279,7 @@ static void signal_cb(uv_signal_t *watcher, int signum)
abort();
break;
}
lws_libuv_stop(context);
lws_context_destroy(context);
}
static const struct option options[] = {
@ -318,6 +320,7 @@ int main(int argc, char **argv)
char key_path[1024] = "";
char ca_path[1024] = "";
int uid = -1, gid = -1;
void *foreign_loops[1];
int use_ssl = 0;
uv_loop_t loop;
int opts = 0;
@ -507,6 +510,10 @@ int main(int argc, char **argv)
* our vhost
*/
info.pvo = &pvo;
info.signal_cb = signal_cb;
foreign_loops[0] = &loop;
info.foreign_loops = foreign_loops;
/*
* Since we used LWS_SERVER_OPTION_EXPLICIT_VHOSTS, this only creates
@ -534,19 +541,10 @@ int main(int argc, char **argv)
info.port++;
#endif
/* libuv event loop */
lws_uv_sigint_cfg(context, 1, signal_cb);
if (lws_uv_initloop(context, &loop, 0)) {
lwsl_err("lws_uv_initloop failed\n");
goto bail;
}
lws_service(context, 0);
lws_libuv_run(context, 0);
bail:
/* when we decided to exit the event loop */
lws_context_destroy(context);
lws_context_destroy2(context);
#if defined(TEST_DYNAMIC_VHOST)