xref: /netbsd-src/external/ibm-public/postfix/dist/src/master/master_avail.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: master_avail.c,v 1.1.1.3 2011/10/28 07:09:53 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, a warning is logged.
32 /*	When the service is eligible for stress-mode operation, servers
33 /*	are restarted and new servers are created with stress mode enabled.
34 /*
35 /*	master_avail_listen() ensures that someone monitors the service's
36 /*	listen socket for connection requests (as long as resources
37 /*	to handle connection requests are available).  This function may
38 /*	be called at random. When the maximum number of servers is running,
39 /*	connection requests are left in the system queue.
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 /*
48 /*	master_avail_less() should be called when the named process
49 /*	has become unavailable for servicing new connection requests.
50 /* DIAGNOSTICS
51 /*	Panic: internal inconsistencies.
52 /* BUGS
53 /* SEE ALSO
54 /*	master_spawn(3), child process birth and death
55 /* LICENSE
56 /* .ad
57 /* .fi
58 /*	The Secure Mailer license must be distributed with this software.
59 /* AUTHOR(S)
60 /*	Wietse Venema
61 /*	IBM T.J. Watson Research
62 /*	P.O. Box 704
63 /*	Yorktown Heights, NY 10598, USA
64 /*--*/
65 
66 /* System libraries. */
67 
68 #include <sys_defs.h>
69 
70 /* Utility library. */
71 
72 #include <events.h>
73 #include <msg.h>
74 
75 /* Application-specific. */
76 
77 #include "master_proto.h"
78 #include "master.h"
79 
80 /* master_avail_event - create child process to handle connection request */
81 
82 static void master_avail_event(int event, char *context)
83 {
84     MASTER_SERV *serv = (MASTER_SERV *) context;
85     time_t  now;
86     int     n;
87 
88     if (event == 0)				/* XXX Can this happen? */
89 	return;
90     /* XXX Should check these when the process or service status is changed. */
91     if (!MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)
92 	|| MASTER_THROTTLED(serv)) {		/* XXX interface botch */
93 	for (n = 0; n < serv->listen_fd_count; n++)
94 	    event_disable_readwrite(serv->listen_fd[n]);
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);
118 	    serv->stress_expire_time = now + 1000;
119 	}
120 	master_spawn(serv);
121     }
122 }
123 
124 /* master_avail_listen - make sure that someone monitors the listen socket */
125 
126 void    master_avail_listen(MASTER_SERV *serv)
127 {
128     const char *myname = "master_avail_listen";
129     time_t  now;
130     int     n;
131 
132     /*
133      * When no-one else is monitoring the service's listen socket, start
134      * monitoring the socket for connection requests. All this under the
135      * restriction that we have sufficient resources to service a connection
136      * request.
137      */
138     if (msg_verbose)
139 	msg_info("%s: avail %d total %d max %d", myname,
140 		 serv->avail_proc, serv->total_proc, serv->max_proc);
141     if (serv->avail_proc < 1 && !MASTER_THROTTLED(serv)) {
142 	if (MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)) {
143 	    if (msg_verbose)
144 		msg_info("%s: enable events %s", myname, serv->name);
145 	    for (n = 0; n < serv->listen_fd_count; n++)
146 		event_enable_read(serv->listen_fd[n], master_avail_event,
147 				  (char *) serv);
148 	} else if ((serv->flags & MASTER_FLAG_LOCAL_ONLY) == 0
149 		   && serv->max_proc != 1/* XXX postscreen(8) */
150 		   && (now = event_time()) - serv->busy_warn_time > 1000) {
151 	    serv->busy_warn_time = now;
152 	    msg_warn("service \"%s\" (%s) has reached its process limit \"%d\": "
153 		     "new clients may experience noticeable delays",
154 		     serv->ext_name, serv->name, serv->max_proc);
155 	    msg_warn("to avoid this condition, increase the process count "
156 		     "in master.cf or reduce the service time per client");
157 	    if (serv->stress_param_val)
158 		msg_warn("see http://www.postfix.org/STRESS_README.html for "
159 		      "examples of stress-adapting configuration settings");
160 	}
161     }
162 }
163 
164 /* master_avail_cleanup - cleanup */
165 
166 void    master_avail_cleanup(MASTER_SERV *serv)
167 {
168     int     n;
169 
170     master_delete_children(serv);		/* XXX calls
171 						 * master_avail_listen */
172     for (n = 0; n < serv->listen_fd_count; n++)
173 	event_disable_readwrite(serv->listen_fd[n]);	/* XXX must be last */
174 }
175 
176 /* master_avail_more - one more available child process */
177 
178 void    master_avail_more(MASTER_SERV *serv, MASTER_PROC *proc)
179 {
180     const char *myname = "master_avail_more";
181     int     n;
182 
183     /*
184      * This child process has become available for servicing connection
185      * requests, so we can stop monitoring the service's listen socket. The
186      * child will do it for us.
187      */
188     if (msg_verbose)
189 	msg_info("%s: pid %d (%s)", myname, proc->pid, proc->serv->name);
190     if (proc->avail == MASTER_STAT_AVAIL)
191 	msg_panic("%s: process already available", myname);
192     serv->avail_proc++;
193     proc->avail = MASTER_STAT_AVAIL;
194     if (msg_verbose)
195 	msg_info("%s: disable events %s", myname, serv->name);
196     for (n = 0; n < serv->listen_fd_count; n++)
197 	event_disable_readwrite(serv->listen_fd[n]);
198 }
199 
200 /* master_avail_less - one less available child process */
201 
202 void    master_avail_less(MASTER_SERV *serv, MASTER_PROC *proc)
203 {
204     const char *myname = "master_avail_less";
205 
206     /*
207      * This child is no longer available for servicing connection requests.
208      * When no child processes are available, start monitoring the service's
209      * listen socket for new connection requests.
210      */
211     if (msg_verbose)
212 	msg_info("%s: pid %d (%s)", myname, proc->pid, proc->serv->name);
213     if (proc->avail != MASTER_STAT_AVAIL)
214 	msg_panic("%s: process not available", myname);
215     serv->avail_proc--;
216     proc->avail = MASTER_STAT_TAKEN;
217     master_avail_listen(serv);
218 }
219