diff --git a/lib/context.c b/lib/context.c index d638ff52..c85a4816 100644 --- a/lib/context.c +++ b/lib/context.c @@ -1721,6 +1721,10 @@ lws_vhost_destroy(struct lws_vhost *vh) * destroys the context itself, setting what was info.pcontext to NULL. */ +/* + * destroy the actual context itself + */ + static void lws_context_destroy3(struct lws_context *context) { @@ -1733,6 +1737,10 @@ lws_context_destroy3(struct lws_context *context) *pcontext_finalize = NULL; } +/* + * really start destroying things + */ + void lws_context_destroy2(struct lws_context *context) { @@ -1802,6 +1810,10 @@ lws_context_destroy2(struct lws_context *context) lws_context_destroy3(context); } +/* + * Begin the context takedown + */ + LWS_VISIBLE void lws_context_destroy(struct lws_context *context) { @@ -1909,6 +1921,22 @@ lws_context_destroy(struct lws_context *context) lws_plat_context_early_destroy(context); + /* + * We face two different needs depending if foreign loop or not. + * + * 1) If foreign loop, we really want to advance the destroy_context() + * past here, and block only for libuv-style async close completion. + * + * 2a) If poll, and we exited by ourselves and are calling a final + * destroy_context() outside of any service already, we want to + * advance all the way in one step. + * + * 2b) If poll, and we are reacting to a SIGINT, service thread(s) may + * be in poll wait or servicing. We can't advance the + * destroy_context() to the point it's freeing things; we have to + * leave that for the final destroy_context() after the service + * thread(s) are finished calling for service. + */ if (context->event_loop_ops->destroy_context1) { context->event_loop_ops->destroy_context1(context); @@ -1916,5 +1944,10 @@ lws_context_destroy(struct lws_context *context) return; } + if (!context->pt[0].event_loop_foreign) + for (n = 0; n < context->count_threads; n++) + if (context->pt[n].inside_service) + return; + lws_context_destroy2(context); } diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index a221201d..4ff58781 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -593,6 +593,7 @@ struct lws_context_per_thread { unsigned char tid; unsigned char lock_depth; + unsigned char inside_service:1; unsigned char event_loop_foreign:1; unsigned char event_loop_destroy_processing_done:1; }; diff --git a/lib/service.c b/lib/service.c index 39dba41c..8cf8c934 100644 --- a/lib/service.c +++ b/lib/service.c @@ -939,24 +939,49 @@ lws_service_fd(struct lws_context *context, struct lws_pollfd *pollfd) LWS_VISIBLE int lws_service(struct lws_context *context, int timeout_ms) { + struct lws_context_per_thread *pt = &context->pt[0]; + int n; + + if (!context) + return 1; + + pt->inside_service = 1; + if (context->event_loop_ops->run_pt) { /* we are configured for an event loop */ context->event_loop_ops->run_pt(context, 0); + pt->inside_service = 0; + return 1; } - return lws_plat_service(context, timeout_ms); + n = lws_plat_service(context, timeout_ms); + + pt->inside_service = 0; + + return n; } LWS_VISIBLE int lws_service_tsi(struct lws_context *context, int timeout_ms, int tsi) { + struct lws_context_per_thread *pt = &context->pt[tsi]; + int n; + + pt->inside_service = 1; + if (context->event_loop_ops->run_pt) { /* we are configured for an event loop */ context->event_loop_ops->run_pt(context, tsi); + pt->inside_service = 0; + return 1; } - return _lws_plat_service_tsi(context, timeout_ms, tsi); + n = _lws_plat_service_tsi(context, timeout_ms, tsi); + + pt->inside_service = 0; + + return n; }