{"action":"created","issue":{"url":"https://api.github.com/repos/warmcat/libwebsockets/issues/411","repository_url":"https://api.github.com/repos/warmcat/libwebsockets","labels_url":"https://api.github.com/repos/warmcat/libwebsockets/issues/411/labels{/name}","comments_url":"https://api.github.com/repos/warmcat/libwebsockets/issues/411/comments","events_url":"https://api.github.com/repos/warmcat/libwebsockets/issues/411/events","html_url":"https://github.com/warmcat/libwebsockets/issues/411","id":130209051,"number":411,"title":"libuv backend","user":{"login":"alexhultman","id":3397140,"avatar_url":"https://avatars.githubusercontent.com/u/3397140?v=3","gravatar_id":"","url":"https://api.github.com/users/alexhultman","html_url":"https://github.com/alexhultman","followers_url":"https://api.github.com/users/alexhultman/followers","following_url":"https://api.github.com/users/alexhultman/following{/other_user}","gists_url":"https://api.github.com/users/alexhultman/gists{/gist_id}","starred_url":"https://api.github.com/users/alexhultman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexhultman/subscriptions","organizations_url":"https://api.github.com/users/alexhultman/orgs","repos_url":"https://api.github.com/users/alexhultman/repos","events_url":"https://api.github.com/users/alexhultman/events{/privacy}","received_events_url":"https://api.github.com/users/alexhultman/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2016-01-31T23:06:09Z","updated_at":"2016-02-03T11:50:41Z","closed_at":null,"body":"Hi guys.\r\n\r\nI took a nap and then I implemented a quick test with libuv. It just started working but seems pretty stable. I need to add more functionalities (signals) and clean things up.\r\n\r\nWould you be interested in working with me to add this new backend? It shares a lot with libev in terms of concepts so maybe it would be easiest to merge libev/libuv backends into one (with some differences, ofc). But this is completely up to you.\r\n\r\nThis is my (really ugly) first patch version:\r\n\r\n```c\r\ndiff --git a/lib/context.c b/lib/context.c\r\nindex e4cbe78..20650cb 100644\r\n--- a/lib/context.c\r\n+++ b/lib/context.c\r\n@@ -378,9 +378,10 @@ lws_context_destroy(struct lws_context *context)\r\n \t\t}\r\n \t}\r\n #ifdef LWS_USE_LIBEV\r\n-\tev_io_stop(context->io_loop, &context->w_accept.watcher);\r\n-\tif (context->use_ev_sigint)\r\n-\t\tev_signal_stop(context->io_loop, &context->w_sigint.watcher);\r\n+    uv_poll_stop(&context->w_accept.watcher);\r\n+    //ev_io_stop(context->io_loop, &context->w_accept.watcher);\r\n+    //if (context->use_ev_sigint)\r\n+        //ev_signal_stop(context->io_loop, &context->w_sigint.watcher);\r\n #endif /* LWS_USE_LIBEV */\r\n \r\n \tfor (n = 0; n < context->count_threads; n++) {\r\ndiff --git a/lib/libev.c b/lib/libev.c\r\nindex 167c045..a7fd1cb 100644\r\n--- a/lib/libev.c\r\n+++ b/lib/libev.c\r\n@@ -30,24 +30,24 @@ void lws_feature_status_libev(struct lws_context_creation_info *info)\r\n }\r\n \r\n static void\r\n-lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)\r\n+lws_accept_cb(uv_poll_t *watcher, int status, int revents)\r\n {\r\n \tstruct lws_io_watcher *lws_io = container_of(watcher,\r\n \t\t\t\t\t\tstruct lws_io_watcher, watcher);\r\n \tstruct lws_context *context = lws_io->context;\r\n \tstruct lws_pollfd eventfd;\r\n \r\n-\tif (revents & EV_ERROR)\r\n-\t\treturn;\r\n+    if (status < 0/*revents & EV_ERROR*/)\r\n+        return;\r\n \r\n-\teventfd.fd = watcher->fd;\r\n+    eventfd.fd = watcher->io_watcher.fd;\r\n \teventfd.events = 0;\r\n-\teventfd.revents = EV_NONE;\r\n-\tif (revents & EV_READ) {\r\n+    eventfd.revents = 0;//EV_NONE;\r\n+    if (revents & UV_READABLE) {\r\n \t\teventfd.events |= LWS_POLLIN;\r\n \t\teventfd.revents |= LWS_POLLIN;\r\n \t}\r\n-\tif (revents & EV_WRITE) {\r\n+    if (revents & UV_WRITABLE) {\r\n \t\teventfd.events |= LWS_POLLOUT;\r\n \t\teventfd.revents |= LWS_POLLOUT;\r\n \t}\r\n@@ -55,9 +55,9 @@ lws_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)\r\n }\r\n \r\n LWS_VISIBLE void\r\n-lws_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents)\r\n+lws_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents)\r\n {\r\n-\tev_break(loop, EVBREAK_ALL);\r\n+    //ev_break(loop, EVBREAK_ALL);\r\n }\r\n \r\n LWS_VISIBLE int\r\n@@ -74,17 +74,17 @@ lws_sigint_cfg(struct lws_context *context, int use_ev_sigint,\r\n }\r\n \r\n LWS_VISIBLE int\r\n-lws_initloop(struct lws_context *context, struct ev_loop *loop)\r\n+lws_initloop(struct lws_context *context, uv_loop_t *loop)\r\n {\r\n-\tstruct ev_signal *w_sigint = &context->w_sigint.watcher;\r\n-\tstruct ev_io *w_accept = &context->w_accept.watcher;\r\n-\tconst char * backend_name;\r\n+    //uv_signal_t *w_sigint = &context->w_sigint.watcher;\r\n+    uv_poll_t *w_accept = &context->w_accept.watcher;\r\n+    //const char * backend_name;\r\n \tint status = 0;\r\n-\tint backend;\r\n-\tint m = 0; /* !!! TODO add pt support */\r\n+    //int backend;\r\n+    int m = 0; /* !!! TODO add pt support */\r\n \r\n \tif (!loop)\r\n-\t\tloop = ev_default_loop(0);\r\n+        loop = uv_default_loop();\r\n \r\n \tcontext->io_loop = loop;\r\n \r\n@@ -92,15 +92,17 @@ lws_initloop(struct lws_context *context, struct ev_loop *loop)\r\n \t * Initialize the accept w_accept with the listening socket\r\n \t * and register a callback for read operations\r\n \t */\r\n-\tev_io_init(w_accept, lws_accept_cb, context->pt[m].lserv_fd, EV_READ);\r\n-\tev_io_start(context->io_loop,w_accept);\r\n+    uv_poll_init(context->io_loop, w_accept, context->pt[m].lserv_fd);\r\n+    uv_poll_start(w_accept, UV_READABLE, lws_accept_cb);\r\n+    //ev_io_init(w_accept, lws_accept_cb, context->pt[m].lserv_fd, UV_READABLE);\r\n+    //ev_io_start(context->io_loop,w_accept);\r\n \r\n \t/* Register the signal watcher unless the user says not to */\r\n \tif (context->use_ev_sigint) {\r\n-\t\tev_signal_init(w_sigint, context->lws_ev_sigint_cb, SIGINT);\r\n-\t\tev_signal_start(context->io_loop,w_sigint);\r\n+        //ev_signal_init(w_sigint, context->lws_ev_sigint_cb, SIGINT);\r\n+        //ev_signal_start(context->io_loop,w_sigint);\r\n \t}\r\n-\tbackend = ev_backend(loop);\r\n+    /*backend = ev_backend(loop);\r\n \r\n \tswitch (backend) {\r\n \tcase EVBACKEND_SELECT:\r\n@@ -126,7 +128,7 @@ lws_initloop(struct lws_context *context, struct ev_loop *loop)\r\n \t\tbreak;\r\n \t}\r\n \r\n-\tlwsl_notice(\" libev backend: %s\\n\", backend_name);\r\n+    lwsl_notice(\" libev backend: %s\\n\", backend_name);*/\r\n \r\n \treturn status;\r\n }\r\n@@ -135,22 +137,24 @@ LWS_VISIBLE void\r\n lws_libev_accept(struct lws *new_wsi, int accept_fd)\r\n {\r\n \tstruct lws_context *context = lws_get_context(new_wsi);\r\n-\tstruct ev_io *r = &new_wsi->w_read.watcher;\r\n-\tstruct ev_io *w = &new_wsi->w_write.watcher;\r\n+    uv_poll_t *r = &new_wsi->w_read.watcher;\r\n+    //uv_poll_t *w = &new_wsi->w_write.watcher;\r\n \r\n \tif (!LWS_LIBEV_ENABLED(context))\r\n \t\treturn;\r\n \r\n \tnew_wsi->w_read.context = context;\r\n \tnew_wsi->w_write.context = context;\r\n-\tev_io_init(r, lws_accept_cb, accept_fd, EV_READ);\r\n-\tev_io_init(w, lws_accept_cb, accept_fd, EV_WRITE);\r\n+    uv_poll_init(context->io_loop, r, accept_fd);\r\n+    //ev_io_init(r, lws_accept_cb, accept_fd, UV_READABLE);\r\n+    //ev_io_init(w, lws_accept_cb, accept_fd, UV_WRITABLE);\r\n }\r\n \r\n LWS_VISIBLE void\r\n lws_libev_io(struct lws *wsi, int flags)\r\n {\r\n \tstruct lws_context *context = lws_get_context(wsi);\r\n+    int current_events = wsi->w_read.watcher.io_watcher.pevents & (UV_READABLE | UV_WRITABLE);\r\n \r\n \tif (!LWS_LIBEV_ENABLED(context))\r\n \t\treturn;\r\n@@ -162,15 +166,26 @@ lws_libev_io(struct lws *wsi, int flags)\r\n \t       (flags & (LWS_EV_READ | LWS_EV_WRITE)));\r\n \r\n \tif (flags & LWS_EV_START) {\r\n-\t\tif (flags & LWS_EV_WRITE)\r\n-\t\t\tev_io_start(context->io_loop, &wsi->w_write.watcher);\r\n-\t\tif (flags & LWS_EV_READ)\r\n-\t\t\tev_io_start(context->io_loop, &wsi->w_read.watcher);\r\n+        if (flags & LWS_EV_WRITE)\r\n+            current_events |= UV_WRITABLE;\r\n+            //ev_io_start(context->io_loop, &wsi->w_write.watcher);\r\n+        if (flags & LWS_EV_READ)\r\n+            current_events |= UV_READABLE;\r\n+            //ev_io_start(context->io_loop, &wsi->w_read.watcher);\r\n+\r\n+        uv_poll_start(&wsi->w_read.watcher, current_events, lws_accept_cb);\r\n \t} else {\r\n-\t\tif (flags & LWS_EV_WRITE)\r\n-\t\t\tev_io_stop(context->io_loop, &wsi->w_write.watcher);\r\n-\t\tif (flags & LWS_EV_READ)\r\n-\t\t\tev_io_stop(context->io_loop, &wsi->w_read.watcher);\r\n+        if (flags & LWS_EV_WRITE)\r\n+            current_events &= ~UV_WRITABLE;\r\n+            //ev_io_stop(context->io_loop, &wsi->w_write.watcher);\r\n+        if (flags & LWS_EV_READ)\r\n+            current_events &= ~UV_READABLE;\r\n+            //ev_io_stop(context->io_loop, &wsi->w_read.watcher);\r\n+\r\n+        if (!(current_events & (UV_READABLE | UV_WRITABLE)))\r\n+            uv_poll_stop(&wsi->w_read.watcher);\r\n+        else\r\n+            uv_poll_start(&wsi->w_read.watcher, current_events, lws_accept_cb);\r\n \t}\r\n }\r\n \r\n@@ -190,5 +205,5 @@ LWS_VISIBLE void\r\n lws_libev_run(const struct lws_context *context)\r\n {\r\n \tif (context->io_loop && LWS_LIBEV_ENABLED(context))\r\n-\t\tev_run(context->io_loop, 0);\r\n+        uv_run(context->io_loop, 0);\r\n }\r\ndiff --git a/lib/libwebsockets.h b/lib/libwebsockets.h\r\nindex 9b66352..400ab81 100644\r\n--- a/lib/libwebsockets.h\r\n+++ b/lib/libwebsockets.h\r\n@@ -166,7 +166,7 @@ struct sockaddr_in;\r\n #endif\r\n \r\n #ifdef LWS_USE_LIBEV\r\n-#include <ev.h>\r\n+#include <uv.h>\r\n #endif /* LWS_USE_LIBEV */\r\n \r\n #ifndef LWS_EXTERN\r\n@@ -1453,17 +1453,17 @@ LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT\r\n lws_http_transaction_completed(struct lws *wsi);\r\n \r\n #ifdef LWS_USE_LIBEV\r\n-typedef void (lws_ev_signal_cb)(EV_P_ struct ev_signal *w, int revents);\r\n+typedef void (lws_ev_signal_cb)(uv_loop_t *l, uv_signal_t *w, int revents);\r\n \r\n LWS_VISIBLE LWS_EXTERN int\r\n lws_sigint_cfg(struct lws_context *context, int use_ev_sigint,\r\n \t       lws_ev_signal_cb *cb);\r\n \r\n LWS_VISIBLE LWS_EXTERN int\r\n-lws_initloop(struct lws_context *context, struct ev_loop *loop);\r\n+lws_initloop(struct lws_context *context, uv_loop_t *loop);\r\n \r\n LWS_VISIBLE void\r\n-lws_sigint_cb(struct ev_loop *loop, struct ev_signal *watcher, int revents);\r\n+lws_sigint_cb(uv_loop_t *loop, uv_signal_t *watcher, int revents);\r\n #endif /* LWS_USE_LIBEV */\r\n \r\n LWS_VISIBLE LWS_EXTERN int\r\ndiff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h\r\nindex 72f71b4..d20da12 100644\r\n--- a/lib/private-libwebsockets.h\r\n+++ b/lib/private-libwebsockets.h\r\n@@ -117,7 +117,7 @@\r\n #include <arpa/inet.h>\r\n #include <poll.h>\r\n #ifdef LWS_USE_LIBEV\r\n-#include <ev.h>\r\n+#include <uv.h>\r\n #endif /* LWS_USE_LIBEV */\r\n #include <sys/mman.h>\r\n \r\n@@ -439,12 +439,12 @@ struct lws;\r\n \r\n #ifdef LWS_USE_LIBEV\r\n struct lws_io_watcher {\r\n-\tstruct ev_io watcher;\r\n+    uv_poll_t watcher;\r\n \tstruct lws_context* context;\r\n };\r\n \r\n struct lws_signal_watcher {\r\n-\tstruct ev_signal watcher;\r\n+    uv_signal_t watcher;\r\n \tstruct lws_context* context;\r\n };\r\n #endif /* LWS_USE_LIBEV */\r\n@@ -560,7 +560,7 @@ struct lws_context {\r\n \tstruct lws **lws_lookup;  /* fd to wsi */\r\n #endif\r\n #ifdef LWS_USE_LIBEV\r\n-\tstruct ev_loop* io_loop;\r\n+    uv_loop_t *io_loop;\r\n \tstruct lws_io_watcher w_accept;\r\n \tstruct lws_signal_watcher w_sigint;\r\n \tlws_ev_signal_cb* lws_ev_sigint_cb;\r\n```"},"comment":{"url":"https://api.github.com/repos/warmcat/libwebsockets/issues/comments/179182904","html_url":"https://github.com/warmcat/libwebsockets/issues/411#issuecomment-179182904","issue_url":"https://api.github.com/repos/warmcat/libwebsockets/issues/411","id":179182904,"user":{"login":"alexhultman","id":3397140,"avatar_url":"https://avatars.githubusercontent.com/u/3397140?v=3","gravatar_id":"","url":"https://api.github.com/users/alexhultman","html_url":"https://github.com/alexhultman","followers_url":"https://api.github.com/users/alexhultman/followers","following_url":"https://api.github.com/users/alexhultman/following{/other_user}","gists_url":"https://api.github.com/users/alexhultman/gists{/gist_id}","starred_url":"https://api.github.com/users/alexhultman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alexhultman/subscriptions","organizations_url":"https://api.github.com/users/alexhultman/orgs","repos_url":"https://api.github.com/users/alexhultman/repos","events_url":"https://api.github.com/users/alexhultman/events{/privacy}","received_events_url":"https://api.github.com/users/alexhultman/received_events","type":"User","site_admin":false},"created_at":"2016-02-03T11:50:41Z","updated_at":"2016-02-03T11:50:41Z","body":"I'm working on updating my wrapper to the libuv-test branch and it is stable until I disconnect, then it crashes in _lws_change_pollfd -> it seems to call uv_poll_start, I think it should call uv_poll_stop. Disconnection worked before so this might be some small change in _lws_change_pollfd that made this?"}}