~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to server/mpm/mpmt_os2/mpmt_os2.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* Multi-process, multi-threaded MPM for OS/2
 
18
 *
 
19
 * Server consists of
 
20
 * - a main, parent process
 
21
 * - a small, static number of child processes
 
22
 *
 
23
 * The parent process's job is to manage the child processes. This involves
 
24
 * spawning children as required to ensure there are always ap_daemons_to_start
 
25
 * processes accepting connections.
 
26
 *
 
27
 * Each child process consists of a a pool of worker threads and a
 
28
 * main thread that accepts connections & passes them to the workers via
 
29
 * a work queue. The worker thread pool is dynamic, managed by a maintanence
 
30
 * thread so that the number of idle threads is kept between
 
31
 * min_spare_threads & max_spare_threads.
 
32
 *
 
33
 */
 
34
 
 
35
/*
 
36
 Todo list
 
37
 - Enforce MaxClients somehow
 
38
*/
 
39
#define CORE_PRIVATE
 
40
#define INCL_NOPMAPI
 
41
#define INCL_DOS
 
42
#define INCL_DOSERRORS
 
43
 
 
44
#include "ap_config.h"
 
45
#include "httpd.h"
 
46
#include "mpm_default.h"
 
47
#include "http_main.h"
 
48
#include "http_log.h"
 
49
#include "http_config.h"
 
50
#include "http_core.h"  /* for get_remote_host */
 
51
#include "http_connection.h"
 
52
#include "mpm.h"
 
53
#include "ap_mpm.h"
 
54
#include "ap_listen.h"
 
55
#include "apr_portable.h"
 
56
#include "mpm_common.h"
 
57
#include "apr_strings.h"
 
58
#include <os2.h>
 
59
#include <process.h>
 
60
 
 
61
/* We don't need many processes,
 
62
 * they're only for redundancy in the event of a crash
 
63
 */
 
64
#define HARD_SERVER_LIMIT 10
 
65
 
 
66
/* Limit on the total number of threads per process
 
67
 */
 
68
#ifndef HARD_THREAD_LIMIT
 
69
#define HARD_THREAD_LIMIT 256
 
70
#endif
 
71
 
 
72
server_rec *ap_server_conf;
 
73
static apr_pool_t *pconf = NULL;  /* Pool for config stuff */
 
74
static const char *ap_pid_fname=NULL;
 
75
 
 
76
/* Config globals */
 
77
static int one_process = 0;
 
78
static int ap_daemons_to_start = 0;
 
79
static int ap_thread_limit = 0;
 
80
static int ap_max_requests_per_child = 0;
 
81
int ap_min_spare_threads = 0;
 
82
int ap_max_spare_threads = 0;
 
83
 
 
84
/* Keep track of a few interesting statistics */
 
85
int ap_max_daemons_limit = -1;
 
86
 
 
87
/* volatile just in case */
 
88
static int volatile shutdown_pending;
 
89
static int volatile restart_pending;
 
90
static int volatile is_graceful = 0;
 
91
ap_generation_t volatile ap_my_generation=0; /* Used by the scoreboard */
 
92
static int is_parent_process=TRUE;
 
93
HMTX ap_mpm_accept_mutex = 0;
 
94
 
 
95
/* An array of these is stored in a shared memory area for passing
 
96
 * sockets from the parent to child processes
 
97
 */
 
98
typedef struct {
 
99
    struct sockaddr_in name;
 
100
    apr_os_sock_t listen_fd;
 
101
} listen_socket_t;
 
102
 
 
103
typedef struct {
 
104
    HMTX accept_mutex;
 
105
    listen_socket_t listeners[1];
 
106
} parent_info_t;
 
107
 
 
108
static char master_main();
 
109
static void spawn_child(int slot);
 
110
void ap_mpm_child_main(apr_pool_t *pconf);
 
111
static void set_signals();
 
112
 
 
113
 
 
114
int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s )
 
115
{
 
116
    char *listener_shm_name;
 
117
    parent_info_t *parent_info;
 
118
    ULONG rc;
 
119
    pconf = _pconf;
 
120
    ap_server_conf = s;
 
121
    restart_pending = 0;
 
122
 
 
123
    DosSetMaxFH(ap_thread_limit * 2);
 
124
    listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getppid());
 
125
    rc = DosGetNamedSharedMem((PPVOID)&parent_info, listener_shm_name, PAG_READ);
 
126
    is_parent_process = rc != 0;
 
127
    ap_scoreboard_fname = apr_psprintf(pconf, "/sharemem/httpd/scoreboard.%d", is_parent_process ? getpid() : getppid());
 
128
 
 
129
    if (rc == 0) {
 
130
        /* Child process */
 
131
        ap_listen_rec *lr;
 
132
        int num_listeners = 0;
 
133
 
 
134
        ap_mpm_accept_mutex = parent_info->accept_mutex;
 
135
 
 
136
        /* Set up a default listener if necessary */
 
137
        if (ap_listeners == NULL) {
 
138
            ap_listen_rec *lr = apr_pcalloc(s->process->pool, sizeof(ap_listen_rec));
 
139
            ap_listeners = lr;
 
140
            apr_sockaddr_info_get(&lr->bind_addr, "0.0.0.0", APR_UNSPEC,
 
141
                                  DEFAULT_HTTP_PORT, 0, s->process->pool);
 
142
            apr_socket_create(&lr->sd, lr->bind_addr->family,
 
143
                              SOCK_STREAM, 0, s->process->pool);
 
144
        }
 
145
 
 
146
        for (lr = ap_listeners; lr; lr = lr->next) {
 
147
            apr_sockaddr_t *sa;
 
148
            apr_os_sock_put(&lr->sd, &parent_info->listeners[num_listeners].listen_fd, pconf);
 
149
            apr_socket_addr_get(&sa, APR_LOCAL, lr->sd);
 
150
            num_listeners++;
 
151
        }
 
152
 
 
153
        DosFreeMem(parent_info);
 
154
 
 
155
        /* Do the work */
 
156
        ap_mpm_child_main(pconf);
 
157
 
 
158
        /* Outta here */
 
159
        return 1;
 
160
    }
 
161
    else {
 
162
        /* Parent process */
 
163
        char restart;
 
164
        is_parent_process = TRUE;
 
165
 
 
166
        if (ap_setup_listeners(ap_server_conf) < 1) {
 
167
            ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s,
 
168
                         "no listening sockets available, shutting down");
 
169
            return 1;
 
170
        }
 
171
 
 
172
        ap_log_pid(pconf, ap_pid_fname);
 
173
 
 
174
        restart = master_main();
 
175
        ++ap_my_generation;
 
176
        ap_scoreboard_image->global->running_generation = ap_my_generation;
 
177
 
 
178
        if (!restart) {
 
179
            const char *pidfile = ap_server_root_relative(pconf, ap_pid_fname);
 
180
 
 
181
            if (pidfile != NULL && remove(pidfile) == 0) {
 
182
                ap_log_error(APLOG_MARK, APLOG_INFO, APR_SUCCESS,
 
183
                             ap_server_conf, "removed PID file %s (pid=%d)",
 
184
                             pidfile, getpid());
 
185
            }
 
186
 
 
187
            ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
 
188
                         "caught SIGTERM, shutting down");
 
189
            return 1;
 
190
        }
 
191
    }  /* Parent process */
 
192
 
 
193
    return 0; /* Restart */
 
194
}
 
195
 
 
196
 
 
197
 
 
198
/* Main processing of the parent process
 
199
 * returns TRUE if restarting
 
200
 */
 
201
static char master_main()
 
202
{
 
203
    server_rec *s = ap_server_conf;
 
204
    ap_listen_rec *lr;
 
205
    parent_info_t *parent_info;
 
206
    char *listener_shm_name;
 
207
    int listener_num, num_listeners, slot;
 
208
    ULONG rc;
 
209
 
 
210
    printf("%s \n", ap_get_server_version());
 
211
    set_signals();
 
212
 
 
213
    if (ap_setup_listeners(ap_server_conf) < 1) {
 
214
        ap_log_error(APLOG_MARK, APLOG_ALERT, 0, s,
 
215
                     "no listening sockets available, shutting down");
 
216
        return FALSE;
 
217
    }
 
218
 
 
219
    /* Allocate a shared memory block for the array of listeners */
 
220
    for (num_listeners = 0, lr = ap_listeners; lr; lr = lr->next) {
 
221
        num_listeners++;
 
222
    }
 
223
 
 
224
    listener_shm_name = apr_psprintf(pconf, "/sharemem/httpd/parent_info.%d", getpid());
 
225
    rc = DosAllocSharedMem((PPVOID)&parent_info, listener_shm_name,
 
226
                           sizeof(parent_info_t) + num_listeners * sizeof(listen_socket_t),
 
227
                           PAG_READ|PAG_WRITE|PAG_COMMIT);
 
228
 
 
229
    if (rc) {
 
230
        ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s,
 
231
                     "failure allocating shared memory, shutting down");
 
232
        return FALSE;
 
233
    }
 
234
 
 
235
    /* Store the listener sockets in the shared memory area for our children to see */
 
236
    for (listener_num = 0, lr = ap_listeners; lr; lr = lr->next, listener_num++) {
 
237
        apr_os_sock_get(&parent_info->listeners[listener_num].listen_fd, lr->sd);
 
238
    }
 
239
 
 
240
    /* Create mutex to prevent multiple child processes from detecting
 
241
     * a connection with apr_poll()
 
242
     */
 
243
 
 
244
    rc = DosCreateMutexSem(NULL, &ap_mpm_accept_mutex, DC_SEM_SHARED, FALSE);
 
245
 
 
246
    if (rc) {
 
247
        ap_log_error(APLOG_MARK, APLOG_ALERT, APR_FROM_OS_ERROR(rc), s,
 
248
                     "failure creating accept mutex, shutting down");
 
249
        return FALSE;
 
250
    }
 
251
 
 
252
    parent_info->accept_mutex = ap_mpm_accept_mutex;
 
253
 
 
254
    /* Allocate shared memory for scoreboard */
 
255
    if (ap_scoreboard_image == NULL) {
 
256
        void *sb_mem;
 
257
        rc = DosAllocSharedMem(&sb_mem, ap_scoreboard_fname,
 
258
                               ap_calc_scoreboard_size(),
 
259
                               PAG_COMMIT|PAG_READ|PAG_WRITE);
 
260
 
 
261
        if (rc) {
 
262
            ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
 
263
                         "unable to allocate shared memory for scoreboard , exiting");
 
264
            return FALSE;
 
265
        }
 
266
 
 
267
        ap_init_scoreboard(sb_mem);
 
268
    }
 
269
 
 
270
    ap_scoreboard_image->global->restart_time = apr_time_now();
 
271
    ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
 
272
                "%s configured -- resuming normal operations",
 
273
                ap_get_server_version());
 
274
    ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf,
 
275
                "Server built: %s", ap_get_server_built());
 
276
#ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
 
277
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
 
278
                "AcceptMutex: %s (default: %s)",
 
279
                apr_proc_mutex_name(accept_mutex),
 
280
                apr_proc_mutex_defname());
 
281
#endif
 
282
    if (one_process) {
 
283
        ap_scoreboard_image->parent[0].pid = getpid();
 
284
        ap_mpm_child_main(pconf);
 
285
        return FALSE;
 
286
    }
 
287
 
 
288
    while (!restart_pending && !shutdown_pending) {
 
289
        RESULTCODES proc_rc;
 
290
        PID child_pid;
 
291
        int active_children = 0;
 
292
 
 
293
        /* Count number of active children */
 
294
        for (slot=0; slot < HARD_SERVER_LIMIT; slot++) {
 
295
            active_children += ap_scoreboard_image->parent[slot].pid != 0 &&
 
296
                !ap_scoreboard_image->parent[slot].quiescing;
 
297
        }
 
298
 
 
299
        /* Spawn children if needed */
 
300
        for (slot=0; slot < HARD_SERVER_LIMIT && active_children < ap_daemons_to_start; slot++) {
 
301
            if (ap_scoreboard_image->parent[slot].pid == 0) {
 
302
                spawn_child(slot);
 
303
                active_children++;
 
304
            }
 
305
        }
 
306
 
 
307
        rc = DosWaitChild(DCWA_PROCESSTREE, DCWW_NOWAIT, &proc_rc, &child_pid, 0);
 
308
 
 
309
        if (rc == 0) {
 
310
            /* A child has terminated, remove its scoreboard entry & terminate if necessary */
 
311
            for (slot=0; ap_scoreboard_image->parent[slot].pid != child_pid && slot < HARD_SERVER_LIMIT; slot++);
 
312
 
 
313
            if (slot < HARD_SERVER_LIMIT) {
 
314
                ap_scoreboard_image->parent[slot].pid = 0;
 
315
                ap_scoreboard_image->parent[slot].quiescing = 0;
 
316
 
 
317
                if (proc_rc.codeTerminate == TC_EXIT) {
 
318
                    /* Child terminated normally, check its exit code and
 
319
                     * terminate server if child indicates a fatal error
 
320
                     */
 
321
                    if (proc_rc.codeResult == APEXIT_CHILDFATAL)
 
322
                        break;
 
323
                }
 
324
            }
 
325
        } else if (rc == ERROR_CHILD_NOT_COMPLETE) {
 
326
            /* No child exited, lets sleep for a while.... */
 
327
            apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL);
 
328
        }
 
329
    }
 
330
 
 
331
    /* Signal children to shut down, either gracefully or immediately */
 
332
    for (slot=0; slot<HARD_SERVER_LIMIT; slot++) {
 
333
      kill(ap_scoreboard_image->parent[slot].pid, is_graceful ? SIGHUP : SIGTERM);
 
334
    }
 
335
 
 
336
    DosFreeMem(parent_info);
 
337
    return restart_pending;
 
338
}
 
339
 
 
340
 
 
341
 
 
342
static void spawn_child(int slot)
 
343
{
 
344
    PPIB ppib;
 
345
    PTIB ptib;
 
346
    char fail_module[100];
 
347
    char progname[CCHMAXPATH];
 
348
    RESULTCODES proc_rc;
 
349
    ULONG rc;
 
350
 
 
351
    ap_scoreboard_image->parent[slot].generation = ap_my_generation;
 
352
    DosGetInfoBlocks(&ptib, &ppib);
 
353
    DosQueryModuleName(ppib->pib_hmte, sizeof(progname), progname);
 
354
    rc = DosExecPgm(fail_module, sizeof(fail_module), EXEC_ASYNCRESULT,
 
355
                    ppib->pib_pchcmd, NULL, &proc_rc, progname);
 
356
 
 
357
    if (rc) {
 
358
        ap_log_error(APLOG_MARK, APLOG_ERR, APR_FROM_OS_ERROR(rc), ap_server_conf,
 
359
                     "error spawning child, slot %d", slot);
 
360
    }
 
361
 
 
362
    if (ap_max_daemons_limit < slot) {
 
363
        ap_max_daemons_limit = slot;
 
364
    }
 
365
 
 
366
    ap_scoreboard_image->parent[slot].pid = proc_rc.codeTerminate;
 
367
}
 
368
 
 
369
 
 
370
 
 
371
/* Signal handling routines */
 
372
 
 
373
static void sig_term(int sig)
 
374
{
 
375
    shutdown_pending = 1;
 
376
    signal(SIGTERM, SIG_DFL);
 
377
}
 
378
 
 
379
 
 
380
 
 
381
static void sig_restart(int sig)
 
382
{
 
383
    if (sig == SIGUSR1) {
 
384
        is_graceful = 1;
 
385
    }
 
386
 
 
387
    restart_pending = 1;
 
388
}
 
389
 
 
390
 
 
391
 
 
392
static void set_signals()
 
393
{
 
394
    struct sigaction sa;
 
395
 
 
396
    sigemptyset(&sa.sa_mask);
 
397
    sa.sa_flags = 0;
 
398
    sa.sa_handler = sig_term;
 
399
 
 
400
    if (sigaction(SIGTERM, &sa, NULL) < 0)
 
401
        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
 
402
 
 
403
    if (sigaction(SIGINT, &sa, NULL) < 0)
 
404
        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGINT)");
 
405
 
 
406
    sa.sa_handler = sig_restart;
 
407
 
 
408
    if (sigaction(SIGHUP, &sa, NULL) < 0)
 
409
        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGHUP)");
 
410
    if (sigaction(SIGUSR1, &sa, NULL) < 0)
 
411
        ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGUSR1)");
 
412
}
 
413
 
 
414
 
 
415
 
 
416
/* Enquiry functions used get MPM status info */
 
417
 
 
418
AP_DECLARE(apr_status_t) ap_mpm_query(int query_code, int *result)
 
419
{
 
420
    switch (query_code) {
 
421
        case AP_MPMQ_MAX_DAEMON_USED:
 
422
            *result = ap_max_daemons_limit;
 
423
            return APR_SUCCESS;
 
424
        case AP_MPMQ_IS_THREADED:
 
425
            *result = AP_MPMQ_DYNAMIC;
 
426
            return APR_SUCCESS;
 
427
        case AP_MPMQ_IS_FORKED:
 
428
            *result = AP_MPMQ_NOT_SUPPORTED;
 
429
            return APR_SUCCESS;
 
430
        case AP_MPMQ_HARD_LIMIT_DAEMONS:
 
431
            *result = HARD_SERVER_LIMIT;
 
432
            return APR_SUCCESS;
 
433
        case AP_MPMQ_HARD_LIMIT_THREADS:
 
434
            *result = HARD_THREAD_LIMIT;
 
435
            return APR_SUCCESS;
 
436
        case AP_MPMQ_MIN_SPARE_DAEMONS:
 
437
            *result = 0;
 
438
            return APR_SUCCESS;
 
439
        case AP_MPMQ_MAX_SPARE_DAEMONS:
 
440
            *result = 0;
 
441
            return APR_SUCCESS;
 
442
        case AP_MPMQ_MAX_REQUESTS_DAEMON:
 
443
            *result = ap_max_requests_per_child;
 
444
            return APR_SUCCESS;
 
445
    }
 
446
    return APR_ENOTIMPL;
 
447
}
 
448
 
 
449
 
 
450
 
 
451
int ap_graceful_stop_signalled(void)
 
452
{
 
453
    return is_graceful;
 
454
}
 
455
 
 
456
 
 
457
 
 
458
/* Configuration handling stuff */
 
459
 
 
460
static int mpmt_os2_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp)
 
461
{
 
462
    one_process = ap_exists_config_define("ONE_PROCESS") ||
 
463
                  ap_exists_config_define("DEBUG");
 
464
    is_graceful = 0;
 
465
    ap_listen_pre_config();
 
466
    ap_daemons_to_start = DEFAULT_START_DAEMON;
 
467
    ap_thread_limit = HARD_THREAD_LIMIT;
 
468
    ap_pid_fname = DEFAULT_PIDLOG;
 
469
    ap_max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;
 
470
    ap_extended_status = 0;
 
471
    ap_min_spare_threads = DEFAULT_MIN_SPARE_THREAD;
 
472
    ap_max_spare_threads = DEFAULT_MAX_SPARE_THREAD;
 
473
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
 
474
        ap_max_mem_free = APR_ALLOCATOR_MAX_FREE_UNLIMITED;
 
475
#endif
 
476
 
 
477
    return OK;
 
478
}
 
479
 
 
480
 
 
481
 
 
482
static void mpmt_os2_hooks(apr_pool_t *p)
 
483
{
 
484
    ap_hook_pre_config(mpmt_os2_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
 
485
}
 
486
 
 
487
 
 
488
 
 
489
static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg)
 
490
{
 
491
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
492
 
 
493
    if (err != NULL) {
 
494
        return err;
 
495
    }
 
496
 
 
497
    ap_daemons_to_start = atoi(arg);
 
498
    return NULL;
 
499
}
 
500
 
 
501
 
 
502
 
 
503
static const char *set_min_spare_threads(cmd_parms *cmd, void *dummy,
 
504
                                         const char *arg)
 
505
{
 
506
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
507
 
 
508
    if (err != NULL) {
 
509
        return err;
 
510
    }
 
511
 
 
512
    ap_min_spare_threads = atoi(arg);
 
513
 
 
514
    if (ap_min_spare_threads <= 0) {
 
515
       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
 
516
                    "WARNING: detected MinSpareThreads set to non-positive.");
 
517
       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
 
518
                    "Resetting to 1 to avoid almost certain Apache failure.");
 
519
       ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL,
 
520
                    "Please read the documentation.");
 
521
       ap_min_spare_threads = 1;
 
522
    }
 
523
 
 
524
    return NULL;
 
525
}
 
526
 
 
527
 
 
528
 
 
529
static const char *set_max_spare_threads(cmd_parms *cmd, void *dummy,
 
530
                                         const char *arg)
 
531
{
 
532
    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
 
533
 
 
534
    if (err != NULL) {
 
535
        return err;
 
536
    }
 
537
 
 
538
    ap_max_spare_threads = atoi(arg);
 
539
    return NULL;
 
540
}
 
541
 
 
542
 
 
543
 
 
544
static const char *ignore_cmd(cmd_parms *cmd, void *dummy, const char *arg)
 
545
{
 
546
    return NULL;
 
547
}
 
548
 
 
549
 
 
550
 
 
551
static const command_rec mpmt_os2_cmds[] = {
 
552
LISTEN_COMMANDS,
 
553
AP_INIT_TAKE1( "StartServers", set_daemons_to_start, NULL, RSRC_CONF,
 
554
  "Number of child processes launched at server startup" ),
 
555
AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,
 
556
  "Minimum number of idle children, to handle request spikes"),
 
557
AP_INIT_TAKE1("MaxSpareThreads", set_max_spare_threads, NULL, RSRC_CONF,
 
558
  "Maximum number of idle children"),
 
559
AP_INIT_TAKE1("User", ignore_cmd, NULL, RSRC_CONF,
 
560
  "Not applicable on this platform"),
 
561
AP_INIT_TAKE1("Group", ignore_cmd, NULL, RSRC_CONF,
 
562
  "Not applicable on this platform"),
 
563
AP_INIT_TAKE1("ScoreBoardFile", ignore_cmd, NULL, RSRC_CONF, \
 
564
  "Not applicable on this platform"),
 
565
{ NULL }
 
566
};
 
567
 
 
568
module AP_MODULE_DECLARE_DATA mpm_mpmt_os2_module = {
 
569
    MPM20_MODULE_STUFF,
 
570
    NULL,            /* hook to run before apache parses args */
 
571
    NULL,            /* create per-directory config structure */
 
572
    NULL,            /* merge per-directory config structures */
 
573
    NULL,            /* create per-server config structure */
 
574
    NULL,            /* merge per-server config structures */
 
575
    mpmt_os2_cmds,   /* command apr_table_t */
 
576
    mpmt_os2_hooks,  /* register_hooks */
 
577
};