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