diff --git a/.gitignore b/.gitignore
index a030dbaaba389204f17dbd8b07d90a643313313e..d2b3e444f6baef80d483dcf7091b7b21eead9d59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
\ No newline at end of file
+doc
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3c6cd9fd3809e54f5c6ee5286c6592f711785a54..8903a49e0d19c638d00da0f7aa5dd9817f75a98b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/lib/context.c b/lib/context.c
index c7657153809dfafd3c7d08b348130d4240e666ff..33069988bfa3e64c2ea4202457505c43b88fd52a 100644
--- a/lib/context.c
+++ b/lib/context.c
@@ -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);
-}
-
-/*
- * 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;
-	}
-
-	/* 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);
+	if (context->event_loop_ops->destroy_context1) {
+		context->event_loop_ops->destroy_context1(context);
 
-
-	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);
+		return;
 	}
-	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);
 }
diff --git a/lib/event-libs/libev/libev.c b/lib/event-libs/libev/libev.c
index bc18683ddb1070c56a91d6123fa77c9899e0d4a7..2ec6d6f5c5d2261d94f60a2fbaad57f491a9cf94 100644
--- a/lib/event-libs/libev/libev.c
+++ b/lib/event-libs/libev/libev.c
@@ -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)
 {
-	ev_break(loop, EVBREAK_ALL);
-}
+	struct lws_context *context = watcher->data;
 
-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;
+	if (context->eventlib_signal_cb) {
+		context->eventlib_signal_cb((void *)watcher, watcher->signum);
 
-	return 0;
+		return;
+	}
+	ev_break(loop, EVBREAK_ALL);
 }
 
-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 fd;
+	int n;
 
-	if (!LWS_LIBEV_ENABLED(context))
-		return;
+	context->eventlib_signal_cb = info->signal_cb;
 
-	if (new_wsi->role_ops == &role_ops_raw_file)
-		fd = desc.filefd;
+	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 (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,
+};
diff --git a/lib/event-libs/libev/private.h b/lib/event-libs/libev/private.h
index eeec24b9ac823bc4d6028307e823721956b19f5e..12f1d9f64bb1a5cb6ea1bd6c6dc8b26920d22b6f 100644
--- a/lib/event-libs/libev/private.h
+++ b/lib/event-libs/libev/private.h
@@ -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);
diff --git a/lib/event-libs/libevent/libevent.c b/lib/event-libs/libevent/libevent.c
index 34069ac0615d198bd155642672452ea390902460..53c4bf95fe78f900e87d76abd077d95bdd98a704 100644
--- a/lib/event-libs/libevent/libevent.c
+++ b/lib/event-libs/libevent/libevent.c
@@ -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;
-
-	if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBEVENT))
-		return;
+	int n;
 
-	if (!pt->event.io_loop)
-		return;
+	context->eventlib_signal_cb = info->signal_cb;
 
-	/*
-	 * 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;
-	}
+	for (n = 0; n < context->count_threads; n++)
+		context->pt[n].w_sigint.context = context;
 
-	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;
-
-	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);
-}
+		fd = wsi->desc.sockfd;
 
-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);
+	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_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)
+static void
+elops_run_pt_event(struct lws_context *context, int tsi)
 {
-	int n;
+	/* 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);
+}
 
-	if (!LWS_LIBEVENT_ENABLED(context))
-		return 0;
+static void
+elops_destroy_pt_event(struct lws_context *context, int tsi)
+{
+	struct lws_context_per_thread *pt = &context->pt[tsi];
+	struct lws_vhost *vh = context->vhost_list;
 
-	for (n = 0; n < context->count_threads; n++)
-		context->pt[n].w_sigint.context = context;
+	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;
+	}
 
-	return 1;
+	if (!pt->event_loop_foreign)
+		event_free(pt->w_sigint.event.watcher);
+	if (!pt->event_loop_foreign)
+		event_base_free(pt->event.io_loop);
 }
 
-LWS_VISIBLE void
-lws_libevent_run(const struct lws_context *context, int tsi)
+static void
+elops_destroy_wsi_event(struct lws *wsi)
 {
-	/* 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);
+	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,
+};
diff --git a/lib/event-libs/libevent/private.h b/lib/event-libs/libevent/private.h
index 00cdcbb5fd8cc6a58b5c46709533d9b5cdc4f392..4715bc2a4c732b0971f7ae1ebb122f1405260a22 100644
--- a/lib/event-libs/libevent/private.h
+++ b/lib/event-libs/libevent/private.h
@@ -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;
 };
 
+#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_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);
+lws_feature_status_libevent(const struct lws_context_creation_info *info);
 
diff --git a/lib/event-libs/libuv/libuv.c b/lib/event-libs/libuv/libuv.c
index 8b89869d5a708f3282a67ccbbf4b6f975ca4c2b6..b8990502f9980f6879cd4ec8515804c6272c1fc6 100644
--- a/lib/event-libs/libuv/libuv.c
+++ b/lib/event-libs/libuv/libuv.c
@@ -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);
+		if (pt->uv.io_loop && !pt->event_loop_foreign)
+			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 (!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,300 +305,43 @@ 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);
+LWS_VISIBLE void
+lws_libuv_stop_without_kill(const struct lws_context *context, int tsi)
+{
+	if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
+		uv_stop(context->pt[tsi].uv.io_loop);
+}
 
-		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);
+LWS_VISIBLE uv_loop_t *
+lws_uv_getloop(struct lws_context *context, int tsi)
+{
+	if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
+		return context->pt[tsi].uv.io_loop;
 
-	uv_idle_stop(&pt->uv.idle);
-	uv_close((uv_handle_t *)&pt->uv.idle, lws_uv_close_cb_sa);
+	return NULL;
 }
 
-void
-lws_libuv_accept(struct lws *wsi, lws_sock_file_fd_type desc)
+static void
+lws_libuv_closewsi_m(uv_handle_t* handle)
 {
-	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;
+	lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data;
 
-	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);
+	compatible_close(sockfd);
 }
 
-void
-lws_libuv_io(struct lws *wsi, int flags)
+int
+lws_libuv_check_watcher_active(struct lws *wsi)
 {
-	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;
+	uv_handle_t *h = (void *)&wsi->w_read.uv.watcher;
 
-	/* w->context is set after the loop is initialized */
+	return uv_is_active(h);
+}
 
-	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)
-{
-	if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
-		uv_stop(context->pt[tsi].uv.io_loop);
-}
-
-
-
-LWS_VISIBLE uv_loop_t *
-lws_uv_getloop(struct lws_context *context, int tsi)
-{
-	if (context->pt[tsi].uv.io_loop && LWS_LIBUV_ENABLED(context))
-		return context->pt[tsi].uv.io_loop;
-
-	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)
-{
-	lws_sockfd_type sockfd = (lws_sockfd_type)(lws_intptr_t)handle->data;
-
-	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)
-{
-	uv_handle_t *h = (void *)&wsi->w_read.uv.watcher;
-
-	return uv_is_active(h);
-}
-
-
-#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
+#if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
 
 LWS_VISIBLE int
 lws_plat_plugins_init(struct lws_context *context, const char * const *d)
@@ -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,
+};
diff --git a/lib/event-libs/libuv/private.h b/lib/event-libs/libuv/private.h
index e2dc5375377c986c6c0d5c3bd306009ecdd1f124..5ea25183964315cfed3fb3e55be21ecb643bd4c3 100644
--- a/lib/event-libs/libuv/private.h
+++ b/lib/event-libs/libuv/private.h
@@ -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);
+
diff --git a/lib/event-libs/poll/poll.c b/lib/event-libs/poll/poll.c
new file mode 100644
index 0000000000000000000000000000000000000000..ad6b29b01f93cccc4398dde4f75a01fb2792ad27
--- /dev/null
+++ b/lib/event-libs/poll/poll.c
@@ -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,
+};
\ No newline at end of file
diff --git a/lib/event-libs/poll/private.h b/lib/event-libs/poll/private.h
new file mode 100644
index 0000000000000000000000000000000000000000..2cd65b8db8d15bade782066c510f140533300a1c
--- /dev/null
+++ b/lib/event-libs/poll/private.h
@@ -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;
\ No newline at end of file
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 47d47c67e06e21544f76946f212ae06fbb29efa2..4cbd4d0d640a23b082aaa9b74b2b9309deff82dd 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -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);
 }
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 405ec913cd1278da5a57583c7db1f2fe3896223b..848b3f81eaed778687fd970b8e9a3dcad73dcdbc 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -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
 
diff --git a/lib/plat/lws-plat-unix.c b/lib/plat/lws-plat-unix.c
index fe80c8e3866a80794a9f70e20f59477f25236bd9..80b43b1b0818c4ee0e7cc08a0387b6cc5ecf7c83 100644
--- a/lib/plat/lws-plat-unix.c
+++ b/lib/plat/lws-plat-unix.c
@@ -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);
diff --git a/lib/pollfd.c b/lib/pollfd.c
index 901167b79075bf4c111b430bac93e43a77fd942d..6a06d51f4139e440f7c0f9fa30da4edbb12efad5 100644
--- a/lib/pollfd.c
+++ b/lib/pollfd.c
@@ -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,
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 827bc388042a03e0100415ff2997ef7981a169cc..5a72047b484dc692be994c66547a5ae7faa711fc 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -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
 };
diff --git a/lib/roles/cgi/cgi-server.c b/lib/roles/cgi/cgi-server.c
index 2de5a875482503dc91e5f0e8563c38123f3b281a..4fc8305b45c5036b14922ac49ad7c92b86b8a5cd 100644
--- a/lib/roles/cgi/cgi-server.c
+++ b/lib/roles/cgi/cgi-server.c
@@ -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;
diff --git a/lib/roles/cgi/ops-cgi.c b/lib/roles/cgi/ops-cgi.c
index 546d2948989535a4ac4de5c5fb7d594ab7cb59a1..bc42c10ee8833d4e1ed477ef35c25599afe3ca6e 100644
--- a/lib/roles/cgi/ops-cgi.c
+++ b/lib/roles/cgi/ops-cgi.c
@@ -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,
 };
diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c
index a5611f8ee588bc73a69d8a6e5367a20f05eff8ee..0cde99d5f1d47a5d3ed97105913f4f1612072963 100644
--- a/lib/roles/h1/ops-h1.c
+++ b/lib/roles/h1/ops-h1.c
@@ -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,
 };
diff --git a/lib/roles/h2/ops-h2.c b/lib/roles/h2/ops-h2.c
index 93c5b7feef568f2f048dc31f0aa279a9ff005948..f10f7c93e7e924184c4c0515862134f41dd9d120 100644
--- a/lib/roles/h2/ops-h2.c
+++ b/lib/roles/h2/ops-h2.c
@@ -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,
 };
diff --git a/lib/roles/http/client/client-handshake.c b/lib/roles/http/client/client-handshake.c
index 7edf3cce7254bfe155d524717b9d120d8501e933..6455a1c04a3a3e109a1e60447e4a329b2583b5d4 100644
--- a/lib/roles/http/client/client-handshake.c
+++ b/lib/roles/http/client/client-handshake.c
@@ -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);
 
diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c
index 689ae29efaefd53b2c73a27a9a089d34f1e18668..2f2224f5138f198f954f7e1aa09826636823ce82 100644
--- a/lib/roles/http/server/server.c
+++ b/lib/roles/http/server/server.c
@@ -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__);
diff --git a/lib/roles/listen/ops-listen.c b/lib/roles/listen/ops-listen.c
index cea1494faabf8c1f3ea08ff8bc3a0676491b5cbe..690476de4eb7c9f0cd0aa0595ea94f1854983fae 100644
--- a/lib/roles/listen/ops-listen.c
+++ b/lib/roles/listen/ops-listen.c
@@ -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,
 };
diff --git a/lib/roles/pipe/ops-pipe.c b/lib/roles/pipe/ops-pipe.c
index 13673444090449553df230ad83760f223c1d4868..4fd4902715a98d9c29465c4836f2dab538343297 100644
--- a/lib/roles/pipe/ops-pipe.c
+++ b/lib/roles/pipe/ops-pipe.c
@@ -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,
 };
diff --git a/lib/roles/raw/ops-raw.c b/lib/roles/raw/ops-raw.c
index 24006fed2d8d64d984410d9e69a20ed72abcf219..f59bdab69f6e14b9bce224e9604b4e3e7ce41a0a 100644
--- a/lib/roles/raw/ops-raw.c
+++ b/lib/roles/raw/ops-raw.c
@@ -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,
 };
diff --git a/lib/service.c b/lib/service.c
index 13ce9d12b9153c111e60b8cd14135fc315900e89..d9b82ab223bd4e2ff3c91646757c502a0cab946c 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -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);
 }
-
diff --git a/lwsws/main.c b/lwsws/main.c
index dcc7b7fa00cc96d249165237603cfa836e9b72c6..1a89f852ac65600e06124f93e7a52a4c591cfaf5 100644
--- a/lwsws/main.c
+++ b/lwsws/main.c
@@ -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);
 
-	uv_signal_stop(&signal_outer);
-	lws_context_destroy(context);
+	lwsl_err("%s: closing\n", __func__);
 
-#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
+	for (n = 0; n < 2; n++) {
+		uv_signal_stop(&signal_outer[n]);
+		uv_close((uv_handle_t *)&signal_outer[n], NULL);
+	}
+
+	lws_context_destroy(context);
 
-	lws_context_destroy2(context);
+	while ((n = uv_loop_close(&loop)) && --budget)
+		uv_run(&loop, UV_RUN_ONCE);
 
-	fprintf(stderr, "lwsws exited cleanly\n");
+	fprintf(stderr, "lwsws exited cleanly: %d\n", n);
 
 #ifndef _WIN32
 	closelog();
diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md b/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md
index 3b823d666e244a55c75a81f2f2191538e2b17677..41cc9d93a0fa3cd9644b4d59b135721a5549b7c8 100644
--- a/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md
+++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/README.md
@@ -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
 
diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.cert b/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.cert
new file mode 100644
index 0000000000000000000000000000000000000000..6f372db40ad29f5bc1e0463078d48f2bd8d5c60c
--- /dev/null
+++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.cert
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF5jCCA86gAwIBAgIJANq50IuwPFKgMA0GCSqGSIb3DQEBCwUAMIGGMQswCQYD
+VQQGEwJHQjEQMA4GA1UECAwHRXJld2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEb
+MBkGA1UECgwSbGlid2Vic29ja2V0cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3Qx
+HzAdBgkqhkiG9w0BCQEWEG5vbmVAaW52YWxpZC5vcmcwIBcNMTgwMzIwMDQxNjA3
+WhgPMjExODAyMjQwNDE2MDdaMIGGMQswCQYDVQQGEwJHQjEQMA4GA1UECAwHRXJl
+d2hvbjETMBEGA1UEBwwKQWxsIGFyb3VuZDEbMBkGA1UECgwSbGlid2Vic29ja2V0
+cy10ZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG9w0BCQEWEG5vbmVA
+aW52YWxpZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCjYtuW
+aICCY0tJPubxpIgIL+WWmz/fmK8IQr11Wtee6/IUyUlo5I602mq1qcLhT/kmpoR8
+Di3DAmHKnSWdPWtn1BtXLErLlUiHgZDrZWInmEBjKM1DZf+CvNGZ+EzPgBv5nTek
+LWcfI5ZZtoGuIP1Dl/IkNDw8zFz4cpiMe/BFGemyxdHhLrKHSm8Eo+nT734tItnH
+KT/m6DSU0xlZ13d6ehLRm7/+Nx47M3XMTRH5qKP/7TTE2s0U6+M0tsGI2zpRi+m6
+jzhNyMBTJ1u58qAe3ZW5/+YAiuZYAB6n5bhUp4oFuB5wYbcBywVR8ujInpF8buWQ
+Ujy5N8pSNp7szdYsnLJpvAd0sibrNPjC0FQCNrpNjgJmIK3+mKk4kXX7ZTwefoAz
+TK4l2pHNuC53QVc/EF++GBLAxmvCDq9ZpMIYi7OmzkkAKKC9Ue6Ef217LFQCFIBK
+Izv9cgi9fwPMLhrKleoVRNsecBsCP569WgJXhUnwf2lon4fEZr3+vRuc9shfqnV0
+nPN1IMSnzXCast7I2fiuRXdIz96KjlGQpP4XfNVA+RGL7aMnWOFIaVrKWLzAtgzo
+GMTvP/AuehKXncBJhYtW0ltTioVx+5yTYSAZWl+IssmXjefxJqYi2/7QWmv1QC9p
+sNcjTMaBQLN03T1Qelbs7Y27sxdEnNUth4kI+wIDAQABo1MwUTAdBgNVHQ4EFgQU
+9mYU23tW2zsomkKTAXarjr2vjuswHwYDVR0jBBgwFoAU9mYU23tW2zsomkKTAXar
+jr2vjuswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEANjIBMrow
+YNCbhAJdP7dhlhT2RUFRdeRUJD0IxrH/hkvb6myHHnK8nOYezFPjUlmRKUgNEDuA
+xbnXZzPdCRNV9V2mShbXvCyiDY7WCQE2Bn44z26O0uWVk+7DNNLH9BnkwUtOnM9P
+wtmD9phWexm4q2GnTsiL6Ul6cy0QlTJWKVLEUQQ6yda582e23J1AXqtqFcpfoE34
+H3afEiGy882b+ZBiwkeV+oq6XVF8sFyr9zYrv9CvWTYlkpTQfLTZSsgPdEHYVcjv
+xQ2D+XyDR0aRLRlvxUa9dHGFHLICG34Juq5Ai6lM1EsoD8HSsJpMcmrH7MWw2cKk
+ujC3rMdFTtte83wF1uuF4FjUC72+SmcQN7A386BC/nk2TTsJawTDzqwOu/VdZv2g
+1WpTHlumlClZeP+G/jkSyDwqNnTu1aodDmUa4xZodfhP1HWPwUKFcq8oQr148QYA
+AOlbUOJQU7QwRWd1VbnwhDtQWXC92A2w1n/xkZSR1BM/NUSDhkBSUU1WjMbWg6Gg
+mnIZLRerQCu1Oozr87rOQqQakPkyt8BUSNK3K42j2qcfhAONdRl8Hq8Qs5pupy+s
+8sdCGDlwR3JNCMv6u48OK87F4mcIxhkSefFJUFII25pCGN5WtE4p5l+9cnO1GrIX
+e2Hl/7M0c/lbZ4FvXgARlex2rkgS0Ka06HE=
+-----END CERTIFICATE-----
diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.key b/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.key
new file mode 100644
index 0000000000000000000000000000000000000000..148f8598ee1b61bcdfd35bba618fb010d8772f39
--- /dev/null
+++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/localhost-100y.key
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+fBrpEY1IATtPq1taBZZogRqI3rOkkPk=
+-----END PRIVATE KEY-----
diff --git a/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c b/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c
index b27763b54dc89d50028988179bbfceef3736ec8b..7108133eed09982e6efce411442f7d2823d409b1 100644
--- a/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c
+++ b/minimal-examples/http-server/minimal-http-server-libuv-foreign/minimal-http-server-libuv-foreign.c
@@ -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");
-}
 
-static void lws_uv_close_cb(uv_handle_t *handle)
-{
-}
+	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;
+	}
 
-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);
+	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;
+	}
 }
 
+
 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;
-
-	uv_loop_init(&loop);
-
-	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;
+	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;
 
-	lws_uv_sigint_cfg(context, 1, signal_cb);
+	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");
 
-	if (lws_uv_initloop(context, &loop, 0)) {
-		lwsl_err("lws_uv_initloop failed\n");
+	/* we create and start our "foreign loop" */
 
-		goto bail;
-	}
-
-	lws_libuv_run(context, 0);
+	uv_loop_init(&loop);
+	uv_signal_init(&loop, &sighandler);
+	uv_signal_start(&sighandler, signal_cb, SIGINT);
 
-bail:
-	lwsl_user("%s: starting exit cleanup...\n", __func__);
+	uv_timer_init(&loop, &timer_outer);
+	uv_timer_start(&timer_outer, timer_cb, 0, 1000);
 
-	/* cleanup the lws part */
+	uv_run(&loop, UV_RUN_DEFAULT);
 
+	/* in the case we hit ^C while lws still exists */
 	lws_context_destroy(context);
-	lws_context_destroy2(context);
 
-	/* cleanup the foreign loop part */
+	/* cleanup the foreign loop assets */
 
-	lwsl_user("%s: lws context destroyed: cleaning the foreign loop\n",
-		    __func__);
+	uv_timer_stop(&timer_outer);
+	uv_close((uv_handle_t*)&timer_outer, NULL);
+	uv_signal_stop(&sighandler);
+	uv_close((uv_handle_t *)&sighandler, NULL);
 
-	/*
-	 * 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 */
-
 	uv_loop_close(&loop);
 
 	lwsl_user("%s: exiting...\n", __func__);
diff --git a/minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt b/minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt
index 1ced4952d61daa5b7951d4acdb58ca369f55afa4..d95e75337ddfbcabdaa9808192ed3c15cf91969f 100644
--- a/minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt
+++ b/minimal-examples/http-server/minimal-http-server-libuv/CMakeLists.txt
@@ -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()
\ No newline at end of file
+endif()
diff --git a/minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server.c b/minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server-libuv.c
similarity index 89%
rename from minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server.c
rename to minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server-libuv.c
index e6e66185e574e8add669d1b2880f51f5d8e5e57e..9d73be132e3a1956d560418fa6d15e949157b549 100644
--- a/minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server.c
+++ b/minimal-examples/http-server/minimal-http-server-libuv/minimal-http-server-libuv.c
@@ -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);
-
-	if (lws_uv_initloop(context, NULL, 0)) {
-		lwsl_err("lws_uv_initloop failed\n");
-
-		goto bail;
-	}
-
-	lws_libuv_run(context, 0);
+	lws_service(context, 0);
 
-bail:
 	lws_context_destroy(context);
-	lws_context_destroy2(context);
 
 	return 0;
 }
diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c
index 9619eb66bba942eab75d5d16dd3ded108e898a99..4ee1bf4f4ee47d70dbdaac0b1ee3751c07e3a6e6 100644
--- a/plugins/protocol_lws_server_status.c
+++ b/plugins/protocol_lws_server_status.c
@@ -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;
 	}
diff --git a/test-apps/test-server-libev.c b/test-apps/test-server-libev.c
index debbf0f15db5677a5834ea6b29dcb1be60ab8143..42eca940bbfeca18b1d4af3efe8a41d30d522580 100644
--- a/test-apps/test-server-libev.c
+++ b/test-apps/test-server-libev.c
@@ -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);
 
diff --git a/test-apps/test-server-libevent.c b/test-apps/test-server-libevent.c
index 2766c9f7d34644eb68b25fa67492f3ff31f9fd7f..bc47f999d8c7929b59c66fab5d1004d9aef710b6 100644
--- a/test-apps/test-server-libevent.c
+++ b/test-apps/test-server-libevent.c
@@ -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");
diff --git a/test-apps/test-server-libuv.c b/test-apps/test-server-libuv.c
index 6d28add452a1e8c174234bb9d8c276a2e084e069..f20cf8bcd20d707020467ef43c9c89340ee9257a 100644
--- a/test-apps/test-server-libuv.c
+++ b/test-apps/test-server-libuv.c
@@ -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");
diff --git a/test-apps/test-server-v2.0.c b/test-apps/test-server-v2.0.c
index 94cddce59fc3085b1f4bb512f93ba3c2a2b51afc..8873d71b4dd0063a77b992ba3ff904f9b7960495 100644
--- a/test-apps/test-server-v2.0.c
+++ b/test-apps/test-server-v2.0.c
@@ -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_libuv_run(context, 0);
+	lws_service(context, 0);
 
-bail:
 	/* when we decided to exit the event loop */
 	lws_context_destroy(context);
-	lws_context_destroy2(context);
 
 
 #if defined(TEST_DYNAMIC_VHOST)