"Fossies" - the Fresh Open Source Software Archive

Member "dovecot-2.3.8/src/master/service.c" (8 Oct 2019, 19767 Bytes) of package /linux/misc/dovecot-2.3.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "service.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.7.2_vs_2.3.8.

    1 /* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
    2 
    3 #include "common.h"
    4 #include "ioloop.h"
    5 #include "array.h"
    6 #include "aqueue.h"
    7 #include "hash.h"
    8 #include "str.h"
    9 #include "net.h"
   10 #include "master-service.h"
   11 #include "master-service-settings.h"
   12 #include "service.h"
   13 #include "service-anvil.h"
   14 #include "service-process.h"
   15 #include "service-monitor.h"
   16 
   17 #include <unistd.h>
   18 #include <signal.h>
   19 
   20 #define SERVICE_DIE_TIMEOUT_MSECS (1000*6)
   21 #define SERVICE_LOGIN_NOTIFY_MIN_INTERVAL_SECS 2
   22 
   23 HASH_TABLE_TYPE(pid_process) service_pids;
   24 
   25 void service_error(struct service *service, const char *format, ...)
   26 {
   27     va_list args;
   28 
   29     va_start(args, format);
   30     i_error("service(%s): %s", service->set->name,
   31         t_strdup_vprintf(format, args));
   32     va_end(args);
   33 }
   34 
   35 static struct service_listener *
   36 service_create_file_listener(struct service *service,
   37                  enum service_listener_type type,
   38                  const struct file_listener_settings *set,
   39                  const char **error_r)
   40 {
   41     struct service_listener *l;
   42     const char *set_name;
   43     gid_t gid;
   44 
   45     l = p_new(service->list->pool, struct service_listener, 1);
   46     l->service = service;
   47     l->type = type;
   48     l->fd = -1;
   49     l->set.fileset.set = set;
   50     l->name = strrchr(set->path, '/');
   51     if (l->name != NULL)
   52         l->name++;
   53     else
   54         l->name = set->path;
   55 
   56     if (get_uidgid(set->user, &l->set.fileset.uid, &gid, error_r) < 0)
   57         set_name = "user";
   58     else if (get_gid(set->group, &l->set.fileset.gid, error_r) < 0)
   59         set_name = "group";
   60     else
   61         return l;
   62 
   63     *error_r = t_strdup_printf(
   64         "%s (See service %s { %s_listener %s { %s } } setting)",
   65         *error_r, service->set->name,
   66         type == SERVICE_LISTENER_UNIX ? "unix" : "fifo",
   67         set->path, set_name);
   68     return NULL;
   69 }
   70 
   71 static int
   72 resolve_ip(const char *address, const struct ip_addr **ips_r,
   73        unsigned int *ips_count_r, const char **error_r)
   74 {
   75     struct ip_addr *ip_list;
   76     unsigned int ips_count;
   77     int ret;
   78 
   79     if (address == NULL || strcmp(address, "*") == 0) {
   80         /* IPv4 any */
   81         ip_list = t_new(struct ip_addr, 1);
   82         *ip_list = net_ip4_any;
   83         *ips_r = ip_list;
   84         *ips_count_r = 1;
   85         return 0;
   86     }
   87 
   88     if (strcmp(address, "::") == 0 || strcmp(address, "[::]") == 0) {
   89         /* IPv6 any */
   90         ip_list = t_new(struct ip_addr, 1);
   91         *ip_list = net_ip6_any;
   92         *ips_r = ip_list;
   93         *ips_count_r = 1;
   94         return 0;
   95     }
   96 
   97     /* Return the first IP if there happens to be multiple. */
   98     ret = net_gethostbyname(address, &ip_list, &ips_count);
   99     if (ret != 0) {
  100         *error_r = t_strdup_printf("Can't resolve address %s: %s",
  101                        address, net_gethosterror(ret));
  102         return -1;
  103     }
  104 
  105     if (ips_count < 1) {
  106         *error_r = t_strdup_printf("No IPs for address: %s", address);
  107         return -1;
  108     }
  109 
  110     *ips_r = ip_list;
  111     *ips_count_r = ips_count;
  112     return 0;
  113 }
  114 
  115 static struct service_listener *
  116 service_create_one_inet_listener(struct service *service,
  117                  const struct inet_listener_settings *set,
  118                  const char *address, const struct ip_addr *ip)
  119 {
  120     struct service_listener *l;
  121 
  122     i_assert(set->port != 0);
  123 
  124     l = p_new(service->list->pool, struct service_listener, 1);
  125     l->service = service;
  126     l->type = SERVICE_LISTENER_INET;
  127     l->fd = -1;
  128     l->set.inetset.set = set;
  129     l->set.inetset.ip = *ip;
  130     l->inet_address = p_strdup(service->list->pool, address);
  131     l->name = set->name;
  132 
  133     return l;
  134 }
  135 
  136 static int
  137 service_create_inet_listeners(struct service *service,
  138                   const struct inet_listener_settings *set,
  139                   const char **error_r)
  140 {
  141     static struct service_listener *l;
  142     const char *const *tmp, *addresses;
  143     const struct ip_addr *ips;
  144     unsigned int i, ips_count;
  145     bool ssl_disabled = strcmp(service->set->master_set->ssl, "no") == 0;
  146 
  147     if (set->port == 0) {
  148         /* disabled */
  149         return 0;
  150     }
  151 
  152     if (*set->address != '\0')
  153         addresses = set->address;
  154     else {
  155         /* use the default listen address */
  156         addresses = service->set->master_set->listen;
  157     }
  158 
  159     tmp = t_strsplit_spaces(addresses, ", ");
  160     for (; *tmp != NULL; tmp++) {
  161         const char *address = *tmp;
  162 
  163         if (set->ssl && ssl_disabled)
  164             continue;
  165 
  166         if (resolve_ip(address, &ips, &ips_count, error_r) < 0)
  167             return -1;
  168 
  169         for (i = 0; i < ips_count; i++) {
  170             l = service_create_one_inet_listener(service, set,
  171                                  address, &ips[i]);
  172             array_push_back(&service->listeners, &l);
  173         }
  174         service->have_inet_listeners = TRUE;
  175     }
  176     return 0;
  177 }
  178 
  179 static int service_get_groups(const char *groups, pool_t pool,
  180                   const char **gids_r, const char **error_r)
  181 {
  182     const char *const *tmp;
  183     string_t *str;
  184     gid_t gid;
  185 
  186     str = t_str_new(64);
  187     for (tmp = t_strsplit(groups, ","); *tmp != NULL; tmp++) {
  188         if (get_gid(*tmp, &gid, error_r) < 0)
  189             return -1;
  190 
  191         if (str_len(str) > 0)
  192             str_append_c(str, ',');
  193         str_append(str, dec2str(gid));
  194     }
  195     *gids_r = p_strdup(pool, str_c(str));
  196     return 0;
  197 }
  198 
  199 static struct service *
  200 service_create(pool_t pool, const struct service_settings *set,
  201            struct service_list *service_list, const char **error_r)
  202 {
  203     struct file_listener_settings *const *unix_listeners;
  204     struct file_listener_settings *const *fifo_listeners;
  205     struct inet_listener_settings *const *inet_listeners;
  206     struct service *service;
  207         struct service_listener *l;
  208     unsigned int i, unix_count, fifo_count, inet_count;
  209 
  210     service = p_new(pool, struct service, 1);
  211     service->list = service_list;
  212     service->set = set;
  213     service->throttle_msecs = SERVICE_STARTUP_FAILURE_THROTTLE_MIN_MSECS;
  214 
  215     service->client_limit = set->client_limit != 0 ? set->client_limit :
  216         set->master_set->default_client_limit;
  217     if (set->service_count > 0 &&
  218         service->client_limit > set->service_count)
  219         service->client_limit = set->service_count;
  220 
  221     service->vsz_limit = set->vsz_limit != (uoff_t)-1 ? set->vsz_limit :
  222         set->master_set->default_vsz_limit;
  223     service->idle_kill = set->idle_kill != 0 ? set->idle_kill :
  224         set->master_set->default_idle_kill;
  225     service->type = service->set->parsed_type;
  226 
  227     if (set->process_limit == 0) {
  228         /* use default */
  229         service->process_limit =
  230             set->master_set->default_process_limit;
  231     } else {
  232         service->process_limit = set->process_limit;
  233     }
  234 
  235     /* default gid to user's primary group */
  236     if (get_uidgid(set->user, &service->uid, &service->gid, error_r) < 0) {
  237         switch (set->user_default) {
  238         case SERVICE_USER_DEFAULT_NONE:
  239             *error_r = t_strdup_printf(
  240                 "%s (See service %s { user } setting)",
  241                 *error_r, set->name);
  242             break;
  243         case SERVICE_USER_DEFAULT_INTERNAL:
  244             *error_r = t_strconcat(*error_r,
  245                 " (See default_internal_user setting)", NULL);
  246             break;
  247         case SERVICE_USER_DEFAULT_LOGIN:
  248             *error_r = t_strconcat(*error_r,
  249                 " (See default_login_user setting)", NULL);
  250             break;
  251         }
  252         return NULL;
  253     }
  254     if (*set->group != '\0') {
  255         if (get_gid(set->group, &service->gid, error_r) < 0) {
  256             *error_r = t_strdup_printf(
  257                 "%s (See service %s { group } setting)",
  258                 *error_r, set->name);
  259             return NULL;
  260         }
  261     }
  262     if (get_gid(set->privileged_group, &service->privileged_gid,
  263             error_r) < 0) {
  264         *error_r = t_strdup_printf(
  265             "%s (See service %s { privileged_group } setting)",
  266             *error_r, set->name);
  267         return NULL;
  268     }
  269 
  270     if (*set->extra_groups != '\0') {
  271         if (service_get_groups(set->extra_groups, pool,
  272                        &service->extra_gids, error_r) < 0) {
  273             *error_r = t_strdup_printf(
  274                 "%s (See service %s { extra_groups } setting)",
  275                 *error_r, set->name);
  276             return NULL;
  277         }
  278     }
  279 
  280     /* set these later, so if something fails we don't have to worry about
  281        closing them */
  282     service->log_fd[0] = -1;
  283     service->log_fd[1] = -1;
  284     service->status_fd[0] = -1;
  285     service->status_fd[1] = -1;
  286     service->master_dead_pipe_fd[0] = -1;
  287     service->master_dead_pipe_fd[1] = -1;
  288     service->log_process_internal_fd = -1;
  289     service->login_notify_fd = -1;
  290 
  291     if (service->type == SERVICE_TYPE_ANVIL) {
  292         service->status_fd[0] = service_anvil_global->status_fd[0];
  293         service->status_fd[1] = service_anvil_global->status_fd[1];
  294     }
  295 
  296     if (array_is_created(&set->unix_listeners))
  297         unix_listeners = array_get(&set->unix_listeners, &unix_count);
  298     else {
  299         unix_listeners = NULL;
  300         unix_count = 0;
  301     }
  302     if (array_is_created(&set->fifo_listeners))
  303         fifo_listeners = array_get(&set->fifo_listeners, &fifo_count);
  304     else {
  305         fifo_listeners = NULL;
  306         fifo_count = 0;
  307     }
  308     if (array_is_created(&set->inet_listeners))
  309         inet_listeners = array_get(&set->inet_listeners, &inet_count);
  310     else {
  311         inet_listeners = NULL;
  312         inet_count = 0;
  313     }
  314 
  315     if (unix_count == 0 && service->type == SERVICE_TYPE_CONFIG) {
  316         *error_r = "Service must have unix listeners";
  317         return NULL;
  318     }
  319 
  320     p_array_init(&service->listeners, pool,
  321              unix_count + fifo_count + inet_count);
  322              
  323     for (i = 0; i < unix_count; i++) {
  324         if (unix_listeners[i]->mode == 0) {
  325             /* disabled */
  326             continue;
  327         }
  328 
  329         l = service_create_file_listener(service, SERVICE_LISTENER_UNIX,
  330                          unix_listeners[i], error_r);
  331         if (l == NULL)
  332             return NULL;
  333         array_push_back(&service->listeners, &l);
  334     }
  335     for (i = 0; i < fifo_count; i++) {
  336         if (fifo_listeners[i]->mode == 0) {
  337             /* disabled */
  338             continue;
  339         }
  340 
  341         l = service_create_file_listener(service, SERVICE_LISTENER_FIFO,
  342                          fifo_listeners[i], error_r);
  343         if (l == NULL)
  344             return NULL;
  345         array_push_back(&service->listeners, &l);
  346     }
  347     for (i = 0; i < inet_count; i++) {
  348         if (service_create_inet_listeners(service, inet_listeners[i],
  349                           error_r) < 0)
  350             return NULL;
  351     }
  352 
  353     service->executable = set->executable;
  354     if (access(t_strcut(service->executable, ' '), X_OK) < 0) {
  355         *error_r = t_strdup_printf("access(%s) failed: %m",
  356                        t_strcut(service->executable, ' '));
  357         return NULL;
  358     }
  359     return service;
  360 }
  361 
  362 struct service *
  363 service_lookup(struct service_list *service_list, const char *name)
  364 {
  365     struct service *const *services;
  366 
  367     array_foreach(&service_list->services, services) {
  368         struct service *service = *services;
  369 
  370         if (strcmp(service->set->name, name) == 0)
  371             return service;
  372     }
  373     return NULL;
  374 }
  375 
  376 struct service *
  377 service_lookup_type(struct service_list *service_list, enum service_type type)
  378 {
  379     struct service *const *services;
  380 
  381     array_foreach(&service_list->services, services) {
  382         struct service *service = *services;
  383 
  384         if (service->type == type)
  385             return service;
  386     }
  387     return NULL;
  388 }
  389 
  390 static bool service_want(struct service_settings *set)
  391 {
  392     char *const *proto;
  393 
  394     if (*set->executable == '\0') {
  395         /* silently allow service {} blocks for disabled extensions
  396            (e.g. service managesieve {} block without pigeonhole
  397            installed) */
  398         return FALSE;
  399     }
  400 
  401     if (*set->protocol == '\0')
  402         return TRUE;
  403 
  404     for (proto = set->master_set->protocols_split; *proto != NULL; proto++) {
  405         if (strcmp(*proto, set->protocol) == 0)
  406             return TRUE;
  407     }
  408     return FALSE;
  409 }
  410 
  411 static int
  412 services_create_real(const struct master_settings *set, pool_t pool,
  413              struct service_list **services_r, const char **error_r)
  414 {
  415     struct service_list *service_list;
  416     struct service *service;
  417     struct service_settings *const *service_settings;
  418     const char *error;
  419     unsigned int i, count;
  420 
  421     service_list = p_new(pool, struct service_list, 1);
  422     service_list->refcount = 1;
  423     service_list->pool = pool;
  424     service_list->service_set = master_service_settings_get(master_service);
  425     service_list->set_pool = master_service_settings_detach(master_service);
  426     service_list->set = set;
  427     service_list->master_log_fd[0] = -1;
  428     service_list->master_log_fd[1] = -1;
  429     service_list->master_fd = -1;
  430 
  431     service_settings = array_get(&set->services, &count);
  432     p_array_init(&service_list->services, pool, count);
  433 
  434     for (i = 0; i < count; i++) {
  435         if (!service_want(service_settings[i]))
  436             continue;
  437         service = service_create(pool, service_settings[i],
  438                      service_list, &error);
  439         if (service == NULL) {
  440             *error_r = t_strdup_printf("service(%s) %s",
  441                 service_settings[i]->name, error);
  442             return -1;
  443         }
  444 
  445         switch (service->type) {
  446         case SERVICE_TYPE_LOG:
  447             if (service_list->log != NULL) {
  448                 *error_r = "Multiple log services specified";
  449                 return -1;
  450             }
  451             service_list->log = service;
  452             break;
  453         case SERVICE_TYPE_CONFIG:
  454             if (service_list->config != NULL) {
  455                 *error_r = "Multiple config services specified";
  456                 return -1;
  457             }
  458             service_list->config = service;
  459             break;
  460         case SERVICE_TYPE_ANVIL:
  461             if (service_list->anvil != NULL) {
  462                 *error_r = "Multiple anvil services specified";
  463                 return -1;
  464             }
  465             service_list->anvil = service;
  466             break;
  467         default:
  468             break;
  469         }
  470 
  471         array_push_back(&service_list->services, &service);
  472     }
  473 
  474     if (service_list->log == NULL) {
  475         *error_r = "log service not specified";
  476         return -1;
  477     }
  478 
  479     if (service_list->config == NULL) {
  480         *error_r = "config process not specified";
  481         return -1;
  482     }
  483 
  484     *services_r = service_list;
  485     return 0;
  486 }
  487 
  488 int services_create(const struct master_settings *set,
  489             struct service_list **services_r, const char **error_r)
  490 {
  491     pool_t pool;
  492 
  493     pool = pool_alloconly_create("services pool", 32768);
  494     if (services_create_real(set, pool, services_r, error_r) < 0) {
  495         pool_unref(&pool);
  496         return -1;
  497     }
  498     return 0;
  499 }
  500 
  501 unsigned int service_signal(struct service *service, int signo,
  502                 unsigned int *uninitialized_count_r)
  503 {
  504     struct service_process *process = service->processes;
  505     unsigned int count = 0;
  506 
  507     *uninitialized_count_r = 0;
  508     for (; process != NULL; process = process->next) {
  509         i_assert(process->service == service);
  510 
  511         if (!SERVICE_PROCESS_IS_INITIALIZED(process) &&
  512             signo != SIGKILL) {
  513             /* too early to signal it */
  514             *uninitialized_count_r += 1;
  515             continue;
  516         }
  517             
  518         if (kill(process->pid, signo) == 0)
  519             count++;
  520         else if (errno != ESRCH) {
  521             service_error(service, "kill(%s, %d) failed: %m",
  522                       dec2str(process->pid), signo);
  523         }
  524     }
  525     if (count > 0) {
  526         i_warning("Sent %s to %u %s processes",
  527               signo == SIGTERM ? "SIGTERM" : "SIGKILL",
  528               count, service->set->name);
  529     }
  530     return count;
  531 }
  532 
  533 static void service_login_notify_send(struct service *service)
  534 {
  535     unsigned int uninitialized_count;
  536 
  537     service->last_login_notify_time = ioloop_time;
  538     timeout_remove(&service->to_login_notify);
  539 
  540     service_signal(service, SIGUSR1, &uninitialized_count);
  541 }
  542 
  543 static void service_login_notify_timeout(struct service *service)
  544 {
  545     service_login_notify_send(service);
  546 }
  547 
  548 void service_login_notify(struct service *service, bool all_processes_full)
  549 {
  550     enum master_login_state state;
  551     int diff;
  552 
  553     if (service->last_login_full_notify == all_processes_full ||
  554         service->login_notify_fd == -1)
  555         return;
  556 
  557     /* change the state always immediately. it's cheap. */
  558     service->last_login_full_notify = all_processes_full;
  559     state = all_processes_full ? MASTER_LOGIN_STATE_FULL :
  560         MASTER_LOGIN_STATE_NONFULL;
  561     if (lseek(service->login_notify_fd, state, SEEK_SET) < 0)
  562         service_error(service, "lseek(notify fd) failed: %m");
  563 
  564     /* but don't send signal to processes too often */
  565     diff = ioloop_time - service->last_login_notify_time;
  566     if (diff < SERVICE_LOGIN_NOTIFY_MIN_INTERVAL_SECS) {
  567         if (service->to_login_notify != NULL)
  568             return;
  569 
  570         diff = (SERVICE_LOGIN_NOTIFY_MIN_INTERVAL_SECS - diff) * 1000;
  571         service->to_login_notify =
  572             timeout_add(diff, service_login_notify_timeout,
  573                     service);
  574     } else {
  575         service_login_notify_send(service);
  576     }
  577 }
  578 
  579 static void services_kill_timeout(struct service_list *service_list)
  580 {
  581     struct service *const *services, *log_service;
  582     unsigned int service_uninitialized, uninitialized_count = 0;
  583     unsigned int signal_count = 0;
  584     int sig;
  585 
  586     if (!service_list->sigterm_sent)
  587         sig = SIGTERM;
  588     else
  589         sig = SIGKILL;
  590     service_list->sigterm_sent = TRUE;
  591 
  592     log_service = NULL;
  593     array_foreach(&service_list->services, services) {
  594         struct service *service = *services;
  595 
  596         if (service->type == SERVICE_TYPE_LOG)
  597             log_service = service;
  598         else {
  599             signal_count += service_signal(service, sig,
  600                                &service_uninitialized);
  601             uninitialized_count += service_uninitialized;
  602         }
  603     }
  604     if (log_service == NULL) {
  605         /* log service doesn't exist - shouldn't really happen */
  606     } else if (signal_count > 0 || uninitialized_count > 0) {
  607         /* kill log service later so the last remaining processes
  608            can still have a chance of logging something */
  609     } else {
  610         if (!service_list->sigterm_sent_to_log)
  611             sig = SIGTERM;
  612         else
  613             sig = SIGKILL;
  614         service_list->sigterm_sent_to_log = TRUE;
  615         signal_count += service_signal(log_service, sig, &service_uninitialized);
  616         uninitialized_count += service_uninitialized;
  617     }
  618     if (signal_count > 0) {
  619         string_t *str = t_str_new(128);
  620         str_printfa(str, "Processes aren't dying after reload, "
  621                 "sent %s to %u processes.",
  622                 sig == SIGTERM ? "SIGTERM" : "SIGKILL", signal_count);
  623         if (uninitialized_count > 0) {
  624             str_printfa(str, " (%u processes still uninitialized)",
  625                     uninitialized_count);
  626         }
  627         i_warning("%s", str_c(str));
  628     }
  629 }
  630 
  631 void services_destroy(struct service_list *service_list, bool wait)
  632 {
  633     /* make sure we log if child processes died unexpectedly */
  634     service_list->destroying = TRUE;
  635     services_monitor_reap_children();
  636 
  637     services_monitor_stop(service_list, wait);
  638 
  639     if (service_list->refcount > 1 &&
  640         service_list->service_set->shutdown_clients) {
  641         service_list->to_kill =
  642             timeout_add(SERVICE_DIE_TIMEOUT_MSECS,
  643                     services_kill_timeout, service_list);
  644     }
  645 
  646     service_list->destroyed = TRUE;
  647     service_list_unref(service_list);
  648 }
  649 
  650 void service_list_ref(struct service_list *service_list)
  651 {
  652     i_assert(service_list->refcount > 0);
  653     service_list->refcount++;
  654 }
  655 
  656 void service_list_unref(struct service_list *service_list)
  657 {
  658     struct service *const *servicep;
  659     struct service_listener *const *listenerp;
  660 
  661     i_assert(service_list->refcount > 0);
  662     if (--service_list->refcount > 0)
  663         return;
  664 
  665     array_foreach(&service_list->services, servicep) {
  666         array_foreach(&(*servicep)->listeners, listenerp)
  667             i_close_fd(&(*listenerp)->fd);
  668     }
  669     i_close_fd(&service_list->master_fd);
  670 
  671     timeout_remove(&service_list->to_kill);
  672     pool_unref(&service_list->set_pool);
  673     pool_unref(&service_list->pool);
  674 }
  675 
  676 const char *services_get_config_socket_path(struct service_list *service_list)
  677 {
  678         struct service_listener *const *listeners;
  679     unsigned int count;
  680 
  681     listeners = array_get(&service_list->config->listeners, &count);
  682     i_assert(count > 0);
  683     return listeners[0]->set.fileset.set->path;
  684 }
  685 
  686 static void service_throttle_timeout(struct service *service)
  687 {
  688     timeout_remove(&service->to_throttle);
  689     service_monitor_listen_start(service);
  690 }
  691 
  692 static void service_drop_listener_connections(struct service *service)
  693 {
  694     struct service_listener *const *listenerp;
  695     int fd;
  696 
  697     array_foreach(&service->listeners, listenerp) {
  698         switch ((*listenerp)->type) {
  699         case SERVICE_LISTENER_UNIX:
  700         case SERVICE_LISTENER_INET:
  701             if ((*listenerp)->fd == -1) {
  702                 /* already stopped listening */
  703                 break;
  704             }
  705             while ((fd = net_accept((*listenerp)->fd,
  706                         NULL, NULL)) >= 0)
  707                 i_close_fd(&fd);
  708             break;
  709         case SERVICE_LISTENER_FIFO:
  710             break;
  711         }
  712     }
  713 }
  714 
  715 void service_throttle(struct service *service, unsigned int msecs)
  716 {
  717     if (service->to_throttle != NULL || service->list->destroyed)
  718         return;
  719 
  720     if (service->processes == NULL)
  721         service_drop_listener_connections(service);
  722 
  723     service_monitor_listen_stop(service);
  724     service->to_throttle = timeout_add(msecs, service_throttle_timeout,
  725                        service);
  726 }
  727 
  728 void services_throttle_time_sensitives(struct service_list *list,
  729                        unsigned int msecs)
  730 {
  731     struct service *const *services;
  732 
  733     array_foreach(&list->services, services) {
  734         struct service *service = *services;
  735 
  736         if (service->type == SERVICE_TYPE_UNKNOWN)
  737             service_throttle(service, msecs);
  738     }
  739 }
  740 
  741 void service_pids_init(void)
  742 {
  743     hash_table_create_direct(&service_pids, default_pool, 0);
  744 }
  745 
  746 void service_pids_deinit(void)
  747 {
  748     struct hash_iterate_context *iter;
  749     void *key;
  750     struct service_process *process;
  751 
  752     /* free all child process information */
  753     iter = hash_table_iterate_init(service_pids);
  754     while (hash_table_iterate(iter, service_pids, &key, &process))
  755         service_process_destroy(process);
  756     hash_table_iterate_deinit(&iter);
  757     hash_table_destroy(&service_pids);
  758 }