Commit 6dd77f50 6dd77f5075bbb6293d5feb1ccd4c8ab05d6b6fb8 by Sergey Poznyakoff

* mailbox/msrv.c (struct _mu_m_server): New member `num_children'.

New member `child_pid'.
(children): Remove global.
(m_server_list): New variable. Keeps track of created m_servers.
(alloc_children, register_child, unregister_child)
(terminate_children): New functions.
(m_server_cleanup): New function.
(mu_m_server_idle): Iterate over all registered m-servers until
one of them recognizes the child.
(mu_m_server_create,mu_m_server_destroy): Keep track of existing
m-servers using m_server_list.
(mu_m_server_set_max_children): Rewrite using alloc_children.
(mu_m_server_run): Terminate all children before returning.
(m_srv_conn): Use register_child to remember created children.
1 parent c3aab462
1 2008-02-04 Sergey Poznyakoff <gray@gnu.org.ua> 1 2008-02-04 Sergey Poznyakoff <gray@gnu.org.ua>
2 2
3 * mailbox/msrv.c (struct _mu_m_server): New member `num_children'.
4 New member `child_pid'.
5 (children): Remove global.
6 (m_server_list): New variable. Keeps track of created m_servers.
7 (alloc_children, register_child, unregister_child)
8 (terminate_children): New functions.
9 (m_server_cleanup): New function.
10 (mu_m_server_idle): Iterate over all registered m-servers until
11 one of them recognizes the child.
12 (mu_m_server_create,mu_m_server_destroy): Keep track of existing
13 m-servers using m_server_list.
14 (mu_m_server_set_max_children): Rewrite using alloc_children.
15 (mu_m_server_run): Terminate all children before returning.
16 (m_srv_conn): Use register_child to remember created children.
17
3 * NEWS: Update. 18 * NEWS: Update.
4 * examples/header.c: New command `itr'. 19 * examples/header.c: New command `itr'.
5 (main): Empty input repeats the recent command. 20 (main): Empty input repeats the recent command.
......
...@@ -95,6 +95,8 @@ struct _mu_m_server ...@@ -95,6 +95,8 @@ struct _mu_m_server
95 95
96 int foreground; /* Should the server remain in foregorund? */ 96 int foreground; /* Should the server remain in foregorund? */
97 size_t max_children; /* Maximum number of sub-processes to run. */ 97 size_t max_children; /* Maximum number of sub-processes to run. */
98 size_t num_children; /* Current number of running sub-processes. */
99 pid_t *child_pid;
98 char *pidfile; /* Name of a PID-file. */ 100 char *pidfile; /* Name of a PID-file. */
99 struct m_default_address defaddr; /* Default address. */ 101 struct m_default_address defaddr; /* Default address. */
100 time_t timeout; /* Default idle timeout. */ 102 time_t timeout; /* Default idle timeout. */
...@@ -117,8 +119,86 @@ struct m_srv_config /* Configuration data for a single TCP server. */ ...@@ -117,8 +119,86 @@ struct m_srv_config /* Configuration data for a single TCP server. */
117 119
118 120
119 static int need_cleanup = 0; 121 static int need_cleanup = 0;
120 static int stop = 0; 122 static int stop = 0; /* FIXME: Must be per-m-server */
121 static size_t children; 123 static mu_list_t m_server_list;
124
125 #define UNUSED_PID ((pid_t)-1)
126
127 static void
128 alloc_children (mu_m_server_t srv, size_t num)
129 {
130 int i;
131 size_t size = num * sizeof (srv->child_pid[0]);
132 size_t last;
133
134 if (srv->child_pid)
135 {
136 srv->child_pid = realloc (srv->child_pid, size);
137 last = srv->max_children;
138 }
139 else
140 {
141 srv->child_pid = malloc (size);
142 last = 0;
143 }
144
145 if (!srv->child_pid)
146 {
147 mu_error ("%s", mu_strerror (ENOMEM));
148 abort ();
149 }
150
151 for (i = last; i < num; i++)
152 srv->child_pid[i] = UNUSED_PID;
153
154 srv->max_children = num;
155 }
156
157 static void
158 register_child (mu_m_server_t msrv, pid_t pid)
159 {
160 int i;
161
162 msrv->num_children++;
163 if (!msrv->child_pid)
164 alloc_children (msrv, msrv->max_children);
165 for (i = 0; i < msrv->max_children; i++)
166 if (msrv->child_pid[i] == UNUSED_PID)
167 {
168 msrv->child_pid[i] = pid;
169 return;
170 }
171 mu_error ("%s:%d: cannot find free PID slot (internal error?)",
172 __FILE__, __LINE__);
173 }
174
175 static int
176 unregister_child (mu_m_server_t msrv, pid_t pid)
177 {
178 int i;
179
180 msrv->num_children--;
181 for (i = 0; i < msrv->max_children; i++)
182 if (msrv->child_pid[i] == pid)
183 {
184 msrv->child_pid[i] = UNUSED_PID;
185 return 0;
186 }
187 return 1;
188 }
189
190 static void
191 terminate_children (mu_m_server_t msrv)
192 {
193 if (msrv->child_pid)
194 {
195 int i;
196
197 for (i = 0; i < msrv->max_children; i++)
198 if (msrv->child_pid[i] != UNUSED_PID)
199 kill (msrv->child_pid[i], SIGTERM);
200 }
201 }
122 202
123 void 203 void
124 mu_m_server_stop (int code) 204 mu_m_server_stop (int code)
...@@ -126,38 +206,54 @@ mu_m_server_stop (int code) ...@@ -126,38 +206,54 @@ mu_m_server_stop (int code)
126 stop = code; 206 stop = code;
127 } 207 }
128 208
129 static int 209 struct exit_data
130 mu_m_server_idle (void *server_data MU_ARG_UNUSED)
131 { 210 {
132 pid_t pid; 211 pid_t pid;
133 int status; 212 int status;
213 };
214
215 static int
216 m_server_cleanup (void *item, void *data)
217 {
218 mu_m_server_t msrv = item;
219 struct exit_data *datp = data;
134 220
135 if (need_cleanup) 221 if (unregister_child (msrv, datp->pid) == 0)
136 { 222 {
137 need_cleanup = 0; 223 if (WIFEXITED (datp->status))
138 while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
139 { 224 {
140 --children; 225 int prio = MU_DIAG_INFO;
141 if (WIFEXITED (status)) 226 int code = WEXITSTATUS (datp->status);
142 { 227 if (code == 0)
143 int prio = MU_DIAG_INFO; 228 prio = MU_DIAG_DEBUG;
144 229 mu_diag_output (prio, "process %lu finished with code %d",
145 status = WEXITSTATUS (status); 230 (unsigned long) datp->pid,
146 if (status == 0) 231 code);
147 prio = MU_DIAG_DEBUG;
148 mu_diag_output (prio, "process %lu finished with code %d",
149 (unsigned long) pid,
150 status);
151 }
152 else if (WIFSIGNALED (status))
153 mu_diag_output (MU_DIAG_ERR, "process %lu terminated on signal %d",
154 (unsigned long) pid,
155 WTERMSIG (status));
156 else
157 mu_diag_output (MU_DIAG_ERR,
158 "process %lu terminated (cause unknown)",
159 (unsigned long) pid);
160 } 232 }
233 else if (WIFSIGNALED (datp->status))
234 mu_diag_output (MU_DIAG_ERR, "process %lu terminated on signal %d",
235 (unsigned long) datp->pid,
236 WTERMSIG (datp->status));
237 else
238 mu_diag_output (MU_DIAG_ERR,
239 "process %lu terminated (cause unknown)",
240 (unsigned long) datp->pid);
241 return 1;
242 }
243 return 0;
244 }
245
246 static int
247 mu_m_server_idle (void *server_data MU_ARG_UNUSED)
248 {
249 if (need_cleanup)
250 {
251 struct exit_data ex;
252
253 need_cleanup = 0;
254 while ( (ex.pid = waitpid (-1, &ex.status, WNOHANG)) > 0)
255 /* Iterate over all m-servers and notify them about the fact. */
256 mu_list_do (m_server_list, m_server_cleanup, &ex);
161 } 257 }
162 return stop; 258 return stop;
163 } 259 }
...@@ -208,6 +304,9 @@ mu_m_server_create (mu_m_server_t *psrv, const char *ident) ...@@ -208,6 +304,9 @@ mu_m_server_create (mu_m_server_t *psrv, const char *ident)
208 sigaddset (&srv->sigmask, SIGQUIT); 304 sigaddset (&srv->sigmask, SIGQUIT);
209 sigaddset (&srv->sigmask, SIGHUP); 305 sigaddset (&srv->sigmask, SIGHUP);
210 *psrv = srv; 306 *psrv = srv;
307 if (!m_server_list)
308 mu_list_create (&m_server_list);
309 mu_list_append (m_server_list, srv);
211 } 310 }
212 311
213 void 312 void
...@@ -262,7 +361,7 @@ mu_m_server_set_data (mu_m_server_t srv, void *data) ...@@ -262,7 +361,7 @@ mu_m_server_set_data (mu_m_server_t srv, void *data)
262 void 361 void
263 mu_m_server_set_max_children (mu_m_server_t srv, size_t num) 362 mu_m_server_set_max_children (mu_m_server_t srv, size_t num)
264 { 363 {
265 srv->max_children = num; 364 alloc_children (srv, num);
266 } 365 }
267 366
268 int 367 int
...@@ -457,8 +556,10 @@ void ...@@ -457,8 +556,10 @@ void
457 mu_m_server_destroy (mu_m_server_t *pmsrv) 556 mu_m_server_destroy (mu_m_server_t *pmsrv)
458 { 557 {
459 mu_m_server_t msrv = *pmsrv; 558 mu_m_server_t msrv = *pmsrv;
559 mu_list_remove (m_server_list, msrv);
460 mu_server_destroy (&msrv->server); 560 mu_server_destroy (&msrv->server);
461 /* FIXME: Send processes the TERM signal */ 561 free (msrv->child_pid);
562 /* FIXME: Send processes the TERM signal here?*/
462 free (msrv->ident); 563 free (msrv->ident);
463 free (msrv); 564 free (msrv);
464 *pmsrv = NULL; 565 *pmsrv = NULL;
...@@ -540,6 +641,7 @@ mu_m_server_run (mu_m_server_t msrv) ...@@ -540,6 +641,7 @@ mu_m_server_run (mu_m_server_t msrv)
540 if (msrv->ident) 641 if (msrv->ident)
541 mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident); 642 mu_diag_output (MU_DIAG_INFO, _("%s started"), msrv->ident);
542 rc = mu_server_run (msrv->server); 643 rc = mu_server_run (msrv->server);
644 terminate_children (msrv);
543 if (msrv->ident) 645 if (msrv->ident)
544 mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident); 646 mu_diag_output (MU_DIAG_INFO, _("%s terminated"), msrv->ident);
545 return rc; 647 return rc;
...@@ -606,10 +708,11 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen, ...@@ -606,10 +708,11 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
606 708
607 if (mu_m_server_idle (server_data)) 709 if (mu_m_server_idle (server_data))
608 return MU_SERVER_SHUTDOWN; 710 return MU_SERVER_SHUTDOWN;
609 if (pconf->msrv->max_children && children >= pconf->msrv->max_children) 711 if (pconf->msrv->max_children
712 && pconf->msrv->num_children >= pconf->msrv->max_children)
610 { 713 {
611 mu_diag_output (MU_DIAG_ERROR, _("too many children (%lu)"), 714 mu_diag_output (MU_DIAG_ERROR, _("too many children (%lu)"),
612 (unsigned long) children); 715 (unsigned long) pconf->msrv->num_children);
613 pause (); 716 pause ();
614 return 0; 717 return 0;
615 } 718 }
...@@ -630,7 +733,7 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen, ...@@ -630,7 +733,7 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
630 } 733 }
631 else 734 else
632 { 735 {
633 children++; 736 register_child (pconf->msrv, pid);
634 } 737 }
635 } 738 }
636 else if (!pconf->msrv->prefork 739 else if (!pconf->msrv->prefork
......