From: HiepNV <[email protected]>
Signed-off-by: root <[email protected]>
---
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 <[email protected]>
+ *
+ * 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