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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * httpd.c: simple http daemon for answering WWW file requests
21 * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3)
24 * changed server number for child-alone processes to 0 and changed name
28 * Added numerous speed hacks proposed by Robert S. Thau (rst@ai.mit.edu)
29 * including set group before fork, and call gettime before to fork
30 * to set up libraries.
33 * Brandon's code snarfed from NCSA 1.4, but tinkered to work with the
34 * Apache server, and also to have child processes do accept() directly.
37 * Extensive rework for Apache.
41 #include "apr_portable.h"
42 #include "apr_strings.h"
43 #include "apr_thread_proc.h"
44 #include "apr_signal.h"
45 #include "apr_tables.h"
46 #include "apr_getopt.h"
47 #include "apr_thread_mutex.h"
49 #define APR_WANT_STDIO
50 #define APR_WANT_STRFUNC
56 #if APR_HAVE_SYS_TYPES_H
57 #include <sys/types.h>
61 #include <sys/select.h>
64 #include "ap_config.h"
66 #include "mpm_default.h"
67 #include "http_main.h"
69 #include "http_config.h"
70 #include "http_core.h" /* for get_remote_host */
71 #include "http_connection.h"
72 #include "scoreboard.h"
74 #include "mpm_common.h"
75 #include "ap_listen.h"
85 #include <nks/netware.h>
89 /* Limit on the total --- clients will be locked out if more servers than
90 * this are needed. It is intended solely to keep the server from crashing
91 * when things get out of hand.
93 * We keep a hard maximum number of servers, for two reasons --- first off,
94 * in case something goes seriously wrong, we want to stop the fork bomb
95 * short of actually crashing the machine we're running on by filling some
96 * kernel table. Secondly, it keeps the size of the scoreboard file small
97 * enough that we can read the whole thing without worrying too much about
100 #ifndef HARD_SERVER_LIMIT
101 #define HARD_SERVER_LIMIT 1
104 #define WORKER_DEAD SERVER_DEAD
105 #define WORKER_STARTING SERVER_STARTING
106 #define WORKER_READY SERVER_READY
107 #define WORKER_IDLE_KILL SERVER_IDLE_KILL
111 int ap_threads_per_child
=0; /* Worker threads per child */
112 static int ap_threads_to_start
=0;
113 static int ap_threads_min_free
=0;
114 static int ap_threads_max_free
=0;
115 static int ap_threads_limit
=0;
116 static int mpm_state
= AP_MPMQ_STARTING
;
119 * The max child slot ever assigned, preserved across restarts. Necessary
120 * to deal with MaxClients changes across SIGWINCH restarts. We use this
121 * value to optimize routines that have to scan the entire scoreboard.
123 int ap_max_workers_limit
= -1;
124 server_rec
*ap_server_conf
;
126 /* *Non*-shared http_main globals... */
128 int hold_screen_on_exit
= 0; /* Indicates whether the screen should be held open */
130 static fd_set listenfds
;
131 static int listenmaxfd
;
133 static apr_pool_t
*pconf
; /* Pool for config stuff */
134 static apr_pool_t
*pmain
; /* Pool for httpd child stuff */
136 static pid_t ap_my_pid
; /* it seems silly to call getpid all the time */
137 static char *ap_my_addrspace
= NULL
;
139 static int die_now
= 0;
141 /* Keep track of the number of worker threads currently active */
142 static unsigned long worker_thread_count
;
143 static int request_count
;
145 /* Structure used to register/deregister a console handler with the OS */
146 static int InstallConsoleHandler(void);
147 static void RemoveConsoleHandler(void);
148 static int CommandLineInterpreter(scr_t screenID
, const char *commandLine
);
149 static CommandParser_t ConsoleHandler
= {0, NULL
, 0};
150 #define HANDLEDCOMMAND 0
151 #define NOTMYCOMMAND 1
153 static int show_settings
= 0;
158 #define DBPRINT0(s) printf(s)
159 #define DBPRINT1(s,v1) printf(s,v1)
160 #define DBPRINT2(s,v1,v2) printf(s,v1,v2)
163 #define DBPRINT1(s,v1)
164 #define DBPRINT2(s,v1,v2)
167 /* volatile just in case */
168 static int volatile shutdown_pending
;
169 static int volatile restart_pending
;
170 static int volatile is_graceful
;
171 static int volatile wait_to_finish
=1;
172 ap_generation_t
volatile ap_my_generation
=0;
174 /* a clean exit from a child with proper cleanup */
175 static void clean_child_exit(int code
, int worker_num
, apr_pool_t
*ptrans
,
176 apr_bucket_alloc_t
*bucket_alloc
) __attribute__ ((noreturn
));
177 static void clean_child_exit(int code
, int worker_num
, apr_pool_t
*ptrans
,
178 apr_bucket_alloc_t
*bucket_alloc
)
180 apr_bucket_alloc_destroy(bucket_alloc
);
181 if (!shutdown_pending
) {
182 apr_pool_destroy(ptrans
);
185 atomic_dec (&worker_thread_count
);
187 ap_update_child_status_from_indexes(0, worker_num
, WORKER_DEAD
,
188 (request_rec
*) NULL
);
189 NXThreadExit((void*)&code
);
192 /* proper cleanup when returning from ap_mpm_run() */
193 static void mpm_main_cleanup(void)
196 apr_pool_destroy(pmain
);
200 AP_DECLARE(apr_status_t
) ap_mpm_query(int query_code
, int *result
)
203 case AP_MPMQ_MAX_DAEMON_USED
:
206 case AP_MPMQ_IS_THREADED
:
207 *result
= AP_MPMQ_DYNAMIC
;
209 case AP_MPMQ_IS_FORKED
:
210 *result
= AP_MPMQ_NOT_SUPPORTED
;
212 case AP_MPMQ_HARD_LIMIT_DAEMONS
:
213 *result
= HARD_SERVER_LIMIT
;
215 case AP_MPMQ_HARD_LIMIT_THREADS
:
216 *result
= HARD_THREAD_LIMIT
;
218 case AP_MPMQ_MAX_THREADS
:
219 *result
= ap_threads_limit
;
221 case AP_MPMQ_MIN_SPARE_DAEMONS
:
224 case AP_MPMQ_MIN_SPARE_THREADS
:
225 *result
= ap_threads_min_free
;
227 case AP_MPMQ_MAX_SPARE_DAEMONS
:
230 case AP_MPMQ_MAX_SPARE_THREADS
:
231 *result
= ap_threads_max_free
;
233 case AP_MPMQ_MAX_REQUESTS_DAEMON
:
234 *result
= ap_max_requests_per_child
;
236 case AP_MPMQ_MAX_DAEMONS
:
239 case AP_MPMQ_MPM_STATE
:
247 /*****************************************************************
248 * Connection structures and accounting...
251 static void mpm_term(void)
253 RemoveConsoleHandler();
258 static void sig_term(int sig
)
260 if (shutdown_pending
== 1) {
261 /* Um, is this _probably_ not an error, if the user has
262 * tried to do a shutdown twice quickly, so we won't
263 * worry about reporting it.
267 shutdown_pending
= 1;
269 DBPRINT0 ("waiting for threads\n");
270 while (wait_to_finish
) {
273 DBPRINT0 ("goodbye\n");
276 /* restart() is the signal handler for SIGHUP and SIGWINCH
277 * in the parent process, unless running in ONE_PROCESS mode
279 static void restart(void)
281 if (restart_pending
== 1) {
282 /* Probably not an error - don't bother reporting it */
289 static void set_signals(void)
291 apr_signal(SIGTERM
, sig_term
);
292 apr_signal(SIGABRT
, sig_term
);
295 int nlmUnloadSignaled(int wait
)
297 shutdown_pending
= 1;
300 while (wait_to_finish
) {
308 /*****************************************************************
309 * Child process main loop.
310 * The following vars are static to avoid getting clobbered by longjmp();
311 * they are really private to child_main.
315 #define MAX_WB_RETRIES 3
317 static int would_block
= 0;
318 static int retry_success
= 0;
319 static int retry_fail
= 0;
320 static int avg_retries
= 0;
324 void worker_main(void *arg
)
326 ap_listen_rec
*lr
, *first_lr
, *last_lr
= NULL
;
329 apr_allocator_t
*allocator
;
330 apr_bucket_alloc_t
*bucket_alloc
;
331 conn_rec
*current_conn
;
332 apr_status_t stat
= APR_EINIT
;
335 int my_worker_num
= (int)arg
;
336 apr_socket_t
*csd
= NULL
;
337 int requests_this_child
= 0;
338 apr_socket_t
*sd
= NULL
;
344 int wouldblock_retry
;
349 apr_allocator_create(&allocator
);
350 apr_allocator_max_free_set(allocator
, ap_max_mem_free
);
352 apr_pool_create_ex(&ptrans
, pmain
, NULL
, allocator
);
353 apr_allocator_owner_set(allocator
, ptrans
);
354 apr_pool_tag(ptrans
, "transaction");
356 bucket_alloc
= apr_bucket_alloc_create_ex(allocator
);
358 atomic_inc (&worker_thread_count
);
362 * (Re)initialize this child to a pre-connection state.
365 apr_pool_clear(ptrans
);
367 if ((ap_max_requests_per_child
> 0
368 && requests_this_child
++ >= ap_max_requests_per_child
)) {
369 DBPRINT1 ("\n**Thread slot %d is shutting down", my_worker_num
);
370 clean_child_exit(0, my_worker_num
, ptrans
, bucket_alloc
);
373 ap_update_child_status_from_indexes(0, my_worker_num
, WORKER_READY
,
374 (request_rec
*) NULL
);
377 * Wait for an acceptable connection to arrive.
381 if (shutdown_pending
|| restart_pending
|| (ap_scoreboard_image
->servers
[0][my_worker_num
].status
== WORKER_IDLE_KILL
)) {
382 DBPRINT1 ("\nThread slot %d is shutting down\n", my_worker_num
);
383 clean_child_exit(0, my_worker_num
, ptrans
, bucket_alloc
);
386 /* Check the listen queue on all sockets for requests */
387 memcpy(&main_fds
, &listenfds
, sizeof(fd_set
));
388 srv
= select(listenmaxfd
+ 1, &main_fds
, NULL
, NULL
, &tv
);
392 ap_log_error(APLOG_MARK
, APLOG_NOTICE
, 0, ap_server_conf
,
393 "select() failed on listen socket");
399 /* remember the last_lr we searched last time around so that
400 we don't end up starving any particular listening socket */
401 if (last_lr
== NULL
) {
411 apr_os_sock_get(&sockdes
, lr
->sd
);
412 if (FD_ISSET(sockdes
, &main_fds
))
417 } while (lr
!= first_lr
);
418 /* if we get here, something unexpected happened. Go back
419 into the select state and try again.
426 wouldblock_retry
= MAX_WB_RETRIES
;
428 while (wouldblock_retry
) {
429 if ((stat
= apr_socket_accept(&csd
, sd
, ptrans
)) == APR_SUCCESS
) {
433 /* if the error is a wouldblock then maybe we were too
434 quick try to pull the next request from the listen
435 queue. Try a few more times then return to our idle
437 if (!APR_STATUS_IS_EAGAIN(stat
)) {
441 if (wouldblock_retry
--) {
447 /* If we got a new socket, set it to non-blocking mode and process
448 it. Otherwise handle the error. */
449 if (stat
== APR_SUCCESS
) {
450 apr_socket_opt_set(csd
, APR_SO_NONBLOCK
, 0);
452 if (wouldblock_retry
< MAX_WB_RETRIES
) {
454 avg_retries
+= (MAX_WB_RETRIES
-wouldblock_retry
);
457 break; /* We have a socket ready for reading */
461 if (APR_STATUS_IS_EAGAIN(stat
)) {
467 if (APR_STATUS_IS_EAGAIN(stat
) ||
469 APR_STATUS_IS_ECONNRESET(stat
) ||
470 APR_STATUS_IS_ETIMEDOUT(stat
) ||
471 APR_STATUS_IS_EHOSTUNREACH(stat
) ||
472 APR_STATUS_IS_ENETUNREACH(stat
)) {
476 else if (APR_STATUS_IS_ENETDOWN(stat
)) {
478 * When the network layer has been shut down, there
479 * is not much use in simply exiting: the parent
480 * would simply re-create us (and we'd fail again).
481 * Use the CHILDFATAL code to tear the server down.
482 * @@@ Martin's idea for possible improvement:
483 * A different approach would be to define
484 * a new APEXIT_NETDOWN exit code, the reception
485 * of which would make the parent shutdown all
486 * children, then idle-loop until it detected that
487 * the network is up again, and restart the children.
488 * Ben Hyde noted that temporary ENETDOWN situations
489 * occur in mobile IP.
491 ap_log_error(APLOG_MARK
, APLOG_EMERG
, stat
, ap_server_conf
,
492 "apr_socket_accept: giving up.");
493 clean_child_exit(APEXIT_CHILDFATAL
, my_worker_num
, ptrans
,
498 ap_log_error(APLOG_MARK
, APLOG_ERR
, stat
, ap_server_conf
,
499 "apr_socket_accept: (client socket)");
500 clean_child_exit(1, my_worker_num
, ptrans
, bucket_alloc
);
505 ap_create_sb_handle(&sbh
, ptrans
, 0, my_worker_num
);
507 * We now have a connection, so set it up with the appropriate
508 * socket options, file descriptors, and read/write buffers.
510 current_conn
= ap_run_create_connection(ptrans
, ap_server_conf
, csd
,
514 ap_process_connection(current_conn
, csd
);
515 ap_lingering_close(current_conn
);
519 clean_child_exit(0, my_worker_num
, ptrans
, bucket_alloc
);
523 static int make_child(server_rec
*s
, int slot
)
529 if (slot
+ 1 > ap_max_workers_limit
) {
530 ap_max_workers_limit
= slot
+ 1;
533 ap_update_child_status_from_indexes(0, slot
, WORKER_STARTING
,
534 (request_rec
*) NULL
);
536 if (ctx
= NXContextAlloc((void (*)(void *)) worker_main
, (void*)slot
, NX_PRIO_MED
, ap_thread_stacksize
, NX_CTX_NORMAL
, &err
)) {
539 sprintf (threadName
, "Apache_Worker %d", slot
);
540 NXContextSetName(ctx
, threadName
);
541 err
= NXThreadCreate(ctx
, NX_THR_BIND_CONTEXT
, &tid
);
548 /* create thread didn't succeed. Fix the scoreboard or else
549 * it will say SERVER_STARTING forever and ever
551 ap_update_child_status_from_indexes(0, slot
, WORKER_DEAD
,
552 (request_rec
*) NULL
);
554 /* In case system resources are maxxed out, we don't want
555 Apache running away with the CPU trying to fork over and
556 over and over again. */
562 ap_scoreboard_image
->servers
[0][slot
].tid
= tid
;
568 /* start up a bunch of worker threads */
569 static void startup_workers(int number_to_start
)
573 for (i
= 0; number_to_start
&& i
< ap_threads_limit
; ++i
) {
574 if (ap_scoreboard_image
->servers
[0][i
].status
!= WORKER_DEAD
) {
577 if (make_child(ap_server_conf
, i
) < 0) {
586 * idle_spawn_rate is the number of children that will be spawned on the
587 * next maintenance cycle if there aren't enough idle servers. It is
588 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
589 * without the need to spawn.
591 static int idle_spawn_rate
= 1;
592 #ifndef MAX_SPAWN_RATE
593 #define MAX_SPAWN_RATE (64)
595 static int hold_off_on_exponential_spawning
;
597 static void perform_idle_server_maintenance(apr_pool_t
*p
)
604 int free_slots
[MAX_SPAWN_RATE
];
608 /* initialize the free_list */
616 for (i
= 0; i
< ap_threads_limit
; ++i
) {
619 if (i
>= ap_max_workers_limit
&& free_length
== idle_spawn_rate
)
621 ws
= &ap_scoreboard_image
->servers
[0][i
];
623 if (status
== WORKER_DEAD
) {
624 /* try to keep children numbers as low as possible */
625 if (free_length
< idle_spawn_rate
) {
626 free_slots
[free_length
] = i
;
630 else if (status
== WORKER_IDLE_KILL
) {
631 /* If it is already marked to die, skip it */
635 /* We consider a starting server as idle because we started it
636 * at least a cycle ago, and if it still hasn't finished starting
637 * then we're just going to swamp things worse by forking more.
638 * So we hopefully won't need to fork more if we count it.
639 * This depends on the ordering of SERVER_READY and SERVER_STARTING.
641 if (status
<= WORKER_READY
) {
643 /* always kill the highest numbered child if we have to...
644 * no really well thought out reason ... other than observing
645 * the server behaviour under linux where lower numbered children
646 * tend to service more hits (and hence are more likely to have
647 * their data in cpu caches).
656 DBPRINT2("Total: %d Idle Count: %d \r", total_non_dead
, idle_count
);
657 ap_max_workers_limit
= last_non_dead
+ 1;
658 if (idle_count
> ap_threads_max_free
) {
659 /* kill off one child... we use the pod because that'll cause it to
660 * shut down gracefully, in case it happened to pick up a request
661 * while we were counting
664 ap_update_child_status_from_indexes(0, last_non_dead
, WORKER_IDLE_KILL
,
665 (request_rec
*) NULL
);
666 DBPRINT1("\nKilling idle thread: %d\n", last_non_dead
);
668 else if (idle_count
< ap_threads_min_free
) {
669 /* terminate the free list */
670 if (free_length
== 0) {
671 /* only report this condition once */
672 static int reported
= 0;
675 ap_log_error(APLOG_MARK
, APLOG_ERR
, 0, ap_server_conf
,
676 "server reached MaxClients setting, consider"
677 " raising the MaxClients setting");
683 if (idle_spawn_rate
>= 8) {
684 ap_log_error(APLOG_MARK
, APLOG_INFO
, 0, ap_server_conf
,
685 "server seems busy, (you may need "
686 "to increase StartServers, or Min/MaxSpareServers), "
687 "spawning %d children, there are %d idle, and "
688 "%d total children", idle_spawn_rate
,
689 idle_count
, total_non_dead
);
692 for (i
= 0; i
< free_length
; ++i
) {
693 DBPRINT1("Spawning additional thread slot: %d\n", free_slots
[i
]);
694 make_child(ap_server_conf
, free_slots
[i
]);
696 /* the next time around we want to spawn twice as many if this
697 * wasn't good enough, but not if we've just done a graceful
699 if (hold_off_on_exponential_spawning
) {
700 --hold_off_on_exponential_spawning
;
702 else if (idle_spawn_rate
< MAX_SPAWN_RATE
) {
703 idle_spawn_rate
*= 2;
712 static void display_settings ()
714 int status_array
[SERVER_NUM_STATUS
];
715 int i
, status
, total
=0;
716 int reqs
= request_count
;
718 int wblock
= would_block
;
725 ClearScreen (getscreenhandle());
726 printf("%s \n", ap_get_server_description());
728 for (i
=0;i
<SERVER_NUM_STATUS
;i
++) {
732 for (i
= 0; i
< ap_threads_limit
; ++i
) {
733 status
= (ap_scoreboard_image
->servers
[0][i
]).status
;
734 status_array
[status
]++;
737 for (i
=0;i
<SERVER_NUM_STATUS
;i
++) {
741 printf ("Available:\t%d\n", status_array
[i
]);
743 case SERVER_STARTING
:
744 printf ("Starting:\t%d\n", status_array
[i
]);
747 printf ("Ready:\t\t%d\n", status_array
[i
]);
749 case SERVER_BUSY_READ
:
750 printf ("Busy:\t\t%d\n", status_array
[i
]);
752 case SERVER_BUSY_WRITE
:
753 printf ("Busy Write:\t%d\n", status_array
[i
]);
755 case SERVER_BUSY_KEEPALIVE
:
756 printf ("Busy Keepalive:\t%d\n", status_array
[i
]);
758 case SERVER_BUSY_LOG
:
759 printf ("Busy Log:\t%d\n", status_array
[i
]);
761 case SERVER_BUSY_DNS
:
762 printf ("Busy DNS:\t%d\n", status_array
[i
]);
765 printf ("Closing:\t%d\n", status_array
[i
]);
767 case SERVER_GRACEFUL
:
768 printf ("Restart:\t%d\n", status_array
[i
]);
770 case SERVER_IDLE_KILL
:
771 printf ("Idle Kill:\t%d\n", status_array
[i
]);
774 printf ("Unknown Status:\t%d\n", status_array
[i
]);
777 if (i
!= SERVER_DEAD
)
778 total
+=status_array
[i
];
780 printf ("Total Running:\t%d\tout of: \t%d\n", total
, ap_threads_limit
);
781 printf ("Requests per interval:\t%d\n", reqs
);
784 printf ("Would blocks:\t%d\n", wblock
);
785 printf ("Successful retries:\t%d\n", retry_success
);
786 printf ("Failed retries:\t%d\n", retry_fail
);
787 printf ("Avg retries:\t%d\n", retry_success
== 0 ? 0 : avg_retries
/ retry_success
);
791 static void show_server_data()
796 printf("%s\n", ap_get_server_description());
797 if (ap_my_addrspace
&& (ap_my_addrspace
[0] != 'O') && (ap_my_addrspace
[1] != 'S'))
798 printf(" Running in address space %s\n", ap_my_addrspace
);
801 /* Display listening ports */
802 printf(" Listening on port(s):");
805 printf(" %d", lr
->bind_addr
->port
);
807 } while(lr
&& lr
!= ap_listeners
);
809 /* Display dynamic modules loaded */
811 for (m
= ap_loaded_modules
; *m
!= NULL
; m
++) {
812 if (((module
*)*m
)->dynamic_load_handle
) {
813 printf(" Loaded dynamic module %s\n", ((module
*)*m
)->name
);
819 static int setup_listeners(server_rec
*s
)
824 if (ap_setup_listeners(s
) < 1 ) {
825 ap_log_error(APLOG_MARK
, APLOG_ALERT
, 0, s
,
826 "no listening sockets available, shutting down");
832 for (lr
= ap_listeners
; lr
; lr
= lr
->next
) {
833 apr_os_sock_get(&sockdes
, lr
->sd
);
834 FD_SET(sockdes
, &listenfds
);
835 if (sockdes
> listenmaxfd
) {
836 listenmaxfd
= sockdes
;
842 static int shutdown_listeners()
846 for (lr
= ap_listeners
; lr
; lr
= lr
->next
) {
847 apr_socket_close(lr
->sd
);
853 /*****************************************************************
854 * Executive routines.
857 int ap_mpm_run(apr_pool_t
*_pconf
, apr_pool_t
*plog
, server_rec
*s
)
859 apr_status_t status
=0;
864 if (setup_listeners(s
)) {
865 ap_log_error(APLOG_MARK
, APLOG_ALERT
, status
, s
,
866 "no listening sockets available, shutting down");
870 restart_pending
= shutdown_pending
= 0;
871 worker_thread_count
= 0;
874 if (ap_run_pre_mpm(s
->process
->pool
, SB_NOT_SHARED
) != OK
) {
879 /* Only set slot 0 since that is all NetWare will ever have. */
880 ap_scoreboard_image
->parent
[0].pid
= getpid();
884 apr_pool_create(&pmain
, pconf
);
885 ap_run_child_init(pmain
, ap_server_conf
);
887 if (ap_threads_max_free
< ap_threads_min_free
+ 1) /* Don't thrash... */
888 ap_threads_max_free
= ap_threads_min_free
+ 1;
891 startup_workers(ap_threads_to_start
);
893 /* Allow the Apache screen to be closed normally on exit() only if it
894 has not been explicitly forced to close on exit(). (ie. the -E flag
895 was specified at startup) */
896 if (hold_screen_on_exit
> 0) {
897 hold_screen_on_exit
= 0;
900 ap_log_error(APLOG_MARK
, APLOG_NOTICE
, 0, ap_server_conf
,
901 "%s configured -- resuming normal operations",
902 ap_get_server_description());
903 ap_log_error(APLOG_MARK
, APLOG_INFO
, 0, ap_server_conf
,
904 "Server built: %s", ap_get_server_built());
905 #ifdef AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
906 ap_log_error(APLOG_MARK
, APLOG_DEBUG
, 0, ap_server_conf
,
907 "AcceptMutex: %s (default: %s)",
908 apr_proc_mutex_name(accept_mutex
),
909 apr_proc_mutex_defname());
913 mpm_state
= AP_MPMQ_RUNNING
;
914 while (!restart_pending
&& !shutdown_pending
) {
915 perform_idle_server_maintenance(pconf
);
919 apr_sleep(SCOREBOARD_MAINTENANCE_INTERVAL
);
921 mpm_state
= AP_MPMQ_STOPPING
;
924 /* Shutdown the listen sockets so that we don't get stuck in a blocking call.
925 shutdown_listeners();*/
927 if (shutdown_pending
) { /* Got an unload from the console */
928 ap_log_error(APLOG_MARK
, APLOG_NOTICE
, 0, ap_server_conf
,
929 "caught SIGTERM, shutting down");
931 while (worker_thread_count
> 0) {
932 printf ("\rShutdown pending. Waiting for %d thread(s) to terminate...",
933 worker_thread_count
);
940 else { /* the only other way out is a restart */
941 /* advance to the next generation */
942 /* XXX: we really need to make sure this new generation number isn't in
943 * use by any of the children.
946 ap_scoreboard_image
->global
->running_generation
= ap_my_generation
;
948 ap_log_error(APLOG_MARK
, APLOG_NOTICE
, 0, ap_server_conf
,
949 "Graceful restart requested, doing restart");
951 /* Wait for all of the threads to terminate before initiating the restart */
952 while (worker_thread_count
> 0) {
953 printf ("\rRestart pending. Waiting for %d thread(s) to terminate...",
954 worker_thread_count
);
957 printf ("\nRestarting...\n");
964 static int netware_pre_config(apr_pool_t
*p
, apr_pool_t
*plog
, apr_pool_t
*ptemp
)
967 char *addrname
= NULL
;
969 mpm_state
= AP_MPMQ_STARTING
;
971 debug
= ap_exists_config_define("DEBUG");
974 ap_my_pid
= getpid();
975 addrname
= getaddressspacename (NULL
, NULL
);
977 ap_my_addrspace
= apr_pstrdup (p
, addrname
);
982 /* The following call has been moved to the mod_nw_ssl pre-config handler */
983 ap_listen_pre_config();
986 ap_threads_to_start
= DEFAULT_START_THREADS
;
987 ap_threads_min_free
= DEFAULT_MIN_FREE_THREADS
;
988 ap_threads_max_free
= DEFAULT_MAX_FREE_THREADS
;
989 ap_threads_limit
= HARD_THREAD_LIMIT
;
990 ap_max_requests_per_child
= DEFAULT_MAX_REQUESTS_PER_CHILD
;
991 ap_extended_status
= 0;
992 ap_thread_stacksize
= DEFAULT_THREAD_STACKSIZE
;
993 #ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
994 ap_max_mem_free
= APR_ALLOCATOR_MAX_FREE_UNLIMITED
;
1000 static int netware_check_config(apr_pool_t
*p
, apr_pool_t
*plog
,
1001 apr_pool_t
*ptemp
, server_rec
*s
)
1003 static int restart_num
= 0;
1006 /* we want this only the first time around */
1007 if (restart_num
++ == 0) {
1011 if (ap_threads_limit
> HARD_THREAD_LIMIT
) {
1013 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1014 "WARNING: MaxThreads of %d exceeds compile-time "
1015 "limit of", ap_threads_limit
);
1016 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1017 " %d threads, decreasing to %d.",
1018 HARD_THREAD_LIMIT
, HARD_THREAD_LIMIT
);
1019 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1020 " To increase, please see the HARD_THREAD_LIMIT"
1022 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1023 " server/mpm/netware%s.", AP_MPM_HARD_LIMITS_FILE
);
1025 ap_log_error(APLOG_MARK
, APLOG_WARNING
, 0, s
,
1026 "MaxThreads of %d exceeds compile-time limit "
1027 "of %d, decreasing to match",
1028 ap_threads_limit
, HARD_THREAD_LIMIT
);
1030 ap_threads_limit
= HARD_THREAD_LIMIT
;
1032 else if (ap_threads_limit
< 1) {
1034 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1035 "WARNING: MaxThreads of %d not allowed, "
1036 "increasing to 1.", ap_threads_limit
);
1038 ap_log_error(APLOG_MARK
, APLOG_WARNING
, 0, s
,
1039 "MaxThreads of %d not allowed, increasing to 1",
1042 ap_threads_limit
= 1;
1045 /* ap_threads_to_start > ap_threads_limit effectively checked in
1046 * call to startup_workers(ap_threads_to_start) in ap_mpm_run()
1048 if (ap_threads_to_start
< 0) {
1050 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1051 "WARNING: StartThreads of %d not allowed, "
1052 "increasing to 1.", ap_threads_to_start
);
1054 ap_log_error(APLOG_MARK
, APLOG_WARNING
, 0, s
,
1055 "StartThreads of %d not allowed, increasing to 1",
1056 ap_threads_to_start
);
1058 ap_threads_to_start
= 1;
1061 if (ap_threads_min_free
< 1) {
1063 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1064 "WARNING: MinSpareThreads of %d not allowed, "
1065 "increasing to 1", ap_threads_min_free
);
1066 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1067 " to avoid almost certain server failure.");
1068 ap_log_error(APLOG_MARK
, APLOG_WARNING
| APLOG_STARTUP
, 0, NULL
,
1069 " Please read the documentation.");
1071 ap_log_error(APLOG_MARK
, APLOG_WARNING
, 0, s
,
1072 "MinSpareThreads of %d not allowed, increasing to 1",
1073 ap_threads_min_free
);
1075 ap_threads_min_free
= 1;
1078 /* ap_threads_max_free < ap_threads_min_free + 1 checked in ap_mpm_run() */
1083 static void netware_mpm_hooks(apr_pool_t
*p
)
1085 ap_hook_pre_config(netware_pre_config
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1086 ap_hook_check_config(netware_check_config
, NULL
, NULL
, APR_HOOK_MIDDLE
);
1089 void netware_rewrite_args(process_rec
*process
)
1091 char *def_server_root
;
1093 const char *opt_arg
;
1095 apr_array_header_t
*mpm_new_argv
;
1099 InstallConsoleHandler();
1101 /* Make sure to hold the Apache screen open if exit() is called */
1102 hold_screen_on_exit
= 1;
1104 /* Rewrite process->argv[];
1106 * add default -d serverroot from the path of this executable
1108 * The end result will look like:
1109 * The -d serverroot default from the running executable
1111 if (process
->argc
> 0) {
1112 char *s
= apr_pstrdup (process
->pconf
, process
->argv
[0]);
1114 int i
, len
= strlen(s
);
1116 for (i
=len
; i
; i
--) {
1117 if (s
[i
] == '\\' || s
[i
] == '/') {
1119 apr_filepath_merge(&def_server_root
, NULL
, s
,
1120 APR_FILEPATH_TRUENAME
, process
->pool
);
1124 /* Use process->pool so that the rewritten argv
1125 * lasts for the lifetime of the server process,
1126 * because pconf will be destroyed after the
1127 * initial pre-flight of the config parser.
1129 mpm_new_argv
= apr_array_make(process
->pool
, process
->argc
+ 2,
1130 sizeof(const char *));
1131 *(const char **)apr_array_push(mpm_new_argv
) = process
->argv
[0];
1132 *(const char **)apr_array_push(mpm_new_argv
) = "-d";
1133 *(const char **)apr_array_push(mpm_new_argv
) = def_server_root
;
1137 apr_getopt_init(&opt
, process
->pool
, process
->argc
, (char**) process
->argv
);
1138 while (apr_getopt(opt
, AP_SERVER_BASEARGS
"n:", optbuf
+ 1, &opt_arg
) == APR_SUCCESS
) {
1139 switch (optbuf
[1]) {
1142 renamescreen(opt_arg
);
1146 /* Don't need to hold the screen open if the output is going to a file */
1147 hold_screen_on_exit
= -1;
1149 *(const char **)apr_array_push(mpm_new_argv
) =
1150 apr_pstrdup(process
->pool
, optbuf
);
1153 *(const char **)apr_array_push(mpm_new_argv
) = opt_arg
;
1158 process
->argc
= mpm_new_argv
->nelts
;
1159 process
->argv
= (const char * const *) mpm_new_argv
->elts
;
1164 static int CommandLineInterpreter(scr_t screenID
, const char *commandLine
)
1166 char *szCommand
= "APACHE2 ";
1167 int iCommandLen
= 8;
1168 char szcommandLine
[256];
1170 screenID
= screenID
;
1173 if (commandLine
== NULL
)
1174 return NOTMYCOMMAND
;
1175 if (strlen(commandLine
) <= strlen(szCommand
))
1176 return NOTMYCOMMAND
;
1178 strncpy (szcommandLine
, commandLine
, sizeof(szcommandLine
)-1);
1180 /* All added commands begin with "APACHE2 " */
1182 if (!strnicmp(szCommand
, szcommandLine
, iCommandLen
)) {
1183 ActivateScreen (getscreenhandle());
1185 /* If an instance id was not given but the nlm is loaded in
1186 protected space, then the the command belongs to the
1187 OS address space instance to pass it on. */
1188 pID
= strstr (szcommandLine
, "-p");
1189 if ((pID
== NULL
) && nlmisloadedprotected())
1190 return NOTMYCOMMAND
;
1192 /* If we got an instance id but it doesn't match this
1193 instance of the nlm, pass it on. */
1196 while (*pID
&& (*pID
== ' '))
1199 if (pID
&& ap_my_addrspace
&& strnicmp(pID
, ap_my_addrspace
, strlen(ap_my_addrspace
)))
1200 return NOTMYCOMMAND
;
1202 /* If we have determined that this command belongs to this
1203 instance of the nlm, then handle it. */
1204 if (!strnicmp("RESTART",&szcommandLine
[iCommandLen
],3)) {
1205 printf("Restart Requested...\n");
1208 else if (!strnicmp("VERSION",&szcommandLine
[iCommandLen
],3)) {
1209 printf("Server version: %s\n", ap_get_server_description());
1210 printf("Server built: %s\n", ap_get_server_built());
1212 else if (!strnicmp("MODULES",&szcommandLine
[iCommandLen
],3)) {
1215 else if (!strnicmp("DIRECTIVES",&szcommandLine
[iCommandLen
],3)) {
1216 ap_show_directives();
1218 else if (!strnicmp("SHUTDOWN",&szcommandLine
[iCommandLen
],3)) {
1219 printf("Shutdown Requested...\n");
1220 shutdown_pending
= 1;
1222 else if (!strnicmp("SETTINGS",&szcommandLine
[iCommandLen
],3)) {
1223 if (show_settings
) {
1225 ClearScreen (getscreenhandle());
1235 if (strnicmp("HELP",&szcommandLine
[iCommandLen
],3))
1236 printf("Unknown APACHE2 command %s\n", &szcommandLine
[iCommandLen
]);
1237 printf("Usage: APACHE2 [command] [-p <instance ID>]\n");
1238 printf("Commands:\n");
1239 printf("\tDIRECTIVES - Show directives\n");
1240 printf("\tHELP - Display this help information\n");
1241 printf("\tMODULES - Show a list of the loaded modules\n");
1242 printf("\tRESTART - Reread the configuration file and restart Apache\n");
1243 printf("\tSETTINGS - Show current thread status\n");
1244 printf("\tSHUTDOWN - Shutdown Apache\n");
1245 printf("\tVERSION - Display the server version information\n");
1248 /* Tell NetWare we handled the command */
1249 return HANDLEDCOMMAND
;
1252 /* Tell NetWare that the command isn't mine */
1253 return NOTMYCOMMAND
;
1256 static int InstallConsoleHandler(void)
1258 /* Our command line handler interfaces the system operator
1261 NX_WRAP_INTERFACE(CommandLineInterpreter
, 2, (void*)&(ConsoleHandler
.parser
));
1263 ConsoleHandler
.rTag
= AllocateResourceTag(getnlmhandle(), "Command Line Processor",
1264 ConsoleCommandSignature
);
1265 if (!ConsoleHandler
.rTag
)
1267 printf("Error on allocate resource tag\n");
1271 RegisterConsoleCommand(&ConsoleHandler
);
1273 /* The Remove procedure unregisters the console handler */
1278 static void RemoveConsoleHandler(void)
1280 UnRegisterConsoleCommand(&ConsoleHandler
);
1281 NX_UNWRAP_INTERFACE(ConsoleHandler
.parser
);
1284 static const char *set_threads_to_start(cmd_parms
*cmd
, void *dummy
, const char *arg
)
1286 const char *err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
1291 ap_threads_to_start
= atoi(arg
);
1295 static const char *set_min_free_threads(cmd_parms
*cmd
, void *dummy
, const char *arg
)
1297 const char *err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
1302 ap_threads_min_free
= atoi(arg
);
1306 static const char *set_max_free_threads(cmd_parms
*cmd
, void *dummy
, const char *arg
)
1308 const char *err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
1313 ap_threads_max_free
= atoi(arg
);
1317 static const char *set_thread_limit (cmd_parms
*cmd
, void *dummy
, const char *arg
)
1319 const char *err
= ap_check_cmd_context(cmd
, GLOBAL_ONLY
);
1324 ap_threads_limit
= atoi(arg
);
1328 static const command_rec netware_mpm_cmds
[] = {
1330 AP_INIT_TAKE1("StartThreads", set_threads_to_start
, NULL
, RSRC_CONF
,
1331 "Number of worker threads launched at server startup"),
1332 AP_INIT_TAKE1("MinSpareThreads", set_min_free_threads
, NULL
, RSRC_CONF
,
1333 "Minimum number of idle threads, to handle request spikes"),
1334 AP_INIT_TAKE1("MaxSpareThreads", set_max_free_threads
, NULL
, RSRC_CONF
,
1335 "Maximum number of idle threads"),
1336 AP_INIT_TAKE1("MaxThreads", set_thread_limit
, NULL
, RSRC_CONF
,
1337 "Maximum number of worker threads alive at the same time"),
1341 module AP_MODULE_DECLARE_DATA mpm_netware_module
= {
1343 netware_rewrite_args
, /* hook to run before apache parses args */
1344 NULL
, /* create per-directory config structure */
1345 NULL
, /* merge per-directory config structures */
1346 NULL
, /* create per-server config structure */
1347 NULL
, /* merge per-server config structures */
1348 netware_mpm_cmds
, /* command apr_table_t */
1349 netware_mpm_hooks
, /* register hooks */