Coverage Report

Created: 2023-03-26 06:28

/src/httpd/server/mpm_common.c
Line
Count
Source (jump to first uncovered line)
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
/* The purpose of this file is to store the code that MOST mpm's will need
18
 * this does not mean a function only goes into this file if every MPM needs
19
 * it.  It means that if a function is needed by more than one MPM, and
20
 * future maintenance would be served by making the code common, then the
21
 * function belongs here.
22
 *
23
 * This is going in src/main because it is not platform specific, it is
24
 * specific to multi-process servers, but NOT to Unix.  Which is why it
25
 * does not belong in src/os/unix
26
 */
27
28
#include "apr.h"
29
#include "apr_thread_proc.h"
30
#include "apr_signal.h"
31
#include "apr_strings.h"
32
#define APR_WANT_STRFUNC
33
#include "apr_want.h"
34
#include "apr_getopt.h"
35
#include "apr_optional.h"
36
#include "apr_allocator.h"
37
38
#include "httpd.h"
39
#include "http_config.h"
40
#include "http_core.h"
41
#include "http_log.h"
42
#include "http_main.h"
43
#include "mpm_common.h"
44
#include "mod_core.h"
45
#include "ap_mpm.h"
46
#include "ap_listen.h"
47
#include "util_mutex.h"
48
49
#include "scoreboard.h"
50
51
#ifdef HAVE_PWD_H
52
#include <pwd.h>
53
#endif
54
#ifdef HAVE_GRP_H
55
#include <grp.h>
56
#endif
57
#if APR_HAVE_UNISTD_H
58
#include <unistd.h>
59
#endif
60
61
/* we know core's module_index is 0 */
62
#undef APLOG_MODULE_INDEX
63
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
64
65
#define DEFAULT_HOOK_LINKS \
66
    APR_HOOK_LINK(monitor) \
67
    APR_HOOK_LINK(drop_privileges) \
68
    APR_HOOK_LINK(mpm) \
69
    APR_HOOK_LINK(mpm_query) \
70
    APR_HOOK_LINK(mpm_register_timed_callback) \
71
    APR_HOOK_LINK(mpm_register_poll_callback) \
72
    APR_HOOK_LINK(mpm_register_poll_callback_timeout) \
73
    APR_HOOK_LINK(mpm_get_name) \
74
    APR_HOOK_LINK(mpm_resume_suspended) \
75
    APR_HOOK_LINK(end_generation) \
76
    APR_HOOK_LINK(child_status) \
77
    APR_HOOK_LINK(output_pending) \
78
    APR_HOOK_LINK(input_pending) \
79
    APR_HOOK_LINK(suspend_connection) \
80
    APR_HOOK_LINK(resume_connection) \
81
    APR_HOOK_LINK(child_stopping) \
82
    APR_HOOK_LINK(child_stopped)
83
84
#if AP_ENABLE_EXCEPTION_HOOK
85
APR_HOOK_STRUCT(
86
    APR_HOOK_LINK(fatal_exception)
87
    DEFAULT_HOOK_LINKS
88
)
89
AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
90
                          (ap_exception_info_t *ei), (ei), OK, DECLINED)
91
#else
92
APR_HOOK_STRUCT(
93
    DEFAULT_HOOK_LINKS
94
)
95
#endif
96
AP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
97
                          (apr_pool_t *p, server_rec *s), (p, s), OK, DECLINED)
98
AP_IMPLEMENT_HOOK_RUN_ALL(int, drop_privileges,
99
                          (apr_pool_t * pchild, server_rec * s),
100
                          (pchild, s), OK, DECLINED)
101
102
AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm,
103
                            (apr_pool_t *pconf, apr_pool_t *plog, server_rec *s),
104
                            (pconf, plog, s), DECLINED)
105
AP_IMPLEMENT_HOOK_RUN_FIRST(int, mpm_query,
106
                            (int query_code, int *result, apr_status_t *_rv),
107
                            (query_code, result, _rv), DECLINED)
108
AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_timed_callback,
109
                            (apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton),
110
                            (t, cbfn, baton), APR_ENOTIMPL)
111
AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_resume_suspended,
112
                            (conn_rec *c),
113
                            (c), APR_ENOTIMPL)
114
AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_poll_callback,
115
                            (apr_pool_t *p, const apr_array_header_t *pds,
116
                             ap_mpm_callback_fn_t *cbfn, void *baton),
117
                            (p, pds, cbfn, baton), APR_ENOTIMPL)
118
AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, mpm_register_poll_callback_timeout,
119
                            (apr_pool_t *p, const apr_array_header_t *pds,
120
                             ap_mpm_callback_fn_t *cbfn,
121
                             ap_mpm_callback_fn_t *tofn,
122
                             void *baton, apr_time_t timeout),
123
                            (p, pds, cbfn, tofn, baton, timeout), APR_ENOTIMPL)
124
AP_IMPLEMENT_HOOK_RUN_FIRST(int, output_pending,
125
                            (conn_rec *c), (c), DECLINED)
126
AP_IMPLEMENT_HOOK_RUN_FIRST(int, input_pending,
127
                            (conn_rec *c), (c), DECLINED)
128
129
AP_IMPLEMENT_HOOK_VOID(end_generation,
130
                       (server_rec *s, ap_generation_t gen),
131
                       (s, gen))
132
AP_IMPLEMENT_HOOK_VOID(child_status,
133
                       (server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status status),
134
                       (s,pid,gen,slot,status))
135
AP_IMPLEMENT_HOOK_VOID(suspend_connection,
136
                       (conn_rec *c, request_rec *r),
137
                       (c, r))
138
AP_IMPLEMENT_HOOK_VOID(resume_connection,
139
                       (conn_rec *c, request_rec *r),
140
                       (c, r))
141
AP_IMPLEMENT_HOOK_VOID(child_stopping,
142
                       (apr_pool_t *pchild, int graceful),
143
                       (pchild, graceful))
144
AP_IMPLEMENT_HOOK_VOID(child_stopped,
145
                       (apr_pool_t *pchild, int graceful),
146
                       (pchild, graceful))
147
148
/* hooks with no args are implemented last, after disabling APR hook probes */
149
#if defined(APR_HOOK_PROBES_ENABLED)
150
#undef APR_HOOK_PROBES_ENABLED
151
#undef APR_HOOK_PROBE_ENTRY
152
#define APR_HOOK_PROBE_ENTRY(ud,ns,name,args)
153
#undef APR_HOOK_PROBE_RETURN
154
#define APR_HOOK_PROBE_RETURN(ud,ns,name,rv,args)
155
#undef APR_HOOK_PROBE_INVOKE
156
#define APR_HOOK_PROBE_INVOKE(ud,ns,name,src,args)
157
#undef APR_HOOK_PROBE_COMPLETE
158
#define APR_HOOK_PROBE_COMPLETE(ud,ns,name,src,rv,args)
159
#undef APR_HOOK_INT_DCL_UD
160
#define APR_HOOK_INT_DCL_UD
161
#endif
162
AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
163
                            (void),
164
                            (), NULL)
165
166
typedef struct mpm_gen_info_t {
167
    APR_RING_ENTRY(mpm_gen_info_t) link;
168
    int gen;          /* which gen? */
169
    int active;       /* number of active processes */
170
    int done;         /* gen finished? (whether or not active processes) */
171
} mpm_gen_info_t;
172
173
APR_RING_HEAD(mpm_gen_info_head_t, mpm_gen_info_t);
174
static struct mpm_gen_info_head_t *geninfo, *unused_geninfo;
175
static int gen_head_init; /* yuck */
176
177
/* variables representing config directives implemented here */
178
AP_DECLARE_DATA const char *ap_pid_fname;
179
AP_DECLARE_DATA int ap_max_requests_per_child;
180
AP_DECLARE_DATA char ap_coredump_dir[MAX_STRING_LEN];
181
AP_DECLARE_DATA int ap_coredumpdir_configured;
182
AP_DECLARE_DATA int ap_graceful_shutdown_timeout;
183
AP_DECLARE_DATA apr_size_t ap_thread_stacksize;
184
185
0
#define ALLOCATOR_MAX_FREE_DEFAULT (2048*1024)
186
AP_DECLARE_DATA apr_uint32_t ap_max_mem_free = ALLOCATOR_MAX_FREE_DEFAULT;
187
188
/* Set defaults for config directives implemented here.  This is
189
 * called from core's pre-config hook, so MPMs which need to override
190
 * one of these should run their pre-config hook after that of core.
191
 */
192
void mpm_common_pre_config(apr_pool_t *pconf)
193
0
{
194
0
    ap_pid_fname = DEFAULT_PIDLOG;
195
0
    ap_max_requests_per_child = 0; /* unlimited */
196
0
    apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));
197
0
    ap_coredumpdir_configured = 0;
198
0
    ap_graceful_shutdown_timeout = 0; /* unlimited */
199
0
    ap_max_mem_free = ALLOCATOR_MAX_FREE_DEFAULT;
200
0
    ap_thread_stacksize = 0; /* use system default */
201
0
}
202
203
/* number of calls to wait_or_timeout between writable probes */
204
#ifndef INTERVAL_OF_WRITABLE_PROBES
205
0
#define INTERVAL_OF_WRITABLE_PROBES 10
206
#endif
207
static int wait_or_timeout_counter;
208
209
AP_DECLARE(void) ap_wait_or_timeout(apr_exit_why_e *status, int *exitcode,
210
                                    apr_proc_t *ret, apr_pool_t *p,
211
                                    server_rec *s)
212
0
{
213
0
    apr_status_t rv;
214
215
0
    ++wait_or_timeout_counter;
216
0
    if (wait_or_timeout_counter == INTERVAL_OF_WRITABLE_PROBES) {
217
0
        wait_or_timeout_counter = 0;
218
0
        ap_run_monitor(p, s);
219
0
    }
220
221
0
    rv = apr_proc_wait_all_procs(ret, exitcode, status, APR_NOWAIT, p);
222
0
    ap_update_global_status();
223
224
0
    if (APR_STATUS_IS_EINTR(rv)) {
225
0
        ret->pid = -1;
226
0
        return;
227
0
    }
228
229
0
    if (APR_STATUS_IS_CHILD_DONE(rv)) {
230
0
        return;
231
0
    }
232
233
0
    apr_sleep(apr_time_from_sec(1));
234
0
    ret->pid = -1;
235
0
}
236
237
#if defined(TCP_NODELAY)
238
void ap_sock_disable_nagle(apr_socket_t *s)
239
0
{
240
    /* The Nagle algorithm says that we should delay sending partial
241
     * packets in hopes of getting more data.  We don't want to do
242
     * this; we are not telnet.  There are bad interactions between
243
     * persistent connections and Nagle's algorithm that have very severe
244
     * performance penalties.  (Failing to disable Nagle is not much of a
245
     * problem with simple HTTP.)
246
     *
247
     * In spite of these problems, failure here is not a shooting offense.
248
     */
249
0
    apr_status_t status = apr_socket_opt_set(s, APR_TCP_NODELAY, 1);
250
251
0
    if (status != APR_SUCCESS) {
252
0
        ap_log_error(APLOG_MARK, APLOG_WARNING, status, ap_server_conf, APLOGNO(00542)
253
0
                     "apr_socket_opt_set: (TCP_NODELAY)");
254
0
    }
255
0
}
256
#endif
257
258
#ifdef HAVE_GETPWNAM
259
AP_DECLARE(uid_t) ap_uname2id(const char *name)
260
0
{
261
0
    struct passwd *ent;
262
263
0
    if (name[0] == '#')
264
0
        return (atoi(&name[1]));
265
266
0
    if (!(ent = getpwnam(name))) {
267
0
        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00543)
268
0
                     "%s: bad user name %s", ap_server_argv0, name);
269
0
        exit(1);
270
0
    }
271
272
0
    return (ent->pw_uid);
273
0
}
274
#endif
275
276
#ifdef HAVE_GETGRNAM
277
AP_DECLARE(gid_t) ap_gname2id(const char *name)
278
0
{
279
0
    struct group *ent;
280
281
0
    if (name[0] == '#')
282
0
        return (atoi(&name[1]));
283
284
0
    if (!(ent = getgrnam(name))) {
285
0
        ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00544)
286
0
                     "%s: bad group name %s", ap_server_argv0, name);
287
0
        exit(1);
288
0
    }
289
290
0
    return (ent->gr_gid);
291
0
}
292
#endif
293
294
#ifndef HAVE_INITGROUPS
295
int initgroups(const char *name, gid_t basegid)
296
{
297
#if defined(_OSD_POSIX) || defined(OS2) || defined(WIN32) || defined(NETWARE)
298
    return 0;
299
#else
300
    gid_t groups[NGROUPS_MAX];
301
    struct group *g;
302
    int index = 0;
303
304
    setgrent();
305
306
    groups[index++] = basegid;
307
308
    while (index < NGROUPS_MAX && ((g = getgrent()) != NULL)) {
309
        if (g->gr_gid != basegid) {
310
            char **names;
311
312
            for (names = g->gr_mem; *names != NULL; ++names) {
313
                if (!strcmp(*names, name))
314
                    groups[index++] = g->gr_gid;
315
            }
316
        }
317
    }
318
319
    endgrent();
320
321
    return setgroups(index, groups);
322
#endif
323
}
324
#endif /* def HAVE_INITGROUPS */
325
326
/* standard mpm configuration handling */
327
328
const char *ap_mpm_set_pidfile(cmd_parms *cmd, void *dummy,
329
                               const char *arg)
330
0
{
331
0
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
332
0
    if (err != NULL) {
333
0
        return err;
334
0
    }
335
336
0
    if (cmd->server->is_virtual) {
337
0
        return "PidFile directive not allowed in <VirtualHost>";
338
0
    }
339
340
0
    ap_pid_fname = arg;
341
0
    return NULL;
342
0
}
343
344
void ap_mpm_dump_pidfile(apr_pool_t *p, apr_file_t *out)
345
0
{
346
0
    apr_file_printf(out, "PidFile: \"%s\"\n",
347
0
                    ap_runtime_dir_relative(p, ap_pid_fname));
348
0
}
349
350
const char *ap_mpm_set_max_requests(cmd_parms *cmd, void *dummy,
351
                                    const char *arg)
352
0
{
353
0
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
354
0
    if (err != NULL) {
355
0
        return err;
356
0
    }
357
358
0
    if (!strcasecmp(cmd->cmd->name, "MaxRequestsPerChild")) {
359
0
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(00545)
360
0
                     "MaxRequestsPerChild is deprecated, use "
361
0
                     "MaxConnectionsPerChild instead.");
362
0
    }
363
364
0
    ap_max_requests_per_child = atoi(arg);
365
366
0
    return NULL;
367
0
}
368
369
const char *ap_mpm_set_coredumpdir(cmd_parms *cmd, void *dummy,
370
                                   const char *arg)
371
0
{
372
0
    apr_finfo_t finfo;
373
0
    const char *fname;
374
0
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
375
0
    if (err != NULL) {
376
0
        return err;
377
0
    }
378
379
0
    fname = ap_server_root_relative(cmd->temp_pool, arg);
380
0
    if (!fname) {
381
0
        return apr_pstrcat(cmd->pool, "Invalid CoreDumpDirectory path ",
382
0
                           arg, NULL);
383
0
    }
384
0
    if (apr_stat(&finfo, fname, APR_FINFO_TYPE, cmd->pool) != APR_SUCCESS) {
385
0
        return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
386
0
                           " does not exist", NULL);
387
0
    }
388
0
    if (finfo.filetype != APR_DIR) {
389
0
        return apr_pstrcat(cmd->pool, "CoreDumpDirectory ", fname,
390
0
                           " is not a directory", NULL);
391
0
    }
392
0
    apr_cpystrn(ap_coredump_dir, fname, sizeof(ap_coredump_dir));
393
0
    ap_coredumpdir_configured = 1;
394
0
    return NULL;
395
0
}
396
397
AP_DECLARE(const char *)ap_mpm_set_graceful_shutdown(cmd_parms *cmd,
398
                                                     void *dummy,
399
                                                     const char *arg)
400
0
{
401
0
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
402
0
    if (err != NULL) {
403
0
        return err;
404
0
    }
405
0
    ap_graceful_shutdown_timeout = atoi(arg);
406
0
    return NULL;
407
0
}
408
409
const char *ap_mpm_set_max_mem_free(cmd_parms *cmd, void *dummy,
410
                                    const char *arg)
411
0
{
412
0
    long value;
413
0
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
414
0
    if (err != NULL) {
415
0
        return err;
416
0
    }
417
418
0
    errno = 0;
419
0
    value = strtol(arg, NULL, 10);
420
0
    if (value < 0 || errno == ERANGE)
421
0
        return apr_pstrcat(cmd->pool, "Invalid MaxMemFree value: ",
422
0
                           arg, NULL);
423
424
0
    ap_max_mem_free = (apr_uint32_t)value * 1024;
425
426
0
    return NULL;
427
0
}
428
429
const char *ap_mpm_set_thread_stacksize(cmd_parms *cmd, void *dummy,
430
                                        const char *arg)
431
0
{
432
0
    long value;
433
0
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
434
0
    if (err != NULL) {
435
0
        return err;
436
0
    }
437
438
0
    errno = 0;
439
0
    value = strtol(arg, NULL, 10);
440
0
    if (value < 0 || errno == ERANGE)
441
0
        return apr_pstrcat(cmd->pool, "Invalid ThreadStackSize value: ",
442
0
                           arg, NULL);
443
444
0
    ap_thread_stacksize = (apr_size_t)value;
445
446
0
    return NULL;
447
0
}
448
449
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
450
0
{
451
0
    apr_status_t rv;
452
453
0
    if (ap_run_mpm_query(query_code, result, &rv) == DECLINED) {
454
0
        rv = APR_EGENERAL;
455
0
    }
456
457
0
    return rv;
458
0
}
459
460
static void end_gen(mpm_gen_info_t *gi)
461
0
{
462
0
    ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
463
0
                 "end of generation %d", gi->gen);
464
0
    ap_run_end_generation(ap_server_conf, gi->gen);
465
0
    APR_RING_REMOVE(gi, link);
466
0
    APR_RING_INSERT_HEAD(unused_geninfo, gi, mpm_gen_info_t, link);
467
0
}
468
469
apr_status_t ap_mpm_end_gen_helper(void *unused) /* cleanup on pconf */
470
0
{
471
0
    int gen = ap_config_generation - 1; /* differs from MPM generation */
472
0
    mpm_gen_info_t *cur;
473
474
0
    if (geninfo == NULL) {
475
        /* initial pconf teardown, MPM hasn't run */
476
0
        return APR_SUCCESS;
477
0
    }
478
479
0
    cur = APR_RING_FIRST(geninfo);
480
0
    while (cur != APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link) &&
481
0
           cur->gen != gen) {
482
0
        cur = APR_RING_NEXT(cur, link);
483
0
    }
484
485
0
    if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
486
        /* last child of generation already exited */
487
0
        ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
488
0
                     "no record of generation %d", gen);
489
0
    }
490
0
    else {
491
0
        cur->done = 1;
492
0
        if (cur->active == 0) {
493
0
            end_gen(cur);
494
0
        }
495
0
    }
496
497
0
    return APR_SUCCESS;
498
0
}
499
500
/* core's child-status hook
501
 * tracks number of remaining children per generation and
502
 * runs the end-generation hook when the last child of
503
 * a generation exits
504
 */
505
void ap_core_child_status(server_rec *s, pid_t pid,
506
                          ap_generation_t gen, int slot,
507
                          mpm_child_status status)
508
0
{
509
0
    mpm_gen_info_t *cur;
510
0
    const char *status_msg = "unknown status";
511
512
0
    if (!gen_head_init) { /* where to run this? */
513
0
        gen_head_init = 1;
514
0
        geninfo = apr_pcalloc(s->process->pool, sizeof *geninfo);
515
0
        unused_geninfo = apr_pcalloc(s->process->pool, sizeof *unused_geninfo);
516
0
        APR_RING_INIT(geninfo, mpm_gen_info_t, link);
517
0
        APR_RING_INIT(unused_geninfo, mpm_gen_info_t, link);
518
0
    }
519
520
0
    cur = APR_RING_FIRST(geninfo);
521
0
    while (cur != APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link) &&
522
0
           cur->gen != gen) {
523
0
        cur = APR_RING_NEXT(cur, link);
524
0
    }
525
526
0
    switch(status) {
527
0
    case MPM_CHILD_STARTED:
528
0
        status_msg = "started";
529
0
        if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
530
            /* first child for this generation */
531
0
            if (!APR_RING_EMPTY(unused_geninfo, mpm_gen_info_t, link)) {
532
0
                cur = APR_RING_FIRST(unused_geninfo);
533
0
                APR_RING_REMOVE(cur, link);
534
0
                cur->active = cur->done = 0;
535
0
            }
536
0
            else {
537
0
                cur = apr_pcalloc(s->process->pool, sizeof *cur);
538
0
            }
539
0
            cur->gen = gen;
540
0
            APR_RING_ELEM_INIT(cur, link);
541
0
            APR_RING_INSERT_HEAD(geninfo, cur, mpm_gen_info_t, link);
542
0
        }
543
0
        ap_random_parent_after_fork();
544
0
        ++cur->active;
545
0
        break;
546
0
    case MPM_CHILD_EXITED:
547
0
        ap_update_global_status();
548
0
        status_msg = "exited";
549
0
        if (cur == APR_RING_SENTINEL(geninfo, mpm_gen_info_t, link)) {
550
0
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00546)
551
0
                         "no record of generation %d of exiting child %" APR_PID_T_FMT,
552
0
                         gen, pid);
553
0
        }
554
0
        else {
555
0
            --cur->active;
556
0
            if (!cur->active && cur->done) { /* no children, server has stopped/restarted */
557
0
                end_gen(cur);
558
0
            }
559
0
        }
560
0
        break;
561
0
    case MPM_CHILD_LOST_SLOT:
562
0
        status_msg = "lost slot";
563
        /* we don't track by slot, so it doesn't matter */
564
0
        break;
565
0
    }
566
0
    ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, s,
567
0
                 "mpm child %" APR_PID_T_FMT " (gen %d/slot %d) %s",
568
0
                 pid, gen, slot, status_msg);
569
0
}
570
571
AP_DECLARE(apr_status_t) ap_mpm_resume_suspended(conn_rec *c)
572
0
{
573
0
    return ap_run_mpm_resume_suspended(c);
574
0
}
575
576
AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t,
577
        ap_mpm_callback_fn_t *cbfn, void *baton)
578
0
{
579
0
    return ap_run_mpm_register_timed_callback(t, cbfn, baton);
580
0
}
581
582
AP_DECLARE(apr_status_t) ap_mpm_register_poll_callback(
583
        apr_pool_t *p, const apr_array_header_t *pfds,
584
        ap_mpm_callback_fn_t *cbfn, void *baton)
585
0
{
586
0
    return ap_run_mpm_register_poll_callback(p, pfds, cbfn, baton);
587
0
}
588
589
AP_DECLARE(apr_status_t) ap_mpm_register_poll_callback_timeout(
590
        apr_pool_t *p, const apr_array_header_t *pfds,
591
        ap_mpm_callback_fn_t *cbfn, ap_mpm_callback_fn_t *tofn,
592
        void *baton, apr_time_t timeout)
593
0
{
594
0
    return ap_run_mpm_register_poll_callback_timeout(p, pfds, cbfn, tofn,
595
0
                                                     baton, timeout);
596
0
}
597
598
AP_DECLARE(const char *)ap_show_mpm(void)
599
0
{
600
0
    const char *name = ap_run_mpm_get_name();
601
602
0
    if (!name) {
603
0
        name = "";
604
0
    }
605
606
0
    return name;
607
0
}
608
609
AP_DECLARE(const char *)ap_check_mpm(void)
610
0
{
611
0
    static const char *last_mpm_name = NULL;
612
613
0
    if (!_hooks.link_mpm || _hooks.link_mpm->nelts == 0)
614
0
        return "No MPM loaded.";
615
0
    else if (_hooks.link_mpm->nelts > 1)
616
0
        return "More than one MPM loaded.";
617
618
0
    if (last_mpm_name) {
619
0
        if (strcmp(last_mpm_name, ap_show_mpm())) {
620
0
            return "The MPM cannot be changed during restart.";
621
0
        }
622
0
    }
623
0
    else {
624
0
        last_mpm_name = apr_pstrdup(ap_pglobal, ap_show_mpm());
625
0
    }
626
627
0
    return NULL;
628
0
}