summaryrefslogtreecommitdiff
path: root/src/mod_rrdtool.c
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2017-09-10 15:28:51 -0400
committerGlenn Strauss <gstrauss@gluelogic.com>2017-09-10 16:24:34 -0400
commit9030cfaecf07fc2426b01f6f3a1df442ccdd3ebb (patch)
tree953b0a4c4e8b7a7ac79adb67f0d5c2111d895c5d /src/mod_rrdtool.c
parent26dce93086ba46a3d9ead391b33b8a02515416ae (diff)
downloadlighttpd-git-9030cfaecf07fc2426b01f6f3a1df442ccdd3ebb.tar.gz
[core] SIGCHLD handle_waitpid hook for modules
centralize most waitpid() handling in core server, with hooks for modules to be informed of pid and status when a process exits. This enables faster discovery (and restart) of exited processes, and also allows for lighttpd to manage backend processes in the parent (master) process when server.max-worker > 0.
Diffstat (limited to 'src/mod_rrdtool.c')
-rw-r--r--src/mod_rrdtool.c85
1 files changed, 67 insertions, 18 deletions
diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c
index 8b80e151..2b8a3788 100644
--- a/src/mod_rrdtool.c
+++ b/src/mod_rrdtool.c
@@ -32,8 +32,10 @@ typedef struct {
int read_fd, write_fd;
pid_t rrdtool_pid;
+ pid_t srv_pid;
int rrdtool_running;
+ time_t rrdtool_startup_ts;
plugin_config **config_storage;
plugin_config conf;
@@ -73,9 +75,10 @@ FREE_FUNC(mod_rrd_free) {
free(p->config_storage);
- if (p->rrdtool_pid > 0) {
- close(p->read_fd);
- close(p->write_fd);
+ if (p->read_fd >= 0) close(p->read_fd);
+ if (p->write_fd >= 0) close(p->write_fd);
+
+ if (p->rrdtool_pid > 0 && p->srv_pid == srv->pid) {
/* collect status */
while (-1 == waitpid(p->rrdtool_pid, NULL, 0) && errno == EINTR) ;
}
@@ -89,6 +92,13 @@ static int mod_rrd_create_pipe(server *srv, plugin_data *p) {
char *args[3];
int to_rrdtool_fds[2];
int from_rrdtool_fds[2];
+ /* mod_rrdtool does not work with server.max-workers > 0
+ * since the data between workers is not aggregated,
+ * and it is not valid to send data to rrdtool more than once a sec
+ * (which would happen with multiple workers writing to same pipe)
+ * If pipes were to be shared, then existing pipes would need to be
+ * reused here, if they already exist (not -1), and after flushing
+ * existing contents (read and discard from read-end of pipes). */
if (pipe(to_rrdtool_fds)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
"pipe failed: ", strerror(errno));
@@ -110,8 +120,11 @@ static int mod_rrd_create_pipe(server *srv, plugin_data *p) {
if (-1 != p->rrdtool_pid) {
close(from_rrdtool_fds[1]);
close(to_rrdtool_fds[0]);
+ if (p->read_fd >= 0) close(p->read_fd);
+ if (p->write_fd >= 0) close(p->write_fd);
p->write_fd = to_rrdtool_fds[1];
p->read_fd = from_rrdtool_fds[0];
+ p->srv_pid = srv->pid;
return 0;
} else {
log_error_write(srv, __FILE__, __LINE__, "SBss", "fork/exec(", p->conf.path_rrdtool_bin, "):", strerror(errno));
@@ -266,6 +279,16 @@ static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p
}
#undef PATCH
+static int mod_rrd_exec(server *srv, plugin_data *p) {
+ if (mod_rrd_create_pipe(srv, p)) {
+ return -1;
+ }
+
+ p->rrdtool_running = 1;
+ p->rrdtool_startup_ts = srv->cur_ts;
+ return 0;
+}
+
SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
plugin_data *p = p_d;
size_t i;
@@ -316,6 +339,8 @@ SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
p->rrdtool_running = 0;
+ p->read_fd = -1;
+ p->write_fd = -1;
if (!activate) return HANDLER_GO_ON;
@@ -327,21 +352,30 @@ SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
return HANDLER_ERROR;
}
- /* open the pipe to rrdtool */
- if (mod_rrd_create_pipe(srv, p)) {
- return HANDLER_ERROR;
- }
-
- p->rrdtool_running = 1;
+ return 0 == mod_rrd_exec(srv, p) ? HANDLER_GO_ON : HANDLER_ERROR;
+}
- return HANDLER_GO_ON;
+static void mod_rrd_fatal_error(server *srv, plugin_data *p) {
+ /* future: might send kill() signal to p->rrdtool_pid to trigger restart */
+ p->rrdtool_running = 0;
+ UNUSED(srv);
}
TRIGGER_FUNC(mod_rrd_trigger) {
plugin_data *p = p_d;
size_t i;
- if (!p->rrdtool_running) return HANDLER_GO_ON;
+ if (!p->rrdtool_running) {
+ /* limit restart to once every 5 sec */
+ /*(0 == p->rrdtool_pid if never activated; not used)*/
+ if (-1 == p->rrdtool_pid
+ && p->srv_pid == srv->pid
+ && p->rrdtool_startup_ts + 5 < srv->cur_ts) {
+ mod_rrd_exec(srv, p);
+ }
+ return HANDLER_GO_ON;
+ }
+
if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
for (i = 0; i < srv->config_context->used; i++) {
@@ -364,20 +398,18 @@ TRIGGER_FUNC(mod_rrd_trigger) {
buffer_append_string_len(p->cmd, CONST_STR_LEN("\n"));
if (-1 == safe_write(p->write_fd, CONST_BUF_LEN(p->cmd))) {
- p->rrdtool_running = 0;
-
log_error_write(srv, __FILE__, __LINE__, "ss",
"rrdtool-write: failed", strerror(errno));
+ mod_rrd_fatal_error(srv, p);
return HANDLER_ERROR;
}
if (-1 == safe_read(p->read_fd, p->resp)) {
- p->rrdtool_running = 0;
-
log_error_write(srv, __FILE__, __LINE__, "ss",
"rrdtool-read: failed", strerror(errno));
+ mod_rrd_fatal_error(srv, p);
return HANDLER_ERROR;
}
@@ -385,11 +417,10 @@ TRIGGER_FUNC(mod_rrd_trigger) {
p->resp->ptr[1] != 'K') {
/* don't fail on this error if we just started (graceful restart, the old one might have just updated too) */
if (!(strstr(p->resp->ptr, "(minimum one second step)") && (srv->cur_ts - srv->startup_ts < 3))) {
- p->rrdtool_running = 0;
-
log_error_write(srv, __FILE__, __LINE__, "sbb",
"rrdtool-response:", p->cmd, p->resp);
+ mod_rrd_fatal_error(srv, p);
return HANDLER_ERROR;
}
}
@@ -401,11 +432,28 @@ TRIGGER_FUNC(mod_rrd_trigger) {
return HANDLER_GO_ON;
}
+static handler_t mod_rrd_waitpid_cb(server *srv, void *p_d, pid_t pid, int status) {
+ plugin_data *p = p_d;
+ if (pid != p->rrdtool_pid) return HANDLER_GO_ON;
+ if (srv->pid != p->srv_pid) return HANDLER_GO_ON;
+
+ p->rrdtool_running = 0;
+ p->rrdtool_pid = -1;
+
+ /* limit restart to once every 5 sec */
+ if (p->rrdtool_startup_ts + 5 < srv->cur_ts)
+ mod_rrd_exec(srv, p);
+
+ UNUSED(status);
+ return HANDLER_FINISHED;
+}
+
REQUESTDONE_FUNC(mod_rrd_account) {
plugin_data *p = p_d;
+ /*(0 == p->rrdtool_pid if never activated; not used)*/
+ if (0 == p->rrdtool_pid) return HANDLER_GO_ON;
mod_rrd_patch_connection(srv, con, p);
- if (!p->rrdtool_running) return HANDLER_GO_ON;
*(p->conf.requests_ptr) += 1;
*(p->conf.bytes_written_ptr) += con->bytes_written;
@@ -424,6 +472,7 @@ int mod_rrdtool_plugin_init(plugin *p) {
p->set_defaults= mod_rrd_set_defaults;
p->handle_trigger = mod_rrd_trigger;
+ p->handle_waitpid = mod_rrd_waitpid_cb;
p->handle_request_done = mod_rrd_account;
p->data = NULL;