From 4cbf81da5989b389af0ccfd43e94d4ae38907e5f Mon Sep 17 00:00:00 2001
From: Alexander Alashkin <alexander.alashkin@cesanta.com>
Date: Mon, 12 Sep 2016 15:09:35 +0100
Subject: [PATCH] Use user timeout in multithreading polling

PUBLISHED_FROM=dbf75bfba087f1b0aa0531e5003ba3e69ed1a6ab
---
 docs/c-api/net.h/intro.md                     |  1 +
 .../net.h/struct_mg_multithreading_opts.md    | 12 ++++++++
 mongoose.c                                    | 28 +++++++++++++++++--
 mongoose.h                                    | 11 ++++++++
 4 files changed, 49 insertions(+), 3 deletions(-)
 create mode 100644 docs/c-api/net.h/struct_mg_multithreading_opts.md

diff --git a/docs/c-api/net.h/intro.md b/docs/c-api/net.h/intro.md
index d102bac1e..98575483a 100644
--- a/docs/c-api/net.h/intro.md
+++ b/docs/c-api/net.h/intro.md
@@ -30,6 +30,7 @@ items:
   - { name: struct_mg_add_sock_opts.md }
   - { name: struct_mg_bind_opts.md }
   - { name: struct_mg_connect_opts.md }
+  - { name: struct_mg_multithreading_opts.md }
 ---
 
 NOTE: Mongoose manager is single threaded. It does not protect
diff --git a/docs/c-api/net.h/struct_mg_multithreading_opts.md b/docs/c-api/net.h/struct_mg_multithreading_opts.md
new file mode 100644
index 000000000..1e388fe9a
--- /dev/null
+++ b/docs/c-api/net.h/struct_mg_multithreading_opts.md
@@ -0,0 +1,12 @@
+---
+title: "struct mg_multithreading_opts"
+decl_name: "struct mg_multithreading_opts"
+symbol_kind: "struct"
+signature: |
+  struct mg_multithreading_opts {
+    int poll_timeout; /* Polling interval */
+  };
+---
+
+Optional parameters for mg_enable_multithreading_opt() 
+
diff --git a/mongoose.c b/mongoose.c
index 64f07c3c2..5e9377efb 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -3456,13 +3456,15 @@ static void multithreaded_ev_handler(struct mg_connection *c, int ev, void *p);
 static void *per_connection_thread_function(void *param) {
   struct mg_connection *c = (struct mg_connection *) param;
   struct mg_mgr m;
+  /* mgr_data can be used subsequently, store its value */
+  int poll_timeout = (intptr_t) c->mgr_data;
 
   mg_mgr_init(&m, NULL);
   mg_add_conn(&m, c);
   mg_call(c, NULL, MG_EV_ACCEPT, &c->sa);
 
   while (m.active_connections != NULL) {
-    mg_mgr_poll(&m, 1000);
+    mg_mgr_poll(&m, poll_timeout ? poll_timeout : 1000);
   }
   mg_mgr_free(&m);
 
@@ -3496,7 +3498,7 @@ static void spawn_handling_thread(struct mg_connection *nc) {
   struct mg_mgr dummy;
   sock_t sp[2];
   struct mg_connection *c[2];
-
+  int poll_timeout;
   /*
    * Create a socket pair, and wrap each socket into the connection with
    * dummy event manager.
@@ -3507,6 +3509,9 @@ static void spawn_handling_thread(struct mg_connection *nc) {
   c[0] = mg_add_sock(&dummy, sp[0], forwarder_ev_handler);
   c[1] = mg_add_sock(&dummy, sp[1], nc->listener->priv_1.f);
 
+  /* link_conns replaces priv_2, storing its value */
+  poll_timeout = (intptr_t) nc->priv_2;
+
   /* Interlink client connection with c[0] */
   link_conns(c[0], nc);
 
@@ -3526,6 +3531,9 @@ static void spawn_handling_thread(struct mg_connection *nc) {
   c[1]->sa = nc->sa;
   c[1]->flags = nc->flags;
 
+  /* priv_2 is used, so, put timeout to mgr_data */
+  c[1]->mgr_data = (void *) (intptr_t) poll_timeout;
+
   mg_start_thread(per_connection_thread_function, c[1]);
 }
 
@@ -3537,11 +3545,25 @@ static void multithreaded_ev_handler(struct mg_connection *c, int ev, void *p) {
   }
 }
 
-void mg_enable_multithreading(struct mg_connection *nc) {
+void mg_enable_multithreading_opt(struct mg_connection *nc,
+                                  struct mg_multithreading_opts opts) {
   /* Wrap user event handler into our multithreaded_ev_handler */
   nc->priv_1.f = nc->handler;
+  /*
+   * We put timeout to `priv_2` member of the main
+   * (listening) connection, mt is not enabled yet,
+   * and this member is not used
+   */
+  nc->priv_2 = (void *) (intptr_t) opts.poll_timeout;
   nc->handler = multithreaded_ev_handler;
 }
+
+void mg_enable_multithreading(struct mg_connection *nc) {
+  struct mg_multithreading_opts opts;
+  memset(&opts, 0, sizeof(opts));
+  mg_enable_multithreading_opt(nc, opts);
+}
+
 #endif
 #ifdef MG_MODULE_LINES
 #line 1 "./src/uri.c"
diff --git a/mongoose.h b/mongoose.h
index c68deae3f..069e6d323 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -189,6 +189,7 @@
 #endif
 #if defined(_MSC_VER) && _MSC_VER <= 1200
 typedef unsigned long uintptr_t;
+typedef long intptr_t;
 #endif
 typedef int socklen_t;
 #if _MSC_VER >= 1700
@@ -287,6 +288,7 @@ typedef struct _stati64 cs_stat_t;
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <stdint.h>
 #include <limits.h>
 #include <math.h>
 #include <netdb.h>
@@ -1583,6 +1585,13 @@ int mg_resolve(const char *domain_name, char *ip_addr_buf, size_t buf_len);
  */
 int mg_check_ip_acl(const char *acl, uint32_t remote_ip);
 
+/*
+ * Optional parameters for mg_enable_multithreading_opt()
+ */
+struct mg_multithreading_opts {
+  int poll_timeout; /* Polling interval */
+};
+
 /*
  * Enables multi-threaded handling for the given listening connection `nc`.
  * For each accepted connection, Mongoose will create a separate thread
@@ -1591,6 +1600,8 @@ int mg_check_ip_acl(const char *acl, uint32_t remote_ip);
  * other connections.
  */
 void mg_enable_multithreading(struct mg_connection *nc);
+void mg_enable_multithreading_opt(struct mg_connection *nc,
+                                  struct mg_multithreading_opts opts);
 
 #ifdef MG_ENABLE_JAVASCRIPT
 /*
-- 
GitLab