/* anvil never dies. it just gets moved to the new services list */
service = service_lookup_type(services, SERVICE_TYPE_ANVIL);
if (service != NULL) {
- while (service->processes != NULL)
- service_process_destroy(service->processes);
+ while (service->busy_processes != NULL)
+ service_process_destroy(service->busy_processes);
+ while (service->idle_processes_head != NULL)
+ service_process_destroy(service->idle_processes_head);
}
services_destroy(services, FALSE);
(long)process->last_kill_sent);
}
+static void
+master_client_process_status_list(struct master_client *client,
+ struct service_process *processes,
+ string_t *str)
+{
+ struct service_process *p;
+
+ for (p = processes; p != NULL; p = p->next) {
+ str_truncate(str, 0);
+ master_client_process_output(str, p);
+ o_stream_nsend(client->conn.output,
+ str_data(str), str_len(str));
+ }
+}
+
static int
master_client_process_status(struct master_client *client,
const char *const *args)
{
struct service *service;
- struct service_process *p;
string_t *str = t_str_new(128);
array_foreach_elem(&services->services, service) {
if (args[0] != NULL && !str_array_find(args, service->set->name))
continue;
- for (p = service->processes; p != NULL; p = p->next) {
- str_truncate(str, 0);
- master_client_process_output(str, p);
- o_stream_nsend(client->conn.output,
- str_data(str), str_len(str));
- }
+ master_client_process_status_list(client,
+ service->busy_processes, str);
+ master_client_process_status_list(client,
+ service->idle_processes_head, str);
}
o_stream_nsend_str(client->conn.output, "\n");
return 1;
#include "array.h"
#include "ioloop.h"
#include "hash.h"
+#include "llist.h"
#include "str.h"
#include "safe-mkstemp.h"
#include "time-util.h"
{
struct service *service = process->service;
+ if (process->idle_start != 0) {
+ /* idling process became busy */
+ DLLIST2_REMOVE(&service->idle_processes_head,
+ &service->idle_processes_tail, process);
+ DLLIST_PREPEND(&service->busy_processes, process);
+ process->idle_start = 0;
+ }
process->total_count +=
process->available_count - status->available_count;
- process->idle_start = 0;
timeout_remove(&process->to_idle);
if (process->available_count != service->client_limit)
return;
+
+ if (process->idle_start == 0) {
+ /* busy process started idling */
+ DLLIST_REMOVE(&service->busy_processes, process);
+ } else {
+ /* Idling process updated its status again to be idling. Maybe
+ it was busy for a little bit? Update its idle_start time. */
+ DLLIST2_REMOVE(&service->idle_processes_head,
+ &service->idle_processes_tail, process);
+ }
+ DLLIST2_APPEND(&service->idle_processes_head,
+ &service->idle_processes_tail, process);
process->idle_start = ioloop_time;
+
if (service->process_avail > service->set->process_min_avail &&
process->to_idle == NULL &&
service->idle_kill != UINT_MAX) {
}
}
-static bool service_processes_close_listeners(struct service *service)
+static bool
+service_processes_list_close_listeners(struct service *service,
+ struct service_process *processes)
{
- struct service_process *process = service->processes;
+ struct service_process *process = processes;
bool ret = FALSE;
for (; process != NULL; process = process->next) {
return ret;
}
+static bool service_processes_close_listeners(struct service *service)
+{
+ bool ret = FALSE;
+
+ if (service_processes_list_close_listeners(service,
+ service->busy_processes))
+ ret = TRUE;
+ if (service_processes_list_close_listeners(service,
+ service->idle_processes_head))
+ ret = TRUE;
+ return ret;
+}
+
static bool
service_list_processes_close_listeners(struct service_list *service_list)
{
}
process->available_count = service->client_limit;
+ process->idle_start = ioloop_time;
service->process_count_total++;
service->process_count++;
service->process_avail++;
- DLLIST_PREPEND(&service->processes, process);
+ DLLIST2_APPEND(&service->idle_processes_head,
+ &service->idle_processes_tail, process);
service_list_ref(service->list);
hash_table_insert(service_pids, POINTER_CAST(process->pid), process);
struct service *service = process->service;
struct service_list *service_list = service->list;
- DLLIST_REMOVE(&service->processes, process);
+ if (process->idle_start == 0)
+ DLLIST_REMOVE(&service->busy_processes, process);
+ else {
+ DLLIST2_REMOVE(&service->idle_processes_head,
+ &service->idle_processes_tail, process);
+ }
hash_table_remove(service_pids, POINTER_CAST(process->pid));
if (process->available_count > 0)
smaller than the correct value. */
unsigned int total_count;
- /* time when process started idling, or 0 if we're not idling */
+ /* Time when process started idling, or 0 if we're not idling. This is
+ updated when the process sends a notification via its status pipe
+ about the number of clients it is processing.
+
+ This field also determines whether the process is in the service's
+ "busy" or "idle" processes linked list. */
time_t idle_start;
/* kill process if it hits idle timeout */
struct timeout *to_idle;
return 0;
}
-unsigned int service_signal(struct service *service, int signo,
- unsigned int *uninitialized_count_r)
+static unsigned int
+service_signal_processes(struct service *service, int signo,
+ struct service_process *processes,
+ unsigned int *uninitialized_count)
{
- struct service_process *process = service->processes;
+ struct service_process *process;
unsigned int count = 0;
- *uninitialized_count_r = 0;
- for (; process != NULL; process = process->next) {
+ for (process = processes; process != NULL; process = process->next) {
i_assert(process->service == service);
if (!SERVICE_PROCESS_IS_INITIALIZED(process) &&
signo != SIGKILL) {
/* too early to signal it */
- *uninitialized_count_r += 1;
+ *uninitialized_count += 1;
continue;
}
return count;
}
+unsigned int service_signal(struct service *service, int signo,
+ unsigned int *uninitialized_count_r)
+{
+ unsigned int count = 0;
+
+ *uninitialized_count_r = 0;
+ count = service_signal_processes(service, signo,
+ service->busy_processes,
+ uninitialized_count_r);
+ count += service_signal_processes(service, signo,
+ service->idle_processes_head,
+ uninitialized_count_r);
+ return count;
+}
+
static void service_login_notify_send(struct service *service)
{
unsigned int uninitialized_count;
if (service->to_throttle != NULL || service->list->destroyed)
return;
- if (service->processes == NULL)
+ if (service->busy_processes == NULL &&
+ service->idle_processes_head == NULL)
service_drop_listener_connections(service);
service_monitor_listen_stop(service);
/* all listeners, even those that aren't currently listening */
ARRAY(struct service_listener *) listeners;
- /* linked list of all processes belonging to this service */
- struct service_process *processes;
+ /* linked list of processes belonging to this service, which have
+ idle_start == 0. */
+ struct service_process *busy_processes;
+ /* linked list of processes belonging to this service, which have
+ ldle_start != 0. */
+ struct service_process *idle_processes_head, *idle_processes_tail;
/* number of processes currently created for this service */
unsigned int process_count;