{"schema":"libjg2-1",
"vpath":"/git/",
"avatar":"/git/avatar/",
"alang":"",
"gen_ut":1756756087,
"reponame":"libwebsockets",
"desc":"libwebsockets lightweight C networking library",
"owner": { "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"https://libwebsockets.org/repo/libwebsockets",
"f":3,
"items": [
{"schema":"libjg2-1",
"cid":"703a261dcbd84e8018fb2caa5b6879df",
"commit": {"type":"commit",
"time": 1522982283,
"time_ofs": 480,
"oid_tree": { "oid": "aad43959bdb64d2e1e136a8942e107cfa2862b47", "alias": []},
"oid":{ "oid": "caaf26c71721a41f4419e0a072bad666c2343adf", "alias": []},
"msg": "libuv: foreign loop detach doesn not require lws running the loop at all",
"sig_commit": { "git_time": { "time": 1522982283, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },
"sig_author": { "git_time": { "time": 1522412566, "offset": 480 }, "name": "Andy Green", "email": "andy@warmcat.com", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" }},
"body": "libuv: foreign loop detach doesn not require lws running the loop at all\n\nThis completely removes the loop self-running stuff.\n\nStatic allocations (uv_idle, timers etc) are referenced-counted in the context\nsame as the wsi are. When lws wants to close, he first closes all his wsi, then\nwhen that is completed in the uv close callbacks, he closes all of his static\nuv handles. When that is also completed in the uv callbacks, he stops the loop\nso the lws context can destroy and exit.\n\nAny direct libuv allocations in protocol handlers must participate in the\nreference counting. Two new apis are provided\n\n - lws_libuv_static_refcount_add(handle, context) to mark the handle with\n a pointer to the context and increment the global uv object counter\n\n - lws_libuv_static_refcount_del() which should be used as the close callback\n for your own libuv objects declared in the protocol scope."
,
"diff": "diff --git a/lib/context.c b/lib/context.c\nindex 3f45216..037f443 100644\n--- a/lib/context.c\n+++ b/lib/context.c\n@@ -1436,7 +1436,7 @@ LWS_VISIBLE void\n lws_context_destroy2(struct lws_context *context);\n \n \n-static void\n+void\n lws_vhost_destroy1(struct lws_vhost *vh)\n {\n \tconst struct lws_protocols *protocol \u003d NULL;\n@@ -1700,8 +1700,8 @@ LWS_VISIBLE void\n lws_context_destroy(struct lws_context *context)\n {\n \tvolatile struct lws_foreign_thread_pollfd *ftp, *next;\n-\tstruct lws_context_per_thread *pt;\n \tvolatile struct lws_context_per_thread *vpt;\n+\tstruct lws_context_per_thread *pt;\n \tstruct lws_vhost *vh \u003d NULL;\n \tstruct lws wsi;\n \tint n, m;\n@@ -1798,6 +1798,19 @@ lws_context_destroy(struct lws_context *context)\n \t}\n \tlws_plat_context_early_destroy(context);\n \n+#if defined(LWS_WITH_LIBUV)\n+\tif (LWS_LIBUV_ENABLED(context))\n+\t\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++) {\n+\t\t\tpt \u003d \u0026context-\u003ept[n];\n+\t\t\tif (!pt-\u003eev_loop_foreign) {\n+#if UV_VERSION_MAJOR \u003e 0\n+\t\t\t\tuv_loop_close(pt-\u003eio_loop_uv);\n+#endif\n+\t\t\t\tlws_free_set_NULL(pt-\u003eio_loop_uv);\n+\t\t\t}\n+\t\t}\n+#endif\n+\n \tif (context-\u003ept[0].fds)\n \t\tlws_free_set_NULL(context-\u003ept[0].fds);\n \ndiff --git a/lib/event-libs/libuv.c b/lib/event-libs/libuv.c\nindex 77138e5..f84ed45 100644\n--- a/lib/event-libs/libuv.c\n+++ b/lib/event-libs/libuv.c\n@@ -240,6 +240,8 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)\n \n \t\tpt-\u003eio_loop_uv \u003d loop;\n \t\tuv_idle_init(loop, \u0026pt-\u003euv_idle);\n+\t\tLWS_UV_REFCOUNT_STATIC_HANDLE_NEW(\u0026pt-\u003euv_idle, context);\n+\n \n \t\tns \u003d ARRAY_SIZE(sigs);\n \t\tif (lws_check_opt(context-\u003eoptions,\n@@ -250,6 +252,8 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)\n \t\t\tassert(ns \u003c\u003d (int)ARRAY_SIZE(pt-\u003esignals));\n \t\t\tfor (n \u003d 0; n \u003c ns; n++) {\n \t\t\t\tuv_signal_init(loop, \u0026pt-\u003esignals[n]);\n+\t\t\t\tLWS_UV_REFCOUNT_STATIC_HANDLE_NEW(\u0026pt-\u003esignals[n],\n+\t\t\t\t\t\t\t\t context);\n \t\t\t\tpt-\u003esignals[n].data \u003d pt-\u003econtext;\n \t\t\t\tuv_signal_start(\u0026pt-\u003esignals[n],\n \t\t\t\t\t\tcontext-\u003elws_uv_sigint_cb,\n@@ -275,12 +279,14 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)\n \t\tvh \u003d vh-\u003evhost_next;\n \t}\n \n-\tif (first) {\n-\t\tuv_timer_init(pt-\u003eio_loop_uv, \u0026pt-\u003euv_timeout_watcher);\n-\t\tuv_timer_start(\u0026pt-\u003euv_timeout_watcher, lws_uv_timeout_cb,\n-\t\t\t 10, 1000);\n-\t\tuv_timer_init(pt-\u003eio_loop_uv, \u0026pt-\u003euv_hrtimer);\n-\t}\n+\tif (!first)\n+\t\treturn status;\n+\n+\tuv_timer_init(pt-\u003eio_loop_uv, \u0026pt-\u003euv_timeout_watcher);\n+\tLWS_UV_REFCOUNT_STATIC_HANDLE_NEW(\u0026pt-\u003euv_timeout_watcher, context);\n+\tuv_timer_start(\u0026pt-\u003euv_timeout_watcher, lws_uv_timeout_cb, 10, 1000);\n+\tuv_timer_init(pt-\u003eio_loop_uv, \u0026pt-\u003euv_hrtimer);\n+\tLWS_UV_REFCOUNT_STATIC_HANDLE_NEW(\u0026pt-\u003euv_hrtimer, context);\n \n \treturn status;\n \n@@ -288,6 +294,73 @@ bail:\n \treturn -1;\n }\n \n+/*\n+ * Closing Phase 2: Close callback for a static UV asset\n+ */\n+\n+static void\n+lws_uv_close_cb_sa(uv_handle_t *handle)\n+{\n+\tstruct lws_context *context \u003d\n+\t\t\tLWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(handle);\n+\tint n;\n+\n+\tlwsl_info(\u0022%s: sa left %d: dyn left: %d\u005cn\u0022, __func__,\n+\t\t context-\u003euv_count_static_asset_handles,\n+\t\t context-\u003ecount_wsi_allocated);\n+\n+\t/* any static assets left? */\n+\n+\tif (LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(handle) ||\n+\t context-\u003ecount_wsi_allocated)\n+\t\treturn;\n+\n+\t/*\n+\t * That's it... all wsi were down, and now every\n+\t * static asset lws had a UV handle for is down.\n+\t *\n+\t * Stop the loop so we can get out of here.\n+\t */\n+\n+\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++) {\n+\t\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[n];\n+\n+\t\tif (!pt-\u003eio_loop_uv || !LWS_LIBUV_ENABLED(context))\n+\t\t\tcontinue;\n+\n+\t\tuv_stop(pt-\u003eio_loop_uv);\n+\n+\t\t/*\n+\t\t * we can't delete non-foreign loop here, because\n+\t\t * the uv_stop() hasn't got us out of the uv_run()\n+\t\t * yet. So we do it in context destroy.\n+\t\t */\n+\t}\n+}\n+\n+/*\n+ * These must be called by protocols that want to use libuv objects directly...\n+ *\n+ * .... when the libuv object is created...\n+ */\n+\n+LWS_VISIBLE void\n+lws_libuv_static_refcount_add(uv_handle_t *h, struct lws_context *context)\n+{\n+\tLWS_UV_REFCOUNT_STATIC_HANDLE_NEW(h, context);\n+}\n+\n+/*\n+ * ... and in the close callback when the object is closed.\n+ */\n+\n+LWS_VISIBLE void\n+lws_libuv_static_refcount_del(uv_handle_t *h)\n+{\n+\treturn lws_uv_close_cb_sa(h);\n+}\n+\n+\n static void lws_uv_close_cb(uv_handle_t *handle)\n {\n }\n@@ -308,7 +381,9 @@ void\n lws_libuv_destroyloop(struct lws_context *context, int tsi)\n {\n \tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[tsi];\n-\tint m, budget \u003d 100, ns;\n+\tint m, /* budget \u003d 100, */ ns;\n+\n+\tlwsl_info(\u0022%s: %d\u005cn\u0022, __func__, tsi);\n \n \tif (!lws_check_opt(context-\u003eoptions, LWS_SERVER_OPTION_LIBUV))\n \t\treturn;\n@@ -316,6 +391,11 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)\n \tif (!pt-\u003eio_loop_uv)\n \t\treturn;\n \n+\tif (pt-\u003eevent_loop_destroy_processing_done)\n+\t\treturn;\n+\n+\tpt-\u003eevent_loop_destroy_processing_done \u003d 1;\n+\n \tif (context-\u003euse_ev_sigint) {\n \t\tuv_signal_stop(\u0026pt-\u003ew_sigint.uv_watcher);\n \n@@ -326,34 +406,17 @@ lws_libuv_destroyloop(struct lws_context *context, int tsi)\n \n \t\tfor (m \u003d 0; m \u003c ns; m++) {\n \t\t\tuv_signal_stop(\u0026pt-\u003esignals[m]);\n-\t\t\tuv_close((uv_handle_t *)\u0026pt-\u003esignals[m], lws_uv_close_cb);\n+\t\t\tuv_close((uv_handle_t *)\u0026pt-\u003esignals[m], lws_uv_close_cb_sa);\n \t\t}\n \t}\n \n \tuv_timer_stop(\u0026pt-\u003euv_timeout_watcher);\n-\tuv_close((uv_handle_t *)\u0026pt-\u003euv_timeout_watcher, lws_uv_close_cb);\n+\tuv_close((uv_handle_t *)\u0026pt-\u003euv_timeout_watcher, lws_uv_close_cb_sa);\n \tuv_timer_stop(\u0026pt-\u003euv_hrtimer);\n-\tuv_close((uv_handle_t *)\u0026pt-\u003euv_hrtimer, lws_uv_close_cb);\n+\tuv_close((uv_handle_t *)\u0026pt-\u003euv_hrtimer, lws_uv_close_cb_sa);\n \n \tuv_idle_stop(\u0026pt-\u003euv_idle);\n-\tuv_close((uv_handle_t *)\u0026pt-\u003euv_idle, lws_uv_close_cb);\n-\n-\twhile (budget-- \u0026\u0026 uv_run(pt-\u003eio_loop_uv, UV_RUN_NOWAIT))\n-\t\t;\n-\n-\tif (pt-\u003eev_loop_foreign)\n-\t\treturn;\n-\n-\tuv_stop(pt-\u003eio_loop_uv);\n-\tuv_walk(pt-\u003eio_loop_uv, lws_uv_walk_cb, NULL);\n-\twhile (uv_run(pt-\u003eio_loop_uv, UV_RUN_NOWAIT))\n-\t\t;\n-#if UV_VERSION_MAJOR \u003e 0\n-\tm \u003d uv_loop_close(pt-\u003eio_loop_uv);\n-\tif (m \u003d\u003d UV_EBUSY)\n-\t\tlwsl_err(\u0022%s: uv_loop_close: UV_EBUSY\u005cn\u0022, __func__);\n-#endif\n-\tlws_free(pt-\u003eio_loop_uv);\n+\tuv_close((uv_handle_t *)\u0026pt-\u003euv_idle, lws_uv_close_cb_sa);\n }\n \n void\n@@ -456,15 +519,75 @@ lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)\n \t\tuv_stop(context-\u003ept[tsi].io_loop_uv);\n }\n \n+\n+\n+LWS_VISIBLE uv_loop_t *\n+lws_uv_getloop(struct lws_context *context, int tsi)\n+{\n+\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n+\t\treturn context-\u003ept[tsi].io_loop_uv;\n+\n+\treturn NULL;\n+}\n+\n static void\n-lws_libuv_kill(const struct lws_context *context)\n+lws_libuv_closewsi(uv_handle_t* handle)\n {\n-\tint n;\n+\tstruct lws *n \u003d NULL, *wsi \u003d (struct lws *)(((char *)handle) -\n+\t\t\t (char *)(\u0026n-\u003ew_read.uv_watcher));\n+\tstruct lws_context *context \u003d lws_get_context(wsi);\n+\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n+\tint lspd \u003d 0, m;\n \n-\tfor (n \u003d 0; n \u003c context-\u003ecount_threads; n++)\n-\t\tif (context-\u003ept[n].io_loop_uv \u0026\u0026\n-\t\t LWS_LIBUV_ENABLED(context))\n-\t\t\tuv_stop(context-\u003ept[n].io_loop_uv);\n+\t/*\n+\t * We get called back here for every wsi that closes\n+\t */\n+\n+\tif (wsi-\u003emode \u003d\u003d LWSCM_SERVER_LISTENER \u0026\u0026\n+\t wsi-\u003econtext-\u003edeprecated) {\n+\t\tlspd \u003d 1;\n+\t\tcontext-\u003edeprecation_pending_listen_close_count--;\n+\t\tif (!context-\u003edeprecation_pending_listen_close_count)\n+\t\t\tlspd \u003d 2;\n+\t}\n+\n+\tlws_pt_lock(pt, __func__);\n+\t__lws_close_free_wsi_final(wsi);\n+\tlws_pt_unlock(pt);\n+\n+\tif (lspd \u003d\u003d 2 \u0026\u0026 context-\u003edeprecation_cb) {\n+\t\tlwsl_notice(\u0022calling deprecation callback\u005cn\u0022);\n+\t\tcontext-\u003edeprecation_cb();\n+\t}\n+\n+\tlwsl_info(\u0022%s: sa left %d: dyn left: %d\u005cn\u0022, __func__,\n+\t\t context-\u003euv_count_static_asset_handles,\n+\t\t context-\u003ecount_wsi_allocated);\n+\n+\t/*\n+\t * eventually, we closed all the wsi...\n+\t */\n+\n+\tif (context-\u003erequested_kill \u0026\u0026 !context-\u003ecount_wsi_allocated) {\n+\t\tstruct lws_vhost *vh \u003d context-\u003evhost_list;\n+\n+\t\t/*\n+\t\t * Start Closing Phase 2: close of static handles\n+\t\t */\n+\n+\t\tlwsl_info(\u0022%s: all lws dynamic handles down, closing static\u005cn\u0022,\n+\t\t\t __func__);\n+\n+\t\tfor (m \u003d 0; m \u003c context-\u003ecount_threads; m++)\n+\t\t\tlws_libuv_destroyloop(context, m);\n+\n+\t\t/* protocols may have initialized libuv objects */\n+\n+\t\twhile (vh) {\n+\t\t\tlws_vhost_destroy1(vh);\n+\t\t\tvh \u003d vh-\u003evhost_next;\n+\t\t}\n+\t}\n }\n \n /*\n@@ -487,6 +610,10 @@ lws_libuv_stop(struct lws_context *context)\n \tm \u003d context-\u003ecount_threads;\n \tcontext-\u003ebeing_destroyed \u003d 1;\n \n+\t/*\n+\t * Phase 1: start the close of every dynamic uv handle\n+\t */\n+\n \twhile (m--) {\n \t\tpt \u003d \u0026context-\u003ept[m];\n \n@@ -503,59 +630,15 @@ lws_libuv_stop(struct lws_context *context)\n \t}\n \n \tlwsl_info(\u0022%s: started closing all wsi\u005cn\u0022, __func__);\n-\tif (context-\u003ecount_wsi_allocated \u003d\u003d 0)\n-\t\tlws_libuv_kill(context);\n-}\n-\n-LWS_VISIBLE uv_loop_t *\n-lws_uv_getloop(struct lws_context *context, int tsi)\n-{\n-\tif (context-\u003ept[tsi].io_loop_uv \u0026\u0026 LWS_LIBUV_ENABLED(context))\n-\t\treturn context-\u003ept[tsi].io_loop_uv;\n-\n-\treturn NULL;\n-}\n-\n-static void\n-lws_libuv_closewsi(uv_handle_t* handle)\n-{\n-\tstruct lws *n \u003d NULL, *wsi \u003d (struct lws *)(((char *)handle) -\n-\t\t\t (char *)(\u0026n-\u003ew_read.uv_watcher));\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\tstruct lws_context_per_thread *pt \u003d \u0026context-\u003ept[(int)wsi-\u003etsi];\n-\tint lspd \u003d 0;\n-\n-\tif (wsi-\u003emode \u003d\u003d LWSCM_SERVER_LISTENER \u0026\u0026\n-\t wsi-\u003econtext-\u003edeprecated) {\n-\t\tlspd \u003d 1;\n-\t\tcontext-\u003edeprecation_pending_listen_close_count--;\n-\t\tif (!context-\u003edeprecation_pending_listen_close_count)\n-\t\t\tlspd \u003d 2;\n-\t}\n-\n-\tlws_pt_lock(pt, __func__);\n-\t__lws_close_free_wsi_final(wsi);\n-\tlws_pt_unlock(pt);\n \n-\tif (lspd \u003d\u003d 2 \u0026\u0026 context-\u003edeprecation_cb) {\n-\t\tlwsl_notice(\u0022calling deprecation callback\u005cn\u0022);\n-\t\tcontext-\u003edeprecation_cb();\n-\t}\n-\n-\tif (context-\u003erequested_kill \u0026\u0026 context-\u003ecount_wsi_allocated \u003d\u003d 0)\n-\t\tlws_libuv_kill(context);\n+\t/* we cannot have completed... there are at least the cancel pipes */\n }\n \n void\n lws_libuv_closehandle(struct lws *wsi)\n {\n-\tstruct lws_context *context \u003d lws_get_context(wsi);\n-\n \t/* required to defer actual deletion until libuv has processed it */\n \tuv_close((uv_handle_t*)\u0026wsi-\u003ew_read.uv_watcher, lws_libuv_closewsi);\n-\n-\tif (context-\u003erequested_kill \u0026\u0026 context-\u003ecount_wsi_allocated \u003d\u003d 0)\n-\t\tlws_libuv_kill(context);\n }\n \n static void\ndiff --git a/lib/libwebsockets.h b/lib/libwebsockets.h\nindex 119eee7..6e8ee44 100644\n--- a/lib/libwebsockets.h\n+++ b/lib/libwebsockets.h\n@@ -4506,6 +4506,29 @@ lws_uv_sigint_cb(uv_signal_t *watcher, int signum);\n \n LWS_VISIBLE LWS_EXTERN void\n lws_close_all_handles_in_loop(uv_loop_t *loop);\n+\n+/*\n+ * Any direct libuv allocations in protocol handlers must participate in the\n+ * lws reference counting scheme. Two apis are provided:\n+ *\n+ * - lws_libuv_static_refcount_add(handle, context) to mark the handle with\n+ * a pointer to the context and increment the global uv object counter\n+ *\n+ * - lws_libuv_static_refcount_del() which should be used as the close callback\n+ * for your own libuv objects declared in the protocol scope.\n+ *\n+ * See the dumb increment plugin for an example of how to use them.\n+ *\n+ * Using the apis allows lws to detach itself from a libuv loop completely\n+ * cleanly and at the moment all of its libuv objects have completed close.\n+ */\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_libuv_static_refcount_add(uv_handle_t *, struct lws_context *context);\n+\n+LWS_VISIBLE LWS_EXTERN void\n+lws_libuv_static_refcount_del(uv_handle_t *);\n+\n #endif /* LWS_WITH_LIBUV */\n ///@}\n \ndiff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h\nindex 196724c..6558273 100644\n--- a/lib/private-libwebsockets.h\n+++ b/lib/private-libwebsockets.h\n@@ -854,6 +854,7 @@ struct lws_context_per_thread {\n #if defined(LWS_WITH_LIBEV) || defined(LWS_WITH_LIBUV) || defined(LWS_WITH_LIBEVENT)\n \tstruct lws_signal_watcher w_sigint;\n \tunsigned char ev_loop_foreign:1;\n+\tunsigned char event_loop_destroy_processing_done:1;\n #endif\n \n \tunsigned long count_conns;\n@@ -1058,6 +1059,25 @@ struct lws_peer {\n };\n #endif\n \n+#if defined(LWS_WITH_LIBUV)\n+/*\n+ * All \u0022static\u0022 (per-pt or per-context) uv handles must\n+ *\n+ * - have their .data set to point to the context\n+ *\n+ * - contribute to context-\u003euv_count_static_asset_handles\n+ * counting\n+ */\n+#define LWS_UV_REFCOUNT_STATIC_HANDLE_NEW(_x, _ctx) \u005c\n+\t\t{ uv_handle_t *_uht \u003d (uv_handle_t *)(_x); _uht-\u003edata \u003d _ctx; \u005c\n+\t\t_ctx-\u003euv_count_static_asset_handles++; }\n+#define LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x) \u005c\n+\t\t((struct lws_context *)((uv_handle_t *)((_x)-\u003edata)))\n+#define LWS_UV_REFCOUNT_STATIC_HANDLE_DESTROYED(_x) \u005c\n+\t\t(--(LWS_UV_REFCOUNT_STATIC_HANDLE_TO_CONTEXT(_x)-\u003e \u005c\n+\t\t\t\tuv_count_static_asset_handles))\n+#endif\n+\n /*\n * the rest is managed per-context, that includes\n *\n@@ -1121,6 +1141,7 @@ struct lws_context {\n #if defined(LWS_WITH_LIBUV)\n \tuv_signal_cb lws_uv_sigint_cb;\n \tuv_loop_t pu_loop;\n+\tint uv_count_static_asset_handles;\n #endif\n #if defined(LWS_WITH_LIBEVENT)\n #if defined(LWS_HIDE_LIBEVENT)\n@@ -1226,6 +1247,8 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd);\n int\n lws_jws_base64_enc(const char *in, size_t in_len, char *out, size_t out_max);\n \n+void\n+lws_vhost_destroy1(struct lws_vhost *vh);\n \n enum {\n \tLWS_EV_READ \u003d (1 \u003c\u003c 0),\ndiff --git a/plugins/protocol_dumb_increment.c b/plugins/protocol_dumb_increment.c\nindex e935bf4..8af2edd 100644\n--- a/plugins/protocol_dumb_increment.c\n+++ b/plugins/protocol_dumb_increment.c\n@@ -76,6 +76,8 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,\n \n \t\tuv_timer_init(lws_uv_getloop(vhd-\u003econtext, 0),\n \t\t\t \u0026vhd-\u003etimeout_watcher);\n+\t\tlws_libuv_static_refcount_add((uv_handle_t *)\u0026vhd-\u003etimeout_watcher,\n+\t\t\t\tvhd-\u003econtext);\n \t\tuv_timer_start(\u0026vhd-\u003etimeout_watcher,\n \t\t\t uv_timeout_cb_dumb_increment, DUMB_PERIOD, DUMB_PERIOD);\n \n@@ -86,7 +88,8 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason,\n \t\t\tbreak;\n \t\tlwsl_notice(\u0022di: LWS_CALLBACK_PROTOCOL_DESTROY: v\u003d%p, ctx\u003d%p\u005cn\u0022, vhd, vhd-\u003econtext);\n \t\tuv_timer_stop(\u0026vhd-\u003etimeout_watcher);\n-\t\tuv_close((uv_handle_t *)\u0026vhd-\u003etimeout_watcher, NULL);\n+\t\tuv_close((uv_handle_t *)\u0026vhd-\u003etimeout_watcher,\n+\t\t\t\t\tlws_libuv_static_refcount_del);\n \t\tbreak;\n \n \tcase LWS_CALLBACK_ESTABLISHED:\ndiff --git a/test-apps/test-server-libuv.c b/test-apps/test-server-libuv.c\nindex 5aecfa6..c4612e5 100644\n--- a/test-apps/test-server-libuv.c\n+++ b/test-apps/test-server-libuv.c\n@@ -190,16 +190,6 @@ void outer_signal_cb(uv_signal_t *s, int signum)\n \tuv_stop(s-\u003eloop);\n }\n \n-static void lws_uv_close_cb(uv_handle_t *handle)\n-{\n-\t//lwsl_err(\u0022%s\u005cn\u0022, __func__);\n-}\n-\n-static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)\n-{\n-\tuv_close(handle, lws_uv_close_cb);\n-}\n-\n /* --- end of foreign test code ---- */\n #endif\n \n@@ -426,15 +416,14 @@ int main(int argc, char **argv)\n \t\t/* we are here either because signal stopped us,\n \t\t * or outer timer expired */\n \n-\t\t/* close short timer */\n+\t\t/* stop short timer */\n \t\tuv_timer_stop(\u0026timer_inner);\n-\t\tuv_close((uv_handle_t*)\u0026timer_inner, timer_close_cb);\n-\n \n \t\tlwsl_notice(\u0022Destroying lws context\u005cn\u0022);\n \n \t\t/* detach lws */\n \t\tlws_context_destroy(context);\n+\t\tlws_context_destroy2(context);\n \n \t\tlwsl_notice(\u0022Please wait while the outer libuv test continues for 10s\u005cn\u0022);\n \n@@ -452,29 +441,19 @@ int main(int argc, char **argv)\n \t\tuv_timer_stop(\u0026timer_outer);\n \t\tuv_timer_stop(\u0026timer_test_cancel);\n \t\tuv_close((uv_handle_t*)\u0026timer_outer, timer_close_cb);\n+\t\tuv_close((uv_handle_t*)\u0026timer_inner, timer_close_cb);\n \t\tuv_signal_stop(\u0026signal_outer);\n \n \t\te \u003d 100;\n \t\twhile (e--)\n \t\t\tuv_run(\u0026loop, UV_RUN_NOWAIT);\n \n-\t\t/* PHASE 2: close anything remaining */\n-\n-\t\tuv_walk(\u0026loop, lws_uv_walk_cb, NULL);\n-\n-\t\te \u003d 100;\n-\t\twhile (e--)\n-\t\t\tuv_run(\u0026loop, UV_RUN_NOWAIT);\n-\n-\t\t/* PHASE 3: close the UV loop itself */\n+\t\t/* PHASE 2: close the UV loop itself */\n \n \t\te \u003d uv_loop_close(\u0026loop);\n \t\tlwsl_notice(\u0022uv loop close rc %s\u005cn\u0022,\n \t\t\t e ? uv_strerror(e) : \u0022ok\u0022);\n \n-\t\t/* PHASE 4: finalize context destruction */\n-\n-\t\tlws_context_destroy2(context);\n \t} else\n #endif\n \t{\ndiff --git a/test-apps/test-server-v2.0.c b/test-apps/test-server-v2.0.c\nindex ae81b47..1531bea 100644\n--- a/test-apps/test-server-v2.0.c\n+++ b/test-apps/test-server-v2.0.c\n@@ -324,6 +324,7 @@ int main(int argc, char **argv)\n \tchar ca_path[1024] \u003d \u0022\u0022;\n \tint uid \u003d -1, gid \u003d -1;\n \tint use_ssl \u003d 0;\n+\tuv_loop_t loop;\n \tint opts \u003d 0;\n \tint n \u003d 0;\n #ifndef _WIN32\n@@ -433,14 +434,18 @@ int main(int argc, char **argv)\n \topenlog(\u0022lwsts\u0022, syslog_options, LOG_DAEMON);\n #endif\n \n-\t/* tell the library what debug level to emit and to send it to syslog */\n-\tlws_set_log_level(debug_level, lwsl_emit_syslog);\n+\t/* tell the library what debug level to emit */\n+\tlws_set_log_level(debug_level, NULL);\n \n \tlwsl_notice(\u0022libwebsockets test server - license LGPL2.1+SLE\u005cn\u0022);\n \tlwsl_notice(\u0022(C) Copyright 2010-2017 Andy Green \u003candy@warmcat.com\u003e\u005cn\u0022);\n \n \tlwsl_notice(\u0022 Using resource path \u005c\u0022%s\u005c\u0022\u005cn\u0022, resource_path);\n \n+\tuv_loop_init(\u0026loop);\n+#if defined(TEST_DYNAMIC_VHOST)\n+\tuv_timer_init(\u0026loop, \u0026timeout_watcher);\n+#endif\n \tinfo.iface \u003d iface;\n \tinfo.protocols \u003d NULL; /* all protocols from lib / plugins */\n \tinfo.ssl_cert_filepath \u003d NULL;\n@@ -534,25 +539,31 @@ int main(int argc, char **argv)\n \n \t/* libuv event loop */\n \tlws_uv_sigint_cfg(context, 1, signal_cb);\n-\tif (lws_uv_initloop(context, NULL, 0)) {\n+\tif (lws_uv_initloop(context, \u0026loop, 0)) {\n \t\tlwsl_err(\u0022lws_uv_initloop failed\u005cn\u0022);\n \t\tgoto bail;\n \t}\n \n-#if defined(TEST_DYNAMIC_VHOST)\n-\tuv_timer_init(lws_uv_getloop(context, 0), \u0026timeout_watcher);\n-#endif\n \tlws_libuv_run(context, 0);\n \n+bail:\n+\t/* when we decided to exit the event loop */\n+\tlws_context_destroy(context);\n+\tlws_context_destroy2(context);\n+\n+\n #if defined(TEST_DYNAMIC_VHOST)\n \tuv_timer_stop(\u0026timeout_watcher);\n \tuv_close((uv_handle_t *)\u0026timeout_watcher, NULL);\n+\n+\t/* let it run until everything completed close */\n+\tuv_run(\u0026loop, UV_RUN_DEFAULT);\n #endif\n \n-bail:\n-\t/* when we decided to exit the event loop */\n-\tlws_context_destroy(context);\n-\tlws_context_destroy2(context);\n+\t/* nothing left in the foreign loop, destroy it */\n+\n+\tuv_loop_close(\u0026loop);\n+\n \tlwsl_notice(\u0022libwebsockets-test-server exited cleanly\u005cn\u0022);\n \n #ifndef _WIN32\n","s":{"c":1756756087,"u": 12187}}
],"g": 13679,"chitpc": 0,"ehitpc": 0,"indexed":0
,
"ab": 0, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}