summaryrefslogtreecommitdiff
path: root/gnu/dist/postfix/src/master/master_avail.c
blob: e5507ef6d9b95f1fb196458c43a45a99b8f319d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*++
/* NAME
/*	master_avail 3
/* SUMMARY
/*	Postfix master - process creation policy
/* SYNOPSIS
/*	#include "master.h"
/*
/*	void	master_avail_listen(serv)
/*	MASTER_SERV *serv;
/*
/*	void	master_avail_cleanup(serv)
/*	MASTER_SERV *serv;
/*
/*	void	master_avail_more(serv, proc)
/*	MASTER_SERV *serv;
/*	MASTER_PROC *proc;
/*
/*	void	master_avail_less(serv, proc)
/*	MASTER_SERV *serv;
/*	MASTER_PROC *proc;
/* DESCRIPTION
/*	This module implements the process creation policy. As long as
/*	the allowed number of processes for the given service is not
/*	exceeded, a connection request is either handled by an existing
/*	available process, or this module causes a new process to be
/*	created to service the request.
/*
/*	master_avail_listen() ensures that someone monitors the service's
/*	listen socket for connection requests (as long as resources
/*	to handle connection requests are available).  This function may
/*	be called at random. When the maximum number of servers is running,
/*	connection requests are left in the system queue.
/*
/*	master_avail_cleanup() should be called when the named service
/*	is taken out of operation. It terminates child processes by
/*	sending SIGTERM.
/*
/*	master_avail_more() should be called when the named process
/*	has become available for servicing new connection requests.
/*
/*	master_avail_less() should be called when the named process
/*	has become unavailable for servicing new connection requests.
/* DIAGNOSTICS
/*	Panic: internal inconsistencies.
/* BUGS
/* SEE ALSO
/*	master_spawn(3), child process birth and death
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System libraries. */

#include <sys_defs.h>

/* Utility library. */

#include <events.h>
#include <msg.h>

/* Application-specific. */

#include "master_proto.h"
#include "master.h"

/* master_avail_event - create child process to handle connection request */

static void master_avail_event(int event, char *context)
{
    MASTER_SERV *serv = (MASTER_SERV *) context;
    int     n;

    if (event == 0)				/* XXX Can this happen? */
	return;
    if (MASTER_THROTTLED(serv)) {		/* XXX interface botch */
	for (n = 0; n < serv->listen_fd_count; n++)
	    event_disable_readwrite(serv->listen_fd[n]);
    } else {
	master_spawn(serv);
    }
}

/* master_avail_listen - make sure that someone monitors the listen socket */

void    master_avail_listen(MASTER_SERV *serv)
{
    char   *myname = "master_avail_listen";
    int     n;

    /*
     * When no-one else is monitoring the service's listen socket, start
     * monitoring the socket for connection requests. All this under the
     * restriction that we have sufficient resources to service a connection
     * request.
     */
    if (msg_verbose)
	msg_info("%s: avail %d total %d max %d", myname,
		 serv->avail_proc, serv->total_proc, serv->max_proc);
    if (serv->avail_proc < 1
	&& MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)
	&& !MASTER_THROTTLED(serv)) {
	if (msg_verbose)
	    msg_info("%s: enable events %s", myname, serv->name);
	for (n = 0; n < serv->listen_fd_count; n++)
	    event_enable_read(serv->listen_fd[n], master_avail_event,
			      (char *) serv);
    }
}

/* master_avail_cleanup - cleanup */

void    master_avail_cleanup(MASTER_SERV *serv)
{
    int     n;

    master_delete_children(serv);		/* XXX calls
						 * master_avail_listen */
    for (n = 0; n < serv->listen_fd_count; n++)
	event_disable_readwrite(serv->listen_fd[n]);	/* XXX must be last */
}

/* master_avail_more - one more available child process */

void    master_avail_more(MASTER_SERV *serv, MASTER_PROC *proc)
{
    char   *myname = "master_avail_more";
    int     n;

    /*
     * This child process has become available for servicing connection
     * requests, so we can stop monitoring the service's listen socket. The
     * child will do it for us.
     */
    if (msg_verbose)
	msg_info("%s: pid %d (%s)", myname, proc->pid, proc->serv->name);
    if (proc->avail == MASTER_STAT_AVAIL)
	msg_panic("%s: process already available", myname);
    serv->avail_proc++;
    proc->avail = MASTER_STAT_AVAIL;
    if (msg_verbose)
	msg_info("%s: disable events %s", myname, serv->name);
    for (n = 0; n < serv->listen_fd_count; n++)
	event_disable_readwrite(serv->listen_fd[n]);
}

/* master_avail_less - one less available child process */

void    master_avail_less(MASTER_SERV *serv, MASTER_PROC *proc)
{
    char   *myname = "master_avail_less";

    /*
     * This child is no longer available for servicing connection requests.
     * When no child processes are available, start monitoring the service's
     * listen socket for new connection requests.
     */
    if (msg_verbose)
	msg_info("%s: pid %d (%s)", myname, proc->pid, proc->serv->name);
    if (proc->avail != MASTER_STAT_AVAIL)
	msg_panic("%s: process not available", myname);
    serv->avail_proc--;
    proc->avail = MASTER_STAT_TAKEN;
    master_avail_listen(serv);
}