vh doubly linked list for wsi on same protocol
authorAndy Green <andy@warmcat.com>
Sat, 16 Apr 2016 00:40:35 +0000 (08:40 +0800)
committerAndy Green <andy@warmcat.com>
Sat, 16 Apr 2016 00:40:35 +0000 (08:40 +0800)
This trades off a couple of wsi pointers for vastly increased speed
for the callback when writeable "all protocol" variants when there
are many kinds of wsi active.

Signed-off-by: Andy Green <andy@warmcat.com>
lib/context.c
lib/libuv.c
lib/pollfd.c
lib/private-libwebsockets.h
lib/server.c
plugins/protocol_dumb_increment.c

index 823896450c6d95ffe61d5423e7ad10d046f533e6..e746e8cbd08b93f2d883b154fe877fe922ca2313 100644 (file)
@@ -277,6 +277,9 @@ lws_create_vhost(struct lws_context *context,
 #endif
                vh->protocols = info->protocols;
 
+       vh->same_vh_protocol_list = (struct lws **)
+                       lws_zalloc(sizeof(struct lws *) * vh->count_protocols);
+
        vh->mount_list = mounts;
 
 #ifdef LWS_USE_UNIX_SOCK
@@ -796,6 +799,7 @@ lws_context_destroy(struct lws_context *context)
                if (vh->protocol_vh_privs)
                        lws_free(vh->protocol_vh_privs);
                lws_ssl_SSL_CTX_destroy(vh);
+               lws_free(vh->same_vh_protocol_list);
 #ifdef LWS_WITH_PLUGINS
                if (context->plugin_list)
                        lws_free((void *)vh->protocols);
index 6013e0905b822e4065c595e84b826d00416cd4ab..090cf7436865313a90c63ad9e3722d22c872305e 100644 (file)
@@ -363,9 +363,9 @@ lws_libuv_stop(struct lws_context *context)
 
                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
                                /* no protocol close */);
@@ -373,6 +373,7 @@ lws_libuv_stop(struct lws_context *context)
                }
        }
 
+       lwsl_info("%s: feels everything closed\n", __func__);
        if (context->count_wsi_allocated == 0)
                lws_libuv_kill(context);
 }
index 9168b9ed7babaf06ad0da5ac3193a6c68b6b44aa..7a657dbfb0fa738a6ec889a2c0d40e769d09c9e4 100644 (file)
@@ -191,6 +191,30 @@ remove_wsi_socket_from_fds(struct lws *wsi)
                                           wsi->user_space, (void *)&pa, 1))
                return -1;
 
+       /*
+        * detach ourselves from vh protocol list if we're on one
+        * A -> B -> C
+        * A -> C , or, B -> C, or A -> B
+        */
+       lwsl_info("%s: removing same prot wsi %p\n", __func__, wsi);
+       if (wsi->same_vh_protocol_prev) {
+               assert (*(wsi->same_vh_protocol_prev) == wsi);
+               lwsl_info("have prev %p, setting him to our next %p\n",
+                        wsi->same_vh_protocol_prev,
+                        wsi->same_vh_protocol_next);
+
+               /* guy who pointed to us should point to our next */
+               *(wsi->same_vh_protocol_prev) = wsi->same_vh_protocol_next;
+       } //else
+               //lwsl_err("null wsi->prev\n");
+       /* our next should point back to our prev */
+       if (wsi->same_vh_protocol_next) {
+               lwsl_info("have next %p\n");
+               wsi->same_vh_protocol_next->same_vh_protocol_prev =
+                               wsi->same_vh_protocol_prev;
+       } //else
+               //lwsl_err("null wsi->next\n");
+
        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);
 
@@ -289,6 +313,9 @@ lws_callback_on_writable(struct lws *wsi)
        if (wsi->state == LWSS_SHUTDOWN)
                return 0;
 
+       if (wsi->socket_is_permanently_unusable)
+               return 0;
+
 #ifdef LWS_USE_HTTP2
        lwsl_info("%s: %p\n", __func__, wsi);
 
@@ -349,66 +376,82 @@ network_sock:
 }
 
 /**
- * lws_callback_on_writable_all_protocol() - Request a callback for
+ * lws_callback_on_writable_all_protocol_vhost() - Request a callback for
  *                     all connections using the given protocol when it
  *                     becomes possible to write to each socket without
  *                     blocking in turn.
  *
- * @context:   lws_context
+ *     This calls back connections with the same protocol ON THE SAME
+ *     VHOST ONLY.
+ *
+ * @vhost:     Only consider connections on this lws_vhost
  * @protocol:  Protocol whose connections will get callbacks
  */
 
 LWS_VISIBLE int
-lws_callback_on_writable_all_protocol(const struct lws_context *context,
+lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
                                      const struct lws_protocols *protocol)
 {
-       const struct lws_context_per_thread *pt = &context->pt[0];
-       unsigned int n, m = context->count_threads;
        struct lws *wsi;
 
-       while (m--) {
-               for (n = 0; n < pt->fds_count; n++) {
-                       wsi = wsi_from_fd(context, pt->fds[n].fd);
-                       if (!wsi)
-                               continue;
-                       if (wsi->protocol == protocol)
-                               lws_callback_on_writable(wsi);
+       if (protocol < vhost->protocols ||
+           protocol >= (vhost->protocols + vhost->count_protocols)) {
+               lwsl_err("%s: protocol is not from vhost\n", __func__);
+
+               return -1;
+       }
+
+       wsi = vhost->same_vh_protocol_list[protocol - vhost->protocols];
+       //lwsl_notice("%s: protocol %p, start wsi %p\n", __func__, protocol, wsi);
+       while (wsi) {
+               //lwsl_notice("%s: protocol %p, this wsi %p (wsi->protocol=%p)\n",
+               //              __func__, protocol, wsi, wsi->protocol);
+               assert(wsi->protocol == protocol);
+               assert(*wsi->same_vh_protocol_prev == wsi);
+               if (wsi->same_vh_protocol_next) {
+               //      lwsl_err("my next says %p\n", wsi->same_vh_protocol_next);
+               //      lwsl_err("my next's prev says %p\n",
+               //              wsi->same_vh_protocol_next->same_vh_protocol_prev);
+                       assert(wsi->same_vh_protocol_next->same_vh_protocol_prev == &wsi->same_vh_protocol_next);
                }
-               pt++;
+               lws_callback_on_writable(wsi);
+               wsi = wsi->same_vh_protocol_next;
        }
 
        return 0;
 }
 
-
 /**
- * lws_callback_on_writable_all_protocol_vhost() - Request a callback for
+ * lws_callback_on_writable_all_protocol() - Request a callback for
  *                     all connections using the given protocol when it
  *                     becomes possible to write to each socket without
  *                     blocking in turn.
  *
- * @vhost:     Only consider connections on this lws_vhost
+ *     This calls back any connection using the same protocol on ANY
+ *     VHOST.
+ *
+ * @context:   lws_context
  * @protocol:  Protocol whose connections will get callbacks
  */
 
 LWS_VISIBLE int
-lws_callback_on_writable_all_protocol_vhost(const struct lws_vhost *vhost,
+lws_callback_on_writable_all_protocol(const struct lws_context *context,
                                      const struct lws_protocols *protocol)
 {
-       const struct lws_context *context = vhost->context;
-       const struct lws_context_per_thread *pt = &context->pt[0];
-       unsigned int n, m = context->count_threads;
-       struct lws *wsi;
-
-       while (m--) {
-               for (n = 0; n < pt->fds_count; n++) {
-                       wsi = wsi_from_fd(context, pt->fds[n].fd);
-                       if (!wsi)
-                               continue;
-                       if (wsi->vhost == vhost && wsi->protocol == protocol)
-                               lws_callback_on_writable(wsi);
-               }
-               pt++;
+       struct lws_vhost *vhost = context->vhost_list;
+       int n;
+
+       while (vhost) {
+               for (n = 0; n < vhost->count_protocols; n++)
+                       if (protocol->callback ==
+                           vhost->protocols[n].callback &&
+                           !strcmp(protocol->name, vhost->protocols[n].name))
+                               break;
+               if (n != vhost->count_protocols)
+                       lws_callback_on_writable_all_protocol_vhost(
+                               vhost, &vhost->protocols[n]);
+
+               vhost = vhost->vhost_next;
        }
 
        return 0;
index f00fb466997eb9ed8ed2963000658b4e9b45c818..f91a5c132e847a11c398d11f2de19046ad818863 100644 (file)
@@ -660,6 +660,7 @@ struct lws_vhost {
        const struct lws_protocols *protocols;
        void **protocol_vh_privs;
        struct lws_protocol_vhost_options *pvo;
+       struct lws **same_vh_protocol_list;
 #ifdef LWS_OPENSSL_SUPPORT
        SSL_CTX *ssl_ctx;
        SSL_CTX *ssl_client_ctx;
@@ -1204,6 +1205,7 @@ struct lws {
        struct lws_cgi *cgi; /* wsi being cgi master have one of these */
 #endif
        const struct lws_protocols *protocol;
+       struct lws **same_vh_protocol_prev, *same_vh_protocol_next;
        struct lws *timeout_list;
        struct lws **timeout_list_prev;
 #ifdef LWS_WITH_ACCESS_LOG
index fc11a74d92a0ac37b43fb1b2767ef8f335375504..761590803304959d17d85361421150c1e914ed3e 100644 (file)
@@ -828,7 +828,7 @@ upgrade_ws:
                hit = 0;
 
                while (*p && !hit) {
-                       unsigned int n = 0;
+                       n = 0;
                        while (n < sizeof(protocol_name) - 1 && *p && *p !=',')
                                protocol_name[n++] = *p++;
                        protocol_name[n] = '\0';
@@ -842,7 +842,6 @@ upgrade_ws:
                                if (wsi->vhost->protocols[n].name &&
                                    !strcmp(wsi->vhost->protocols[n].name,
                                            protocol_name)) {
-                                       lwsl_info("prot match %d\n", n);
                                        wsi->protocol = &wsi->vhost->protocols[n];
                                        hit = 1;
                                        break;
@@ -862,10 +861,11 @@ upgrade_ws:
                        }
                        /*
                         * some clients only have one protocol and
-                        * do not sent the protocol list header...
+                        * do not send the protocol list header...
                         * allow it and match to protocol 0
                         */
                        lwsl_info("defaulting to prot 0 handler\n");
+                       n = 0;
                        wsi->protocol = &wsi->vhost->protocols[0];
                }
 
@@ -877,7 +877,6 @@ upgrade_ws:
                 * Give the user code a chance to study the request and
                 * have the opportunity to deny it
                 */
-
                if ((wsi->protocol->callback)(wsi,
                                LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
                                wsi->user_space,
@@ -906,6 +905,31 @@ upgrade_ws:
                        goto bail_nuke_ah;
                }
 
+               /*
+                * stitch protocol choice into the vh protocol linked list
+                * We always insert ourselves at the start of the list
+                *
+                * X <-> B
+                * X <-> pAn <-> pB
+                */
+               //lwsl_err("%s: pre insert vhost start wsi %p, that wsi prev == %p\n",
+               //              __func__,
+               //              wsi->vhost->same_vh_protocol_list[n],
+               //              wsi->same_vh_protocol_prev);
+               wsi->same_vh_protocol_prev = /* guy who points to us */
+                       &wsi->vhost->same_vh_protocol_list[n];
+               wsi->same_vh_protocol_next = /* old first guy is our next */
+                               wsi->vhost->same_vh_protocol_list[n];
+               /* we become the new first guy */
+               wsi->vhost->same_vh_protocol_list[n] = wsi;
+
+               if (wsi->same_vh_protocol_next)
+                       /* old first guy points back to us now */
+                       wsi->same_vh_protocol_next->same_vh_protocol_prev =
+                                       &wsi->same_vh_protocol_next;
+
+
+
                /* we are upgrading to ws, so http/1.1 and keepalive +
                 * pipelined header considerations about keeping the ah around
                 * no longer apply.  However it's common for the first ws
index 711251b506f1ac3fd7d791545d90cecbc568e5d3..fd4eb299cfa64cefe7fea85aadb1a076fbb080a8 100644 (file)
@@ -40,7 +40,7 @@ uv_timeout_cb_dumb_increment(uv_timer_t *w
 {
        struct per_vhost_data__dumb_increment *vhd = lws_container_of(w,
                        struct per_vhost_data__dumb_increment, timeout_watcher);
-       lws_callback_on_writable_all_protocol(vhd->context, vhd->protocol);
+       lws_callback_on_writable_all_protocol_vhost(vhd->vhost, vhd->protocol);
 }
 
 static int