1 /* $NetBSD: master_avail.c,v 1.1.1.4 2013/01/02 18:59:01 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* master_avail 3 6 /* SUMMARY 7 /* Postfix master - process creation policy 8 /* SYNOPSIS 9 /* #include "master.h" 10 /* 11 /* void master_avail_listen(serv) 12 /* MASTER_SERV *serv; 13 /* 14 /* void master_avail_cleanup(serv) 15 /* MASTER_SERV *serv; 16 /* 17 /* void master_avail_more(serv, proc) 18 /* MASTER_SERV *serv; 19 /* MASTER_PROC *proc; 20 /* 21 /* void master_avail_less(serv, proc) 22 /* MASTER_SERV *serv; 23 /* MASTER_PROC *proc; 24 /* DESCRIPTION 25 /* This module implements the process creation policy. As long as 26 /* the allowed number of processes for the given service is not 27 /* exceeded, a connection request is either handled by an existing 28 /* available process, or this module causes a new process to be 29 /* created to service the request. 30 /* 31 /* When the service runs out of process slots, and the service 32 /* is eligible for stress-mode operation, a warning is logged, 33 /* servers are asked to restart at their convenience, and new 34 /* servers are created with stress mode enabled. 35 /* 36 /* master_avail_listen() ensures that someone monitors the service's 37 /* listen socket for connection requests (as long as resources 38 /* to handle connection requests are available). This function may 39 /* be called at random times, but it must be called after each status 40 /* change of a service (throttled, process limit, etc.) or child 41 /* process (taken, available, dead, etc.). 42 /* 43 /* master_avail_cleanup() should be called when the named service 44 /* is taken out of operation. It terminates child processes by 45 /* sending SIGTERM. 46 /* 47 /* master_avail_more() should be called when the named process 48 /* has become available for servicing new connection requests. 49 /* This function updates the process availability status and 50 /* counter, and implicitly calls master_avail_listen(). 51 /* 52 /* master_avail_less() should be called when the named process 53 /* has become unavailable for servicing new connection requests. 54 /* This function updates the process availability status and 55 /* counter, and implicitly calls master_avail_listen(). 56 /* DIAGNOSTICS 57 /* Panic: internal inconsistencies. 58 /* BUGS 59 /* SEE ALSO 60 /* master_spawn(3), child process birth and death 61 /* LICENSE 62 /* .ad 63 /* .fi 64 /* The Secure Mailer license must be distributed with this software. 65 /* AUTHOR(S) 66 /* Wietse Venema 67 /* IBM T.J. Watson Research 68 /* P.O. Box 704 69 /* Yorktown Heights, NY 10598, USA 70 /*--*/ 71 72 /* System libraries. */ 73 74 #include <sys_defs.h> 75 76 /* Utility library. */ 77 78 #include <events.h> 79 #include <msg.h> 80 81 /* Application-specific. */ 82 83 #include "master_proto.h" 84 #include "master.h" 85 86 /* master_avail_event - create child process to handle connection request */ 87 88 static void master_avail_event(int event, char *context) 89 { 90 MASTER_SERV *serv = (MASTER_SERV *) context; 91 time_t now; 92 93 if (event == 0) /* XXX Can this happen? */ 94 msg_panic("master_avail_event: null event"); 95 else { 96 97 /* 98 * When all servers for a public internet service are busy, we start 99 * creating server processes with "-o stress=yes" on the command 100 * line, and keep creating such processes until the process count is 101 * below the limit for at least 1000 seconds. This provides a minimal 102 * solution that can be adopted into legacy and stable Postfix 103 * releases. 104 * 105 * This is not the right place to update serv->stress_param_val in 106 * response to stress level changes. Doing so would would contaminate 107 * the "postfix reload" code with stress management implementation 108 * details, creating a source of future bugs. Instead, we update 109 * simple counters or flags here, and use their values to determine 110 * the proper serv->stress_param_val value when exec-ing a server 111 * process. 112 */ 113 if (serv->stress_param_val != 0 114 && !MASTER_LIMIT_OK(serv->max_proc, serv->total_proc + 1)) { 115 now = event_time(); 116 if (serv->stress_expire_time < now) 117 master_restart_service(serv, NO_CONF_RELOAD); 118 serv->stress_expire_time = now + 1000; 119 } 120 master_spawn(serv); 121 } 122 } 123 124 /* master_avail_listen - enforce the socket monitoring policy */ 125 126 void master_avail_listen(MASTER_SERV *serv) 127 { 128 const char *myname = "master_avail_listen"; 129 int listen_flag; 130 time_t now; 131 int n; 132 133 /* 134 * Caution: several other master_XXX modules call master_avail_listen(), 135 * master_avail_more() or master_avail_less(). To avoid mutual dependency 136 * problems, the code below invokes no code in other master_XXX modules, 137 * and modifies no data that is maintained by other master_XXX modules. 138 * 139 * When no-one else is monitoring the service's listen socket, start 140 * monitoring the socket for connection requests. All this under the 141 * restriction that we have sufficient resources to service a connection 142 * request. 143 */ 144 if (msg_verbose) 145 msg_info("%s: %s avail %d total %d max %d", myname, serv->name, 146 serv->avail_proc, serv->total_proc, serv->max_proc); 147 if (MASTER_THROTTLED(serv) || serv->avail_proc > 0) { 148 listen_flag = 0; 149 } else if (MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)) { 150 listen_flag = 1; 151 } else { 152 listen_flag = 0; 153 if (serv->stress_param_val != 0) { 154 now = event_time(); 155 if (serv->busy_warn_time < now - 1000) { 156 serv->busy_warn_time = now; 157 msg_warn("service \"%s\" (%s) has reached its process limit \"%d\": " 158 "new clients may experience noticeable delays", 159 serv->ext_name, serv->name, serv->max_proc); 160 msg_warn("to avoid this condition, increase the process count " 161 "in master.cf or reduce the service time per client"); 162 msg_warn("see http://www.postfix.org/STRESS_README.html for " 163 "examples of stress-adapting configuration settings"); 164 } 165 } 166 } 167 if (listen_flag && !MASTER_LISTENING(serv)) { 168 if (msg_verbose) 169 msg_info("%s: enable events %s", myname, serv->name); 170 for (n = 0; n < serv->listen_fd_count; n++) 171 event_enable_read(serv->listen_fd[n], master_avail_event, 172 (char *) serv); 173 serv->flags |= MASTER_FLAG_LISTEN; 174 } else if (!listen_flag && MASTER_LISTENING(serv)) { 175 if (msg_verbose) 176 msg_info("%s: disable events %s", myname, serv->name); 177 for (n = 0; n < serv->listen_fd_count; n++) 178 event_disable_readwrite(serv->listen_fd[n]); 179 serv->flags &= ~MASTER_FLAG_LISTEN; 180 } 181 } 182 183 /* master_avail_cleanup - cleanup */ 184 185 void master_avail_cleanup(MASTER_SERV *serv) 186 { 187 int n; 188 189 master_delete_children(serv); /* XXX calls 190 * master_avail_listen */ 191 192 /* 193 * This code is redundant because master_delete_children() throttles the 194 * service temporarily before calling master_avail_listen/less(), which 195 * then turn off read events. This temporary throttling is not documented 196 * (it is only an optimization), and therefore we must not depend on it. 197 */ 198 if (MASTER_LISTENING(serv)) { 199 for (n = 0; n < serv->listen_fd_count; n++) 200 event_disable_readwrite(serv->listen_fd[n]); 201 serv->flags &= ~MASTER_FLAG_LISTEN; 202 } 203 } 204 205 /* master_avail_more - one more available child process */ 206 207 void master_avail_more(MASTER_SERV *serv, MASTER_PROC *proc) 208 { 209 const char *myname = "master_avail_more"; 210 211 /* 212 * Caution: several other master_XXX modules call master_avail_listen(), 213 * master_avail_more() or master_avail_less(). To avoid mutual dependency 214 * problems, the code below invokes no code in other master_XXX modules, 215 * and modifies no data that is maintained by other master_XXX modules. 216 * 217 * This child process has become available for servicing connection 218 * requests, so we can stop monitoring the service's listen socket. The 219 * child will do it for us. 220 */ 221 if (msg_verbose) 222 msg_info("%s: pid %d (%s)", myname, proc->pid, proc->serv->name); 223 if (proc->avail == MASTER_STAT_AVAIL) 224 msg_panic("%s: process already available", myname); 225 serv->avail_proc++; 226 proc->avail = MASTER_STAT_AVAIL; 227 master_avail_listen(serv); 228 } 229 230 /* master_avail_less - one less available child process */ 231 232 void master_avail_less(MASTER_SERV *serv, MASTER_PROC *proc) 233 { 234 const char *myname = "master_avail_less"; 235 236 /* 237 * Caution: several other master_XXX modules call master_avail_listen(), 238 * master_avail_more() or master_avail_less(). To avoid mutual dependency 239 * problems, the code below invokes no code in other master_XXX modules, 240 * and modifies no data that is maintained by other master_XXX modules. 241 * 242 * This child is no longer available for servicing connection requests. 243 * When no child processes are available, start monitoring the service's 244 * listen socket for new connection requests. 245 */ 246 if (msg_verbose) 247 msg_info("%s: pid %d (%s)", myname, proc->pid, proc->serv->name); 248 if (proc->avail != MASTER_STAT_AVAIL) 249 msg_panic("%s: process not available", myname); 250 serv->avail_proc--; 251 proc->avail = MASTER_STAT_TAKEN; 252 master_avail_listen(serv); 253 } 254