service-monitor.c revision 6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "common.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "array.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "ioloop.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "fd-close-on-exec.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "hash.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "service.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "service-process.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "service-process-notify.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "service-log.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include "service-monitor.h"
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include <unistd.h>
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include <sys/wait.h>
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#include <syslog.h>
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina#define THROTTLE_TIMEOUT (1000*60)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_monitor_stop(struct service *service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_monitor_listen_start(struct service *service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_monitor_listen_stop(struct service *service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_status_input(struct service *service)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina{
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina struct master_status status;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina struct service_process *process;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina ssize_t ret;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina ret = read(service->status_fd[0], &status, sizeof(status));
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina switch (ret) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina case 0:
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_error(service, "read(status) failed: EOF");
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_stop(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina case -1:
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_error(service, "read(status) failed: %m");
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_stop(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina default:
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_error(service, "child %s sent partial status update "
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina "(%d bytes)", dec2str(status.pid), (int)ret);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina case sizeof(status):
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina break;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina process = hash_table_lookup(service->list->pids, &status.pid);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (process == NULL) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* we've probably wait()ed it away already. ignore */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (process->uid != status.uid || process->service != service) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* a) Process was closed and another process was created with
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina the same PID, but we're still receiving status update from
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina the old process.
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina b) Some process is trying to corrupt our internal state by
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina trying to pretend to be someone else. We could use stronger
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina randomness here, but the worst they can do is DoS and there
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina are already more serious problems if someone is able to do
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina this.. */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_error(service, "Ignoring invalid update from child %s "
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina "(UID=%u)", dec2str(status.pid), status.uid);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (process->to_status != NULL) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* first status notification */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina timeout_remove(&process->to_status);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (process->available_count == status.available_count)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (process->available_count > status.available_count) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* process started servicing requests */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina process->total_count +=
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina process->available_count - status.available_count;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (status.available_count == 0) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina i_assert(service->process_avail > 0);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (--service->process_avail == 0)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_listen_start(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina process->idle_start = 0;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina } else {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* process finished servicing requests */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (process->available_count == 0) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (service->process_avail++ == 0)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_listen_stop(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina i_assert(service->process_avail <=
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service->process_count);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (status.available_count == service->set->client_limit)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina process->idle_start = ioloop_time;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina process->available_count = status.available_count;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina}
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_throttle_timeout(struct service *service)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina{
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina timeout_remove(&service->to_throttle);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_listen_start(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina}
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březinastatic void service_monitor_throttle(struct service *service)
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina{
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (service->to_throttle != NULL)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina return;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_error(service, "command startup failed, throttling");
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_listen_stop(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service->to_throttle = timeout_add(THROTTLE_TIMEOUT,
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_throttle_timeout, service);
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina}
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březinastatic void service_accept(struct service *service)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina{
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina i_assert(service->process_avail == 0);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service->process_count == service->process_limit) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* we've reached our limits, new connections will have to
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina wait until there are more processes available */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service->listen_pending = TRUE;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_listen_stop(service);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina return;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* create a child process and let it accept() this connection */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service_process_create(service, NULL, NULL) == NULL)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_throttle(service);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina else
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_listen_stop(service);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina}
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinastatic void service_monitor_listen_start(struct service *service)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina{
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina struct service_listener *const *listeners;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina unsigned int i, count;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service->listen_pending = FALSE;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina listeners = array_get(&service->listeners, &count);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina for (i = 0; i < count; i++) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (listeners[i]->io == NULL && listeners[i]->fd != -1) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina listeners[i]->io = io_add(listeners[i]->fd, IO_READ,
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_accept, service);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina}
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinastatic void service_monitor_listen_stop(struct service *service)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina{
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina struct service_listener *const *listeners;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina unsigned int i, count;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina listeners = array_get(&service->listeners, &count);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina for (i = 0; i < count; i++) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina struct service_listener *l = listeners[i];
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (l->io != NULL)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina io_remove(&l->io);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina}
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinavoid services_monitor_start(struct service_list *service_list)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina{
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina struct service *const *services;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina unsigned int i, count;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina services_log_init(service_list);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina services = array_get(&service_list->services, &count);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina for (i = 0; i < count; i++) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (services[i]->status_fd[0] == -1) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina /* we haven't yet created status pipe */
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (pipe(services[i]->status_fd) < 0) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_error(services[i], "pipe() failed: %m");
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina continue;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina net_set_nonblock(services[i]->status_fd[0], TRUE);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina fd_close_on_exec(services[i]->status_fd[0], TRUE);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina net_set_nonblock(services[i]->status_fd[1], TRUE);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina fd_close_on_exec(services[i]->status_fd[1], TRUE);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina services[i]->io_status =
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina io_add(services[i]->status_fd[0], IO_READ,
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_status_input, services[i]);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (services[i]->status_fd[0] != -1)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_listen_start(services[i]);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service_process_create(service_list->log, NULL, NULL) != NULL)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_listen_stop(service_list->log);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service_process_create(service_list->config, NULL, NULL) != NULL)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_listen_stop(service_list->config);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina}
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinastatic void service_monitor_stop(struct service *service)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina{
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina int i;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service->io_status != NULL)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina io_remove(&service->io_status);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service->status_fd[0] != -1) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina for (i = 0; i < 2; i++) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (close(service->status_fd[i]) < 0) {
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_error(service,
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina "close(status fd) failed: %m");
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service->status_fd[i] = -1;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina }
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_listen_stop(service);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (service->to_throttle != NULL)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina timeout_remove(&service->to_throttle);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina}
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinavoid services_monitor_stop(struct service_list *service_list)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina{
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina struct service *const *services;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina unsigned int i, count;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina services = array_get(&service_list->services, &count);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina for (i = 0; i < count; i++)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_monitor_stop(services[i]);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina services_log_deinit(service_list);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina}
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březinastatic void service_process_failure(struct service_process *process, int status)
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina{
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina struct service *service = process->service;
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina service_process_log_status_error(process, status);
10a28f461c25d788ff4dcffefa881e7aa724a25dPavel Březina if (process->total_count == 0)
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina service_monitor_throttle(service);
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina if (service->list->anvil_kills != NULL)
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina service_process_notify_add(service->list->anvil_kills, process);
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina}
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březinavoid services_monitor_reap_children(struct service_list *service_list)
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina{
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina struct service_process *process;
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina struct service *service;
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina pid_t pid;
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina int status;
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina process = hash_table_lookup(service_list->pids, &pid);
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina if (process == NULL) {
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina i_error("waitpid() returned unknown PID %s",
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina dec2str(pid));
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina continue;
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina }
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina
ca6dd8e7ac91c7f8e3b4d55206d4f39791ab7149Pavel Březina service = process->service;
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (status == 0) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* success */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (service->listen_pending)
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_monitor_listen_start(service);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina } else {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_process_failure(process, status);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina }
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina service_process_destroy(process);
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (service->process_avail == 0 && service->to_throttle == NULL)
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek service_monitor_listen_start(service);
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek }
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek}
4e5e846de22407f825fe3b4040d79606818a2419Jakub Hrozek