# HG changeset patch
# User Yingqi Lu <Yingqi.Lu@intel.com>
# Date 1408145210 25200
#      Fri Aug 15 16:26:50 2014 -0700
# Node ID d9c7259d275dbcae8a0d001ee9703b13312b3263
# Parent  6edcb183e62d610808addebbd18249abb7224a0a
These are the patch files for SO_REUSEPORT support.

diff -r 6edcb183e62d -r d9c7259d275d ngx_connection.c
--- a/ngx_connection.c	Fri Aug 15 16:25:32 2014 -0700
+++ b/ngx_connection.c	Fri Aug 15 16:26:50 2014 -0700
@@ -304,7 +304,7 @@
 ngx_int_t
 ngx_open_listening_sockets(ngx_cycle_t *cycle)
 {
-    int               reuseaddr;
+    int               reuseaddr, reuseport;
     ngx_uint_t        i, tries, failed;
     ngx_err_t         err;
     ngx_log_t        *log;
@@ -312,6 +312,7 @@
     ngx_listening_t  *ls;
 
     reuseaddr = 1;
+    reuseport = 1;
 #if (NGX_SUPPRESS_WARN)
     failed = 0;
 #endif
@@ -370,6 +371,24 @@
                 return NGX_ERROR;
             }
 
+            if (so_reuseport_enabled)
+            {
+                if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
+                               (const void *) &reuseport, sizeof(int))
+                    == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  "setsockopt(SO_REUSEPORT) %V failed",
+                                  &ls[i].addr_text);
+                    if (ngx_close_socket(s) == -1) {
+                        ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                      ngx_close_socket_n " %V failed",
+                                      &ls[i].addr_text);
+                    }
+
+                    return NGX_ERROR;
+                }
+            }
+
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
 
             if (ls[i].sockaddr->sa_family == AF_INET6) {
diff -r 6edcb183e62d -r d9c7259d275d ngx_cycle.c
--- a/ngx_cycle.c	Fri Aug 15 16:25:32 2014 -0700
+++ b/ngx_cycle.c	Fri Aug 15 16:26:50 2014 -0700
@@ -25,7 +25,7 @@
 
 ngx_uint_t             ngx_test_config;
 ngx_uint_t             ngx_quiet_mode;
-
+ngx_uint_t             so_reuseport_enabled;
 #if (NGX_THREADS)
 ngx_tls_key_t          ngx_core_tls_key;
 #endif
@@ -55,6 +55,34 @@
     ngx_core_module_t   *module;
     char                 hostname[NGX_MAXHOSTNAMELEN];
 
+    ngx_uint_t           j, num_cores, num_dup_sockets, orig_nelts;
+    ngx_socket_t         temp_s;
+    int                  one = 1;
+    so_reuseport_enabled = 0;
+    temp_s = ngx_socket(AF_INET, SOCK_STREAM, 0);
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT 15
+#endif
+    if (setsockopt(temp_s, SOL_SOCKET, SO_REUSEPORT,
+                  (const void *) &one, sizeof(int)) == 0) {
+        so_reuseport_enabled = 1;
+    }
+    ngx_close_socket(temp_s);
+
+    if (so_reuseport_enabled) {
+#ifdef _SC_NPROCESSORS_ONLN
+        num_cores = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+        num_cores = 1;
+#endif
+        if (num_cores > 8) {
+            num_dup_sockets = num_cores/8;
+        } else {
+            num_dup_sockets = 1;
+        }
+    } else {
+        num_dup_sockets = 1;
+    }
     ngx_timezone_update();
 
     /* force localtime update with a new timezone */
@@ -114,7 +142,7 @@
     }
 
 
-    n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
+    n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10 * num_dup_sockets;
 
     cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *));
     if (cycle->paths.elts == NULL) {
@@ -164,7 +192,7 @@
         return NULL;
     }
 
-    n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
+    n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10 * num_dup_sockets;
 
     cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t));
     if (cycle->listening.elts == NULL) {
@@ -231,7 +259,7 @@
 
     ngx_memzero(&conf, sizeof(ngx_conf_t));
     /* STUB: init array ? */
-    conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
+    conf.args = ngx_array_create(pool, (10 * num_dup_sockets), sizeof(ngx_str_t));
     if (conf.args == NULL) {
         ngx_destroy_pool(pool);
         return NULL;
@@ -575,7 +603,15 @@
 #endif
         }
     }
+    orig_nelts = cycle->listening.nelts;
+    cycle->listening.nelts  = cycle->listening.nelts * num_dup_sockets;
 
+    ls = cycle->listening.elts;
+    for (i = 0; i < num_dup_sockets; i++) {
+        for(j = 0; j < orig_nelts; j++) {
+            ls[j + i * orig_nelts] = ls[j];
+        }
+    }
     if (ngx_open_listening_sockets(cycle) != NGX_OK) {
         goto failed;
     }
@@ -747,7 +783,7 @@
             exit(1);
         }
 
-        n = 10;
+        n = 10 * num_dup_sockets;
         ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool,
                                           n * sizeof(ngx_cycle_t *));
         if (ngx_old_cycles.elts == NULL) {
diff -r 6edcb183e62d -r d9c7259d275d ngx_cycle.h
--- a/ngx_cycle.h	Fri Aug 15 16:25:32 2014 -0700
+++ b/ngx_cycle.h	Fri Aug 15 16:26:50 2014 -0700
@@ -136,6 +136,7 @@
 extern ngx_module_t           ngx_core_module;
 extern ngx_uint_t             ngx_test_config;
 extern ngx_uint_t             ngx_quiet_mode;
+extern ngx_uint_t             so_reuseport_enabled;
 #if (NGX_THREADS)
 extern ngx_tls_key_t          ngx_core_tls_key;
 #endif
