From: HiepNV <hie...@vccloud.vn>

Signed-off-by: root <hie...@vccloud.vn>
---
 Makefile                  |   4 +-
 include/proto/shm_proxy.h |  28 +++
 src/dumpstats.c           |  59 ++++++-
 src/haproxy.c             |  48 ++++-
 src/shm_proxy.c           | 439 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 571 insertions(+), 7 deletions(-)
 create mode 100644 include/proto/shm_proxy.h
 create mode 100644 src/shm_proxy.c

diff --git a/Makefile b/Makefile
index 3c9ee24..7a7a67a 100644
--- a/Makefile
+++ b/Makefile
@@ -204,7 +204,7 @@ CFLAGS = $(ARCH_FLAGS) $(CPU_CFLAGS) $(DEBUG_CFLAGS) 
$(SPEC_CFLAGS)
 # These LDFLAGS are used as the first "ld" options, regardless of any library
 # path or any other option. They may be changed to add any linker-specific
 # option at the beginning of the ld command line.
-LDFLAGS = $(ARCH_FLAGS) -g
+LDFLAGS = $(ARCH_FLAGS) -g -pthread
 
 #### Target system options
 # Depending on the target platform, some options are set, as well as some
@@ -707,7 +707,7 @@ OBJS = src/haproxy.o src/sessionhash.o src/base64.o 
src/protocol.o \
        src/session.o src/stream.o src/hdr_idx.o src/ev_select.o src/signal.o \
        src/acl.o src/sample.o src/memory.o src/freq_ctr.o src/auth.o \
        src/compression.o src/payload.o src/hash.o src/pattern.o src/map.o \
-       src/namespace.o src/mailers.o
+       src/namespace.o src/mailers.o src/shm_proxy.o
 
 EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o \
               $(EBTREE_DIR)/eb32tree.o $(EBTREE_DIR)/eb64tree.o \
diff --git a/include/proto/shm_proxy.h b/include/proto/shm_proxy.h
new file mode 100644
index 0000000..2f4e5c9
--- /dev/null
+++ b/include/proto/shm_proxy.h
@@ -0,0 +1,28 @@
+#ifndef _PROTO_SHM_PROXY_H
+#define _PROTO_SHM_PROXY_H
+
+#include <stdio.h>
+
+#include <types/proxy.h>
+
+extern int *children; /* List of children pid */
+
+/* allocate shared memory for shared proxy stats
+ *
+ * return 0 on success and -1 on error
+ */
+extern int shm_proxy_alloc(void);
+
+/* initialize shared proxy stats to current proxy stats */
+extern int shm_proxy_init(void);
+
+/* update shared proxy stats */
+extern int shm_proxy_update(void);
+
+/* copy shared proxy stats to a private memory */
+extern struct proxy *shm_proxy_copy();
+
+/* cleanup */
+extern void shm_proxy_free(void);
+
+#endif
diff --git a/src/dumpstats.c b/src/dumpstats.c
index b8e822f..cbbd6a9 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <pwd.h>
 #include <grp.h>
+#include <signal.h>
 
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -63,6 +64,7 @@
 #include <proto/raw_sock.h>
 #include <proto/stream_interface.h>
 #include <proto/task.h>
+#include <proto/shm_proxy.h>
 
 #ifdef USE_OPENSSL
 #include <proto/ssl_sock.h>
@@ -230,6 +232,8 @@ enum {
 };
 
 extern const char *stat_status_codes[];
+/* Pointer store copy of shm_proxy */
+static struct proxy *shm_proxy = NULL;
 
 /* allocate a new stats frontend named <name>, and return it
  * (or NULL in case of lack of memory).
@@ -2210,6 +2214,48 @@ static int stats_sock_parse_request(struct 
stream_interface *si, char *line)
        return 1;
 }
 
+/* Update shm_proxy for multi-process mode */
+static void update_shm_proxy()
+{
+       if (global.nbproc > 1) {
+               size_t i;
+               sigset_t mask;
+               struct timespec timeout = {
+                       .tv_sec = 0,
+                       .tv_nsec = 100 * 1000 * 1000,
+               };
+
+               if (sigemptyset(&mask) < 0) {
+                       Warning("Call sigemptyset error: %s\n", 
strerror(errno));
+                       return;
+               }
+               if (sigaddset(&mask, SIGCONT) < 0) {
+                       Warning("Add SIGCONT to signal set error: %s\n",
+                               strerror(errno));
+                       return;
+               }
+               if (shm_proxy_init() < 0) {
+                       Warning("Cannot initialize shm_proxy.\n");
+                       return;
+               }
+               for (i = 0; i < global.nbproc; i++) {
+                       if (children[i] != pid && children[i] > 0) {
+                               /* Update shm_proxy for process i */
+                               if(kill(children[i], SIGUSR2) != 0) {
+                                       Warning("Cannot send signal SIGUSR2 "
+                                               "to process %d: %s\n",
+                                               children[i], strerror(errno));
+                               }
+                               /* Wait 100 milisecond or received SIGCONT */
+                               sigtimedwait(&mask, NULL, &timeout);
+                       }
+               }
+               if (!(shm_proxy = shm_proxy_copy())) {
+                       Warning("Cannot copy shm_proxy to private memory\n");
+               }
+       }
+}
+
 /* This I/O handler runs as an applet embedded in a stream interface. It is
  * used to processes I/O from/to the stats unix socket. The system relies on a
  * state machine handling requests and various responses. We read a request,
@@ -2229,6 +2275,8 @@ static void cli_io_handler(struct appctx *appctx)
        if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
                goto out;
 
+       update_shm_proxy();
+
        while (1) {
                if (appctx->st0 == STAT_CLI_INIT) {
                        /* Stats output not initialized yet */
@@ -4383,7 +4431,10 @@ static int stats_dump_stat_to_buffer(struct 
stream_interface *si, struct uri_aut
                        }
                }
 
-               appctx->ctx.stats.px = proxy;
+               if (shm_proxy)
+                       appctx->ctx.stats.px = shm_proxy;
+               else
+                       appctx->ctx.stats.px = proxy;
                appctx->ctx.stats.px_st = STAT_PX_ST_INIT;
                appctx->st2 = STAT_ST_LIST;
                /* fall through */
@@ -4859,6 +4910,7 @@ static void http_stats_io_handler(struct appctx *appctx)
 
        /* all states are processed in sequence */
        if (appctx->st0 == STAT_HTTP_HEAD) {
+               update_shm_proxy();
                if (stats_send_http_headers(si)) {
                        if (s->txn->meth == HTTP_METH_HEAD)
                                appctx->st0 = STAT_HTTP_DONE;
@@ -6039,7 +6091,10 @@ static int stats_dump_errors_to_buffer(struct 
stream_interface *si)
                        return 0;
                }
 
-               appctx->ctx.errors.px = proxy;
+               if (!shm_proxy)
+                       appctx->ctx.errors.px = proxy;
+               else
+                       appctx->ctx.errors.px = shm_proxy;
                appctx->ctx.errors.buf = 0;
                appctx->ctx.errors.bol = 0;
                appctx->ctx.errors.ptr = -1;
diff --git a/src/haproxy.c b/src/haproxy.c
index 474179c..cc76cd6 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -102,6 +102,7 @@
 #include <proto/stream.h>
 #include <proto/signal.h>
 #include <proto/task.h>
+#include <proto/shm_proxy.h>
 
 #ifdef CONFIG_HAP_CTTPROXY
 #include <proto/cttproxy.h>
@@ -120,6 +121,7 @@ extern const struct comp_algo comp_algos[];
 /* list of config files */
 static struct list cfg_cfgfiles = LIST_HEAD_INIT(cfg_cfgfiles);
 int  pid;                      /* current process id */
+int *children = NULL;          /* children pid */
 int  relative_pid = 1;         /* process id starting at 1 */
 
 /* global options */
@@ -510,6 +512,31 @@ void dump(struct sig_handler *sh)
        pool_gc2();
 }
 
+/* Update shm_proxy when received SIGUSR2 signal */
+void sig_update_shm_proxy(struct sig_handler *sh)
+{
+       int i;
+       Warning("SIGUSR2 received, update shm_proxy\n");
+       if (shm_proxy_update() != 0)
+               Warning("Update shm_proxy error!\n");
+       /* Send SIGCONT to all processes except current process to
+        * wake up porcess sent SIGUSR2 */
+       for (i = 0; i < global.nbproc; i++) {
+               if (children[i] != pid && children[i] > 0)
+                       if(kill(children[i], SIGCONT) != 0) {
+                               Warning("Cannot send signal SIGCONT to "
+                                       "process %d: %s\n",
+                                       children[i], strerror(errno));
+                       }
+       }
+}
+
+/* Catch then bypass a specified signal */
+void sig_pass(struct sig_handler *sh)
+{
+       return;
+}
+
 /*
  * This function initializes all the necessary variables. It only returns
  * if everything is OK. If something fails, it exits.
@@ -1548,6 +1575,11 @@ int main(int argc, char **argv)
         */
        signal_register_fct(SIGPIPE, NULL, 0);
 
+       /* SIGUSR2 used to update shm_proxy */
+       signal_register_fct(SIGUSR2, sig_update_shm_proxy, SIGUSR2);
+       /* SIGCONT used to wakeup suspending process */
+       signal_register_fct(SIGCONT, sig_pass, SIGCONT);
+
        /* ulimits */
        if (!global.rlimit_nofile)
                global.rlimit_nofile = global.maxsock;
@@ -1740,9 +1772,19 @@ int main(int argc, char **argv)
        if (global.mode & (MODE_DAEMON | MODE_SYSTEMD)) {
                struct proxy *px;
                int ret = 0;
-               int *children = calloc(global.nbproc, sizeof(int));
                int proc;
 
+               /* Multi-process mode */
+               if (global.nbproc > 1) {
+                       if (shm_proxy_alloc() < 0) {
+                               Alert("[%s.main()] Cannot allocate "
+                                     "shared memory.\n", argv[0]);
+                               exit(1);
+                       }
+               } else {
+                       children = malloc(sizeof(int) * global.nbproc);
+               }
+
                /* the father launches the required number of processes */
                for (proc = 0; proc < global.nbproc; proc++) {
                        ret = fork();
@@ -1795,11 +1837,11 @@ int main(int argc, char **argv)
                                for (proc = 0; proc < global.nbproc; proc++)
                                        while (waitpid(children[proc], NULL, 0) 
== -1 && errno == EINTR);
                        }
+                       /* Release shared memory when all children processes 
exit */
+                       shm_proxy_free();
                        exit(0); /* parent must leave */
                }
 
-               free(children);
-               children = NULL;
                /* if we're NOT in QUIET mode, we should now close the 3 first 
FDs to ensure
                 * that we can detach from the TTY. We MUST NOT do it in other 
cases since
                 * it would have already be done, and 0-2 would have been 
affected to listening
diff --git a/src/shm_proxy.c b/src/shm_proxy.c
new file mode 100644
index 0000000..14cdc4e
--- /dev/null
+++ b/src/shm_proxy.c
@@ -0,0 +1,439 @@
+/*
+ * Proxy variables and functions.
+ *
+ * Copyright 2000-2009 Willy Tarreau <w...@1wt.eu>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <semaphore.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+
+#include <proto/proxy.h>
+#include <proto/shm_proxy.h>
+
+#include <types/global.h>
+#include <types/proxy.h>
+#include <types/server.h>
+#include <types/listener.h>
+#include <types/counters.h>
+
+#include <common/mini-clist.h>
+
+
+/* Shared proxys stats in multi-process mode */
+static struct proxy *shm_proxy = NULL;
+static size_t shm_size;
+static int shmid;
+
+/* Semaphore to manupulate with shared memory */
+static sem_t *sem;
+
+static void update_frontend(struct proxy *dest, struct proxy *src) {
+       /* sessions rate : current */
+       dest->fe_sess_per_sec.curr_ctr += src->fe_sess_per_sec.curr_ctr;
+       dest->fe_sess_per_sec.prev_ctr += src->fe_sess_per_sec.prev_ctr;
+       dest->fe_conn_per_sec.curr_ctr += src->fe_conn_per_sec.curr_ctr;
+       dest->fe_conn_per_sec.prev_ctr += src->fe_conn_per_sec.prev_ctr;
+       dest->fe_req_per_sec.curr_ctr += src->fe_req_per_sec.curr_ctr;
+       dest->fe_req_per_sec.prev_ctr += src->fe_req_per_sec.prev_ctr;
+       /* sessions rate: max */
+       dest->fe_counters.sps_max += src->fe_counters.sps_max;
+       dest->fe_counters.cps_max += src->fe_counters.cps_max;
+       dest->fe_counters.p.http.rps_max += src->fe_counters.p.http.rps_max;
+       /* sessions rate: limit */
+       dest->fe_sps_lim += src->fe_sps_lim;
+       /* sessions: current, max, limit, total */
+       dest->feconn += src->feconn;
+       dest->fe_counters.conn_max += src->fe_counters.conn_max;
+       dest->maxconn += src->maxconn;
+       dest->fe_counters.cum_sess += src->fe_counters.cum_sess;
+       dest->fe_counters.cum_conn += src->fe_counters.cum_conn;
+       /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
+       dest->fe_counters.p.http.cum_req += src->fe_counters.p.http.cum_req;  
+       dest->fe_counters.p.http.rsp[0] += src->fe_counters.p.http.rsp[0];
+       dest->fe_counters.p.http.rsp[1] += src->fe_counters.p.http.rsp[1];
+       dest->fe_counters.p.http.comp_rsp += src->fe_counters.p.http.comp_rsp;
+       dest->fe_counters.p.http.rsp[2] += src->fe_counters.p.http.rsp[2]; 
+       dest->fe_counters.p.http.rsp[3] += src->fe_counters.p.http.rsp[3];
+       dest->fe_counters.p.http.rsp[4] += src->fe_counters.p.http.rsp[4]; 
+       dest->fe_counters.intercepted_req += src->fe_counters.intercepted_req;
+       dest->fe_counters.p.http.rsp[5] += src->fe_counters.p.http.rsp[5];
+       /* bytes: in */
+       dest->fe_counters.bytes_in += src->fe_counters.bytes_in;
+       /* bytes: out + compression stats */
+       dest->fe_counters.comp_in += src->fe_counters.comp_in;
+       dest->fe_counters.comp_byp += src->fe_counters.comp_byp;
+       dest->fe_counters.bytes_out += src->fe_counters.bytes_out;
+       dest->fe_counters.comp_out += src->fe_counters.comp_out;
+       /* denied, errors */
+       dest->fe_counters.denied_req += src->fe_counters.denied_req;
+       dest->fe_counters.denied_resp += src->fe_counters.denied_resp;
+       dest->fe_counters.failed_req += src->fe_counters.failed_req;
+}
+
+static void update_backend(struct proxy *dest, struct proxy *src) {
+       /* queue : current, max */
+       dest->nbpend += src->nbpend;
+       dest->totpend += src->totpend;
+       dest->be_counters.nbpend_max += src->be_counters.nbpend_max;
+       dest->be_sess_per_sec.curr_ctr += src->be_sess_per_sec.curr_ctr;
+       dest->be_sess_per_sec.prev_ctr += src->be_sess_per_sec.prev_ctr;
+       dest->be_counters.sps_max += src->be_counters.sps_max;
+       /* sessions: current, max, limit, total */
+       dest->beconn += src->beconn;
+       dest->be_counters.conn_max += src->be_counters.conn_max;
+       dest->fullconn += src->fullconn;
+       dest->be_counters.cum_conn += src->be_counters.cum_conn;
+       /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
+       dest->be_counters.p.http.cum_req += src->be_counters.p.http.cum_req;
+       dest->be_counters.p.http.rsp[0] += src->be_counters.p.http.rsp[0];
+       dest->be_counters.p.http.rsp[1] += src->be_counters.p.http.rsp[1];
+       dest->be_counters.p.http.rsp[2] += src->be_counters.p.http.rsp[2];
+       dest->be_counters.p.http.rsp[3] += src->be_counters.p.http.rsp[3];
+       dest->be_counters.p.http.rsp[4] += src->be_counters.p.http.rsp[4];
+       dest->be_counters.p.http.rsp[5] += src->be_counters.p.http.rsp[5];
+       dest->be_counters.p.http.comp_rsp += src->be_counters.p.http.comp_rsp;
+       dest->be_counters.intercepted_req += src->be_counters.intercepted_req;
+       /* sessions: lbtot */
+       dest->be_counters.cum_lbconn += src->be_counters.cum_lbconn;
+       /* bytes: in */
+       dest->be_counters.bytes_in += src->be_counters.bytes_in;
+       /* bytes:out + compression stats */
+       dest->be_counters.comp_in += src->be_counters.comp_in;
+       dest->be_counters.comp_byp += src->be_counters.comp_byp;
+       dest->be_counters.bytes_out += src->be_counters.bytes_out;
+       dest->be_counters.comp_out += src->be_counters.comp_out;
+       /* denied: req, resp */
+       dest->be_counters.denied_req += src->be_counters.denied_req;
+       dest->be_counters.denied_resp += src->be_counters.denied_resp;
+       /* errors : request, connect */
+       dest->be_counters.failed_conns += src->be_counters.failed_conns;
+       dest->be_counters.failed_resp += src->be_counters.failed_resp;
+       dest->be_counters.cli_aborts += src->be_counters.cli_aborts;
+       dest->be_counters.srv_aborts += src->be_counters.srv_aborts;
+       /* warnings: retries, redispatches */
+       dest->be_counters.retries += src->be_counters.retries;
+       dest->be_counters.redispatches += src->be_counters.redispatches;
+}
+
+static void update_server(struct server *dest, struct server *src)
+{
+       /* queue : current, max, limit */
+       dest->nbpend += src->nbpend;
+       dest->counters.nbpend_max += src->counters.nbpend_max;
+       dest->maxqueue += src->maxqueue;
+       /* sessions rate : current, max, limit */
+       dest->sess_per_sec.curr_ctr += src->sess_per_sec.curr_ctr;
+       dest->sess_per_sec.prev_ctr += src->sess_per_sec.prev_ctr;
+       dest->counters.sps_max += src->counters.sps_max;
+       /* sessions: current, max, limit, total */
+       dest->cur_sess += src->cur_sess;
+       dest->counters.cur_sess_max += src->counters.cur_sess_max;
+       dest->maxconn += src->maxconn;
+       dest->counters.cum_sess += src->counters.cum_sess;
+       /* http response (via hover): 1xx, 2xx, 3xx, 4xx, 5xx, other */
+       dest->counters.p.http.rsp[0] += src->counters.p.http.rsp[0];
+       dest->counters.p.http.rsp[1] += src->counters.p.http.rsp[1];
+       dest->counters.p.http.rsp[2] += src->counters.p.http.rsp[2];
+       dest->counters.p.http.rsp[3] += src->counters.p.http.rsp[3];
+       dest->counters.p.http.rsp[4] += src->counters.p.http.rsp[4];
+       dest->counters.p.http.rsp[5] += src->counters.p.http.rsp[5];
+       /* sessions: lbtot, last */
+       dest->counters.cum_lbconn += src->counters.cum_lbconn;
+       /* bytes : in, out */
+       dest->counters.bytes_in += src->counters.bytes_in;
+       dest->counters.bytes_out += src->counters.bytes_out;
+       /* denied, errors */
+       dest->counters.failed_secu += src->counters.failed_secu;
+       dest->counters.failed_conns += src->counters.failed_conns;
+       dest->counters.failed_resp += src->counters.failed_resp;
+       dest->counters.cli_aborts += src->counters.cli_aborts;
+       dest->counters.srv_aborts += src->counters.srv_aborts;
+       /* warnings: retries, redispatches */
+       dest->counters.retries += src->counters.retries;
+       dest->counters.redispatches += src->counters.redispatches;
+}
+
+static void update_li(struct listener *dest, struct listener *src)
+{
+       /* sessions: current, max, limit, total, lbtot, lastsess */
+       dest->nbconn += src->nbconn;
+       dest->maxconn += src->maxconn;
+       dest->counters->conn_max += src->counters->conn_max;
+       dest->counters->cum_conn += src->counters->cum_conn;
+       /* bytes: in, out */
+       dest->counters->bytes_in += src->counters->bytes_in;
+       dest->counters->bytes_out += src->counters->bytes_out;
+       /* denied, errors */
+       dest->counters->denied_req += src->counters->denied_req;
+       dest->counters->denied_resp += src->counters->denied_resp;
+       dest->counters->failed_req += src->counters->failed_req;
+}
+
+int shm_proxy_alloc()
+{
+       struct proxy *px;
+       struct server *srv, *shm_srv;
+       struct listener *shm_li;
+       struct licounters *shm_lictr;
+       struct list *l;
+       char *shm_start = NULL;
+       size_t i, nbpx = 0, nbsrv = 0, nbli = 0, nblictr = 0;
+
+       /* Shared memory size:
+        * proxys + servers + listeners + licounters + sem + children
+        */
+       for (px = proxy; px != NULL; px = px->next) {
+               nbpx++;
+               for (srv = px->srv; srv != NULL; srv = srv->next)
+                       nbsrv++;
+               for (l = px->conf.listeners.n;
+                    l != &px->conf.listeners; l = l->n) {
+                       nbli++;
+                       if (LIST_ELEM(l, struct listener *, by_fe)->counters)
+                               nblictr++;
+               }
+       }
+       shm_size = sizeof(struct proxy) * nbpx + \
+                  sizeof(struct server) * nbsrv + \
+                  sizeof(struct listener) * nbli + \
+                  sizeof(struct licounters) * nblictr + \
+                  sizeof(sem_t) + sizeof(int) * global.nbproc;
+
+       /* Allocate shared memory to store shared proxy stats */
+       if ((shmid = shmget(IPC_PRIVATE, shm_size,
+                           IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR)) < 0)
+               return -1;
+       if ((shm_start = shmat(shmid, NULL, 0)) == (void *)-1)
+               return -1;
+
+       /* Shared memory structure:
+        * [proxys,servers,listeners,licounters,sem,children]
+        */
+       shm_proxy = (struct proxy *)shm_start;
+       shm_srv = (struct server *)(shm_proxy + nbpx);
+       shm_li = (struct listener *)(shm_srv + nbsrv);
+       shm_lictr = (struct licounters *)(shm_li + nbli);
+       sem = (sem_t *)(shm_lictr + nblictr);
+       children = (int *)(sem + 1);
+       for (i = 0, px = proxy; i < nbpx; i++, px = px->next) {
+               if (i < nbpx - 1)
+                       shm_proxy[i].next = &shm_proxy[i + 1];
+               else
+                       shm_proxy[i].next = NULL; /* End of proxy list */
+               if (px->srv != NULL) {
+                       /* Servers list of current proxy */
+                       for (srv = px->srv, shm_proxy[i].srv = shm_srv;
+                            srv->next != NULL; srv = srv->next) {
+                               shm_srv->next = shm_srv + 1;
+                               shm_srv++;
+                       }
+                       shm_srv->next = NULL; /* End of servers list */
+                       shm_srv++;
+               } else {
+                       shm_proxy[i].srv = NULL;
+               }
+               /* Listeners list of current proxy */
+               LIST_INIT(&shm_proxy[i].conf.listeners);
+               for (l = px->conf.listeners.n;
+                    l != &px->conf.listeners; l = l->n) {
+                       if (LIST_ELEM(l, struct listener *, by_fe)->counters)
+                               shm_li->counters = shm_lictr++;
+                       LIST_ADD(&shm_proxy[i].conf.listeners, &shm_li->by_fe);
+                       shm_li++;
+               }
+       }
+
+       /* Initialize mutex semaphore shared to all processes */
+       if (sem_init(sem, 1, 1) < 0)
+               return -2;
+
+       return 0;
+}
+
+int shm_proxy_init()
+{
+       struct proxy *px, *shm_px, *px_next;
+       struct listener *li, *shm_li;
+       struct licounters *lictr;
+       struct list *l, *shm_l, tmpl;
+       struct server *srv, *shm_srv, *srv_next;
+
+       /* Beginning of critical section */
+       if (sem_wait(sem) < 0)
+               return -1;
+
+       /* Copy stats of current proxy to shm_proxy */
+       for (px = proxy, shm_px = shm_proxy;
+            px != NULL; px = px->next, shm_px = shm_px->next) {
+               for (srv = px->srv, shm_srv = shm_px->srv;
+                    srv != NULL; srv = srv->next, shm_srv = shm_srv->next) {
+                       /* Copy server */
+                       srv_next = shm_srv->next;
+                       memcpy(shm_srv, srv, sizeof(struct server));
+                       shm_srv->next = srv_next;
+               }
+               for (l = px->conf.listeners.n,
+                    shm_l = shm_px->conf.listeners.n;
+                    l != &px->conf.listeners; l = l->n, shm_l = shm_l->n) {
+                       li = LIST_ELEM(l, struct listener *, by_fe);
+                       shm_li = LIST_ELEM(shm_l, struct listener *, by_fe);
+                       /* Copy listener counters */
+                       if (li->counters)
+                               memcpy(shm_li->counters, li->counters,
+                                      sizeof(struct licounters));
+                       /* Copy listenter */
+                       tmpl = *shm_l;
+                       lictr = shm_li->counters;
+                       memcpy(shm_li, li, sizeof(struct listener));
+                       shm_li->counters = lictr;
+                       *shm_l = tmpl;
+               }
+               /* Copy proxy */
+               px_next = shm_px->next;
+               srv = shm_px->srv;
+               tmpl = shm_px->conf.listeners;
+               memcpy(shm_px, px, sizeof(struct proxy));
+               shm_px->conf.listeners = tmpl;
+               shm_px->srv = srv;
+               shm_px->next = px_next;
+       }
+       /* End of critical section */
+       if (sem_post(sem) < 0)
+               return -2;
+
+       return 0;
+}
+
+int shm_proxy_update()
+{
+       struct proxy *px, *shm_px;
+       struct server *srv, *shm_srv;
+       struct list *l, *shm_l;
+       struct listener *shm_li, *li;
+
+       /* Beginning of critical section */
+       if (sem_wait(sem) < 0)
+               return -1;
+       /* Update shm_proxy from proxy */
+       for (px = proxy, shm_px = shm_proxy;
+            px != NULL; px = px->next, shm_px = shm_px->next) {
+               /* frontend */
+               update_frontend(shm_px, px);
+               /* listeners */
+               for (l = px->conf.listeners.n,
+                    shm_l = shm_px->conf.listeners.n;
+                    l != &px->conf.listeners; l = l->n, shm_l = shm_l->n) {
+                       shm_li = LIST_ELEM(shm_l, struct listener *, by_fe);
+                       li = LIST_ELEM(l, struct listener *, by_fe);
+                       if (li->counters)
+                               update_li(shm_li, li);
+               }
+               /* server */
+               for (srv = px->srv, shm_srv = shm_px->srv;
+                    srv != NULL; srv = srv->next, shm_srv = shm_srv->next) {
+                       update_server(shm_srv, srv);
+               }
+               /* backend */
+               update_backend(shm_px, px);
+       }
+       /* End of critical section */
+       if (sem_post(sem) < 0)
+               return -2;
+
+       return 0;
+}
+
+struct proxy *shm_proxy_copy()
+{
+       struct proxy *px;
+       struct server *srv, *shm_srv;
+       struct listener *li;
+       struct licounters *lictr;
+       struct list *l;
+       size_t len, i, nbpx = 0, nbsrv = 0, nbli = 0, nblictr = 0;
+
+       /* Memory size: proxys + servers + listeners + licounters */
+       for (px = proxy; px != NULL; px = px->next) {
+               nbpx++;
+               for (srv = px->srv; srv != NULL; srv = srv->next)
+                       nbsrv++;
+               for (l = px->conf.listeners.n;
+                    l != &px->conf.listeners; l = l->n) {
+                       nbli++;
+                       if (LIST_ELEM(l, struct listener *, by_fe)->counters)
+                               nblictr++;
+               }
+       }
+       len = sizeof(struct proxy) * nbpx + \
+             sizeof(struct server) * nbsrv + \
+             sizeof(struct listener) * nbli + \
+             sizeof(struct licounters) * nblictr;
+
+       /* Memory structure:
+        * [proxys,servers,listeners,licounters]
+        */
+       if(!(px = malloc(len)))
+               return NULL;
+       srv = (struct server *)(px + nbpx);
+       li = (struct listener *)(srv + nbsrv);
+       lictr = (struct licounters *)(li + nbli);
+
+       /* Beginning of critical section */
+       if (sem_wait(sem) < 0)
+               return NULL;
+       /* Copy to private memory address */
+       memcpy(px, shm_proxy, len);
+       for (i = 0; i < nbpx; i++) {
+               if (shm_proxy[i].next)
+                       px[i].next = &px[i + 1];
+               else
+                       px[i].next = NULL; /* End of proxys list */
+
+               /* Current proxy servers list */
+               if (shm_proxy[i].srv != NULL) {
+                       for (shm_srv = shm_proxy[i].srv, px[i].srv = srv;
+                            shm_srv->next != NULL; shm_srv = shm_srv->next) {
+                               srv->next = srv + 1;
+                               srv++;
+                       }
+                       srv->next = NULL;
+                       srv++;
+               } else { /* srv is NULL */
+                       px[i].srv = NULL;
+               }
+
+               /* Current proxy listeners list */
+               LIST_INIT(&px[i].conf.listeners);
+               for (l = shm_proxy[i].conf.listeners.n;
+                    l != &shm_proxy[i].conf.listeners; l = l->n) {
+                       if (LIST_ELEM(l, struct listener *, by_fe)->counters)
+                               li->counters = lictr++;
+                       LIST_ADD(&px[i].conf.listeners, &li->by_fe);
+                       li++;
+               }
+       }
+       /* End of critical section */
+       if (sem_post(sem) < 0)
+               return NULL;
+
+       return px;
+}
+
+void shm_proxy_free()
+{
+       if (shm_proxy) {
+               shmctl(shmid, IPC_RMID, NULL);
+               shm_proxy = NULL;
+       }
+}
-- 
1.9.1


Reply via email to