context_destroy: figure out if anything still in event loop

This commit is contained in:
Andy Green 2018-05-02 19:27:29 +08:00
parent bce8cca042
commit 9cce1874b0
3 changed files with 61 additions and 2 deletions

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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;
}