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