service-monitor.c revision e59faf65ce864fe95dc00f5d52b8323cdbd0608a
/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "array.h"
#include "ioloop.h"
#include "fd-close-on-exec.h"
#include "hash.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "service.h"
#include "service-process.h"
#include "service-process-notify.h"
#include "service-anvil.h"
#include "service-log.h"
#include "service-monitor.h"
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60
#define SERVICE_DROP_WARN_INTERVAL_SECS 60
{
/* we don't have any extra idling processes anymore. */
} else {
}
}
}
const struct master_status *status)
{
process->total_count +=
process->idle_start = 0;
if (status->available_count != 0)
return;
/* process used up all of its clients */
service->process_avail--;
service->process_avail == 0 &&
/* we may need to start more */
}
const struct master_status *status)
{
if (process->available_count == 0) {
/* process can accept more clients again */
if (service->process_avail++ == 0)
}
/* we have more processes than we really need.
add a bit of randomness so that we don't send the
signal to all of them at once */
process);
}
}
}
{
struct master_status status;
struct service_process *process;
switch (ret) {
case 0:
return;
case -1:
return;
default:
return;
case sizeof(status):
break;
}
/* we've probably wait()ed it away already. ignore */
return;
}
/* a) Process was closed and another process was created with
the same PID, but we're still receiving status update from
the old process.
b) Some process is trying to corrupt our internal state by
trying to pretend to be someone else. We could use stronger
randomness here, but the worst they can do is DoS and there
are already more serious problems if someone is able to do
this.. */
return;
}
/* first status notification */
}
return;
/* process started servicing some more clients */
} else {
/* process finished servicing some clients */
}
}
{
return;
}
{
if (service->last_drop_warning +
i_warning("service(%s): process_limit reached, "
"client connections are being dropped",
}
/* reached process limit, notify processes that they
need to start killing existing connections if they
reach connection limit */
}
}
{
/* we've reached our limits, new clients will have to
wait until there are more processes available */
return;
}
/* create a child process and let it accept() this connection */
else
}
{
unsigned int i, count;
return;
for (i = 0; i < count; i++) {
break;
}
}
/* we created some processes, they'll do the listening now */
}
}
{
struct service_listener *const *listeners;
if (service->process_avail > 0 ||
return;
struct service_listener *l = *listeners;
}
}
{
struct service_listener *const *listeners;
struct service_listener *l = *listeners;
}
}
{
int fd;
return 0;
T_BEGIN {
const char *path;
if (fd == -1) {
path);
} else {
}
} T_END;
}
{
if (service_login_create_notify_fd(service) < 0)
continue;
}
/* we haven't yet created status pipe */
continue;
}
}
}
}
}
{
int i;
for (i = 0; i < 2; i++) {
"close(status fd) failed: %m");
}
}
}
"close(login notify fd) failed: %m");
}
}
}
{
}
{
if (process->total_count == 0)
}
void services_monitor_reap_children(void)
{
struct service_process *process;
int status;
bool service_stopped;
i_error("waitpid() returned unknown PID %s",
continue;
}
if (status == 0) {
/* success */
if (service->listen_pending)
} else {
}
if (!service_stopped) {
}
}
}