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