Apache HTTPD
mpm_netware.c
Go to the documentation of this file.
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/*
18 * httpd.c: simple http daemon for answering WWW file requests
19 *
20 *
21 * 03-21-93 Rob McCool wrote original code (up to NCSA HTTPd 1.3)
22 *
23 * 03-06-95 blong
24 * changed server number for child-alone processes to 0 and changed name
25 * of processes
26 *
27 * 03-10-95 blong
28 * Added numerous speed hacks proposed by Robert S. Thau ([email protected])
29 * including set group before fork, and call gettime before to fork
30 * to set up libraries.
31 *
32 * 04-14-95 rst / rh
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.
35 *
36 * April-July '95 rst
37 * Extensive rework for Apache.
38 */
39
40#include "apr.h"
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"
48
49#define APR_WANT_STDIO
50#define APR_WANT_STRFUNC
51#include "apr_want.h"
52
53#if APR_HAVE_UNISTD_H
54#include <unistd.h>
55#endif
56#if APR_HAVE_SYS_TYPES_H
57#include <sys/types.h>
58#endif
59
60#ifndef USE_WINSOCK
61#include <sys/select.h>
62#endif
63
64#include "ap_config.h"
65#include "httpd.h"
66#include "mpm_default.h"
67#include "http_main.h"
68#include "http_log.h"
69#include "http_config.h"
70#include "http_core.h" /* for get_remote_host */
71#include "http_connection.h"
72#include "scoreboard.h"
73#include "ap_mpm.h"
74#include "mpm_common.h"
75#include "ap_listen.h"
76#include "ap_mmn.h"
77
78#ifdef HAVE_TIME_H
79#include <time.h>
80#endif
81
82#include <signal.h>
83
84#include <netware.h>
85#include <nks/netware.h>
86#include <library.h>
87#include <screen.h>
88
89int nlmUnloadSignaled(int wait);
90
91/* Limit on the total --- clients will be locked out if more servers than
92 * this are needed. It is intended solely to keep the server from crashing
93 * when things get out of hand.
94 *
95 * We keep a hard maximum number of servers, for two reasons --- first off,
96 * in case something goes seriously wrong, we want to stop the fork bomb
97 * short of actually crashing the machine we're running on by filling some
98 * kernel table. Secondly, it keeps the size of the scoreboard file small
99 * enough that we can read the whole thing without worrying too much about
100 * the overhead.
101 */
102#ifndef HARD_SERVER_LIMIT
103#define HARD_SERVER_LIMIT 1
104#endif
105
106#define WORKER_DEAD SERVER_DEAD
107#define WORKER_STARTING SERVER_STARTING
108#define WORKER_READY SERVER_READY
109#define WORKER_IDLE_KILL SERVER_IDLE_KILL
110
111#define MPM_HARD_LIMITS_FILE "/mpm_default.h"
112
113/* *Non*-shared http_main globals... */
114
115static int ap_threads_per_child=0; /* Worker threads per child */
119static int ap_threads_limit=0;
121
122/*
123 * The max child slot ever assigned, preserved across restarts. Necessary
124 * to deal with MaxRequestWorkers changes across SIGWINCH restarts. We use this
125 * value to optimize routines that have to scan the entire scoreboard.
126 */
127static int ap_max_workers_limit = -1;
128
129int hold_screen_on_exit = 0; /* Indicates whether the screen should be held open */
130
132static int listenmaxfd;
133
134static apr_pool_t *pconf; /* Pool for config stuff */
135static apr_pool_t *pmain; /* Pool for httpd child stuff */
136
137static pid_t ap_my_pid; /* it seems silly to call getpid all the time */
138static char *ap_my_addrspace = NULL;
139
140static int die_now = 0;
141
142/* Keep track of the number of worker threads currently active */
143static unsigned long worker_thread_count;
144static int request_count;
145
146/* Structure used to register/deregister a console handler with the OS */
147static int InstallConsoleHandler(void);
148static void RemoveConsoleHandler(void);
149static int CommandLineInterpreter(scr_t screenID, const char *commandLine);
151#define HANDLEDCOMMAND 0
152#define NOTMYCOMMAND 1
153
154static int show_settings = 0;
155
156//#define DBINFO_ON
157//#define DBPRINT_ON
158#ifdef DBPRINT_ON
159#define DBPRINT0(s) printf(s)
160#define DBPRINT1(s,v1) printf(s,v1)
161#define DBPRINT2(s,v1,v2) printf(s,v1,v2)
162#else
163#define DBPRINT0(s)
164#define DBPRINT1(s,v1)
165#define DBPRINT2(s,v1,v2)
166#endif
167
168/* volatile just in case */
169static int volatile shutdown_pending;
170static int volatile restart_pending;
171static int volatile is_graceful;
172static int volatile wait_to_finish=1;
174
175/* a clean exit from a child with proper cleanup */
176static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans,
177 apr_bucket_alloc_t *bucket_alloc) __attribute__ ((noreturn));
179 apr_bucket_alloc_t *bucket_alloc)
180{
181 apr_bucket_alloc_destroy(bucket_alloc);
182 if (!shutdown_pending) {
184 }
185
187 if (worker_num >=0)
189 (request_rec *) NULL);
190 NXThreadExit((void*)&code);
191}
192
193/* proper cleanup when returning from ap_mpm_run() */
194static void mpm_main_cleanup(void)
195{
196 if (pmain) {
198 }
199}
200
201static int netware_query(int query_code, int *result, apr_status_t *rv)
202{
203 *rv = APR_SUCCESS;
204 switch(query_code){
206 *result = 1;
207 break;
210 break;
213 break;
216 break;
219 break;
222 break;
224 *result = 0;
225 break;
228 break;
230 *result = 0;
231 break;
234 break;
237 break;
239 *result = 1;
240 break;
242 *result = mpm_state;
243 break;
246 break;
247 default:
248 *rv = APR_ENOTIMPL;
249 break;
250 }
251 return OK;
252}
253
254static const char *netware_get_name(void)
255{
256 return "NetWare";
257}
258
259/*****************************************************************
260 * Connection structures and accounting...
261 */
262
263static void mpm_term(void)
264{
266 wait_to_finish = 0;
268}
269
270static void sig_term(int sig)
271{
272 if (shutdown_pending == 1) {
273 /* Um, is this _probably_ not an error, if the user has
274 * tried to do a shutdown twice quickly, so we won't
275 * worry about reporting it.
276 */
277 return;
278 }
280
281 DBPRINT0 ("waiting for threads\n");
282 while (wait_to_finish) {
284 }
285 DBPRINT0 ("goodbye\n");
286}
287
288/* restart() is the signal handler for SIGHUP and SIGWINCH
289 * in the parent process, unless running in ONE_PROCESS mode
290 */
291static void restart(void)
292{
293 if (restart_pending == 1) {
294 /* Probably not an error - don't bother reporting it */
295 return;
296 }
297 restart_pending = 1;
298 is_graceful = 1;
299}
300
301static void set_signals(void)
302{
305}
306
308{
310
311 if (wait) {
312 while (wait_to_finish) {
314 }
315 }
316
317 return 0;
318}
319
320/*****************************************************************
321 * Child process main loop.
322 * The following vars are static to avoid getting clobbered by longjmp();
323 * they are really private to child_main.
324 */
325
326
327#define MAX_WB_RETRIES 3
328#ifdef DBINFO_ON
329static int would_block = 0;
330static int retry_success = 0;
331static int retry_fail = 0;
332static int avg_retries = 0;
333#endif
334
335/*static */
336void worker_main(void *arg)
337{
341 apr_bucket_alloc_t *bucket_alloc;
344 ap_sb_handle_t *sbh;
347
348 int my_worker_num = (int)arg;
350 int requests_this_child = 0;
351 apr_socket_t *sd = NULL;
353
354 int sockdes;
355 int srv;
356 struct timeval tv;
358
361
362 tv.tv_sec = 1;
363 tv.tv_usec = 0;
364
367
370 apr_pool_tag(ptrans, "transaction");
371
373
375
376 while (!die_now) {
377 /*
378 * (Re)initialize this child to a pre-connection state.
379 */
382
385 DBPRINT1 ("\n**Thread slot %d is shutting down", my_worker_num);
386 clean_child_exit(0, my_worker_num, ptrans, bucket_alloc);
387 }
388
390 (request_rec *) NULL);
391
392 /*
393 * Wait for an acceptable connection to arrive.
394 */
395
396 for (;;) {
398 DBPRINT1 ("\nThread slot %d is shutting down\n", my_worker_num);
399 clean_child_exit(0, my_worker_num, ptrans, bucket_alloc);
400 }
401
402 /* Check the listen queue on all sockets for requests */
403 memcpy(&main_fds, &listenfds, sizeof(fd_set));
405
406 if (srv <= 0) {
407 if (srv < 0) {
409 "select() failed on listen socket");
411 }
412 continue;
413 }
414
415 /* remember the last_lr we searched last time around so that
416 we don't end up starving any particular listening socket */
417 if (last_lr == NULL) {
419 }
420 else {
421 lr = last_lr->next;
422 if (!lr)
424 }
425 first_lr = lr;
426 do {
429 goto got_listener;
430 lr = lr->next;
431 if (!lr)
433 } while (lr != first_lr);
434 /* if we get here, something unexpected happened. Go back
435 into the select state and try again.
436 */
437 continue;
439 last_lr = lr;
440 sd = lr->sd;
441
443
444 while (wouldblock_retry) {
445 if ((stat = apr_socket_accept(&csd, sd, ptrans)) == APR_SUCCESS) {
446 break;
447 }
448 else {
449 /* if the error is a wouldblock then maybe we were too
450 quick try to pull the next request from the listen
451 queue. Try a few more times then return to our idle
452 listen state. */
454 break;
455 }
456
457 if (wouldblock_retry--) {
459 }
460 }
461 }
462
463 /* If we got a new socket, set it to non-blocking mode and process
464 it. Otherwise handle the error. */
465 if (stat == APR_SUCCESS) {
467#ifdef DBINFO_ON
471 }
472#endif
473 break; /* We have a socket ready for reading */
474 }
475 else {
476#ifdef DBINFO_ON
478 would_block++;
479 retry_fail++;
480 }
481 else if (
482#else
484#endif
489 ;
490 }
491#ifdef USE_WINSOCK
492 else if (APR_STATUS_IS_ENETDOWN(stat)) {
493 /*
494 * When the network layer has been shut down, there
495 * is not much use in simply exiting: the parent
496 * would simply re-create us (and we'd fail again).
497 * Use the CHILDFATAL code to tear the server down.
498 * @@@ Martin's idea for possible improvement:
499 * A different approach would be to define
500 * a new APEXIT_NETDOWN exit code, the reception
501 * of which would make the parent shutdown all
502 * children, then idle-loop until it detected that
503 * the network is up again, and restart the children.
504 * Ben Hyde noted that temporary ENETDOWN situations
505 * occur in mobile IP.
506 */
508 "apr_socket_accept: giving up.");
510 bucket_alloc);
511 }
512#endif
513 else {
515 "apr_socket_accept: (client socket)");
516 clean_child_exit(1, my_worker_num, ptrans, bucket_alloc);
517 }
518 }
519 }
520
522 /*
523 * We now have a connection, so set it up with the appropriate
524 * socket options, file descriptors, and read/write buffers.
525 */
527 my_worker_num, sbh,
528 bucket_alloc);
529 if (current_conn) {
530 current_conn->current_thread = thd;
533 }
535 }
536 clean_child_exit(0, my_worker_num, ptrans, bucket_alloc);
537}
538
539
540static int make_child(server_rec *s, int slot)
541{
542 int tid;
543 int err=0;
545
546 if (slot + 1 > ap_max_workers_limit) {
548 }
549
551 (request_rec *) NULL);
552
553 if (ctx = NXContextAlloc((void (*)(void *)) worker_main, (void*)slot, NX_PRIO_MED, ap_thread_stacksize, NX_CTX_NORMAL, &err)) {
554 char threadName[32];
555
556 sprintf (threadName, "Apache_Worker %d", slot);
559 if (err) {
561 }
562 }
563
564 if (err) {
565 /* create thread didn't succeed. Fix the scoreboard or else
566 * it will say SERVER_STARTING forever and ever
567 */
569 (request_rec *) NULL);
570
571 /* In case system resources are maxxed out, we don't want
572 Apache running away with the CPU trying to fork over and
573 over and over again. */
575
576 return -1;
577 }
578
579 ap_scoreboard_image->servers[0][slot].tid = tid;
580
581 return 0;
582}
583
584
585/* start up a bunch of worker threads */
587{
588 int i;
589
590 for (i = 0; number_to_start && i < ap_threads_limit; ++i) {
592 continue;
593 }
594 if (make_child(ap_server_conf, i) < 0) {
595 break;
596 }
598 }
599}
600
601
602/*
603 * idle_spawn_rate is the number of children that will be spawned on the
604 * next maintenance cycle if there aren't enough idle servers. It is
605 * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by
606 * without the need to spawn.
607 */
608static int idle_spawn_rate = 1;
609#ifndef MAX_SPAWN_RATE
610#define MAX_SPAWN_RATE (64)
611#endif
613
615{
616 int i;
617 int idle_count;
619 int free_length;
621 int last_non_dead;
622 int total_non_dead;
623
624 /* initialize the free_list */
625 free_length = 0;
626
627 idle_count = 0;
628 last_non_dead = -1;
629 total_non_dead = 0;
630
631 for (i = 0; i < ap_threads_limit; ++i) {
632 int status;
633
635 break;
637 status = ws->status;
638 if (status == WORKER_DEAD) {
639 /* try to keep children numbers as low as possible */
642 ++free_length;
643 }
644 }
645 else if (status == WORKER_IDLE_KILL) {
646 /* If it is already marked to die, skip it */
647 continue;
648 }
649 else {
650 /* We consider a starting server as idle because we started it
651 * at least a cycle ago, and if it still hasn't finished starting
652 * then we're just going to swamp things worse by forking more.
653 * So we hopefully won't need to fork more if we count it.
654 * This depends on the ordering of SERVER_READY and SERVER_STARTING.
655 */
656 if (status <= WORKER_READY) {
657 ++ idle_count;
658 }
659
662 }
663 }
664 DBPRINT2("Total: %d Idle Count: %d \r", total_non_dead, idle_count);
667 /* kill off one child... we use the pod because that'll cause it to
668 * shut down gracefully, in case it happened to pick up a request
669 * while we were counting
670 */
671 idle_spawn_rate = 1;
673 (request_rec *) NULL);
674 DBPRINT1("\nKilling idle thread: %d\n", last_non_dead);
675 }
676 else if (idle_count < ap_threads_min_free) {
677 /* terminate the free list */
678 if (free_length == 0) {
679 /* only report this condition once */
680 static int reported = 0;
681
682 if (!reported) {
684 "server reached MaxRequestWorkers setting, consider"
685 " raising the MaxRequestWorkers setting");
686 reported = 1;
687 }
688 idle_spawn_rate = 1;
689 }
690 else {
691 if (idle_spawn_rate >= 8) {
693 "server seems busy, (you may need "
694 "to increase StartServers, or Min/MaxSpareServers), "
695 "spawning %d children, there are %d idle, and "
696 "%d total children", idle_spawn_rate,
698 }
699 DBPRINT0("\n");
700 for (i = 0; i < free_length; ++i) {
701 DBPRINT1("Spawning additional thread slot: %d\n", free_slots[i]);
703 }
704 /* the next time around we want to spawn twice as many if this
705 * wasn't good enough, but not if we've just done a graceful
706 */
709 }
710 else if (idle_spawn_rate < MAX_SPAWN_RATE) {
711 idle_spawn_rate *= 2;
712 }
713 }
714 }
715 else {
716 idle_spawn_rate = 1;
717 }
718}
719
720static void display_settings()
721{
723 int i, status, total=0;
724 int reqs = request_count;
725#ifdef DBINFO_ON
726 int wblock = would_block;
727
728 would_block = 0;
729#endif
730
731 request_count = 0;
732
735
736 for (i=0;i<SERVER_NUM_STATUS;i++) {
737 status_array[i] = 0;
738 }
739
740 for (i = 0; i < ap_threads_limit; ++i) {
743 }
744
745 for (i=0;i<SERVER_NUM_STATUS;i++) {
746 switch(i)
747 {
748 case SERVER_DEAD:
749 printf ("Available:\t%d\n", status_array[i]);
750 break;
751 case SERVER_STARTING:
752 printf ("Starting:\t%d\n", status_array[i]);
753 break;
754 case SERVER_READY:
755 printf ("Ready:\t\t%d\n", status_array[i]);
756 break;
757 case SERVER_BUSY_READ:
758 printf ("Busy:\t\t%d\n", status_array[i]);
759 break;
761 printf ("Busy Write:\t%d\n", status_array[i]);
762 break;
764 printf ("Busy Keepalive:\t%d\n", status_array[i]);
765 break;
766 case SERVER_BUSY_LOG:
767 printf ("Busy Log:\t%d\n", status_array[i]);
768 break;
769 case SERVER_BUSY_DNS:
770 printf ("Busy DNS:\t%d\n", status_array[i]);
771 break;
772 case SERVER_CLOSING:
773 printf ("Closing:\t%d\n", status_array[i]);
774 break;
775 case SERVER_GRACEFUL:
776 printf ("Restart:\t%d\n", status_array[i]);
777 break;
778 case SERVER_IDLE_KILL:
779 printf ("Idle Kill:\t%d\n", status_array[i]);
780 break;
781 default:
782 printf ("Unknown Status:\t%d\n", status_array[i]);
783 break;
784 }
785 if (i != SERVER_DEAD)
786 total+=status_array[i];
787 }
788 printf ("Total Running:\t%d\tout of: \t%d\n", total, ap_threads_limit);
789 printf ("Requests per interval:\t%d\n", reqs);
790
791#ifdef DBINFO_ON
792 printf ("Would blocks:\t%d\n", wblock);
793 printf ("Successful retries:\t%d\n", retry_success);
794 printf ("Failed retries:\t%d\n", retry_fail);
795 printf ("Avg retries:\t%d\n", retry_success == 0 ? 0 : avg_retries / retry_success);
796#endif
797}
798
799static void show_server_data()
800{
802 module **m;
803
805 if (ap_my_addrspace && (ap_my_addrspace[0] != 'O') && (ap_my_addrspace[1] != 'S'))
806 printf(" Running in address space %s\n", ap_my_addrspace);
807
808
809 /* Display listening ports */
810 printf(" Listening on port(s):");
812 do {
813 printf(" %d", lr->bind_addr->port);
814 lr = lr->next;
815 } while (lr && lr != ap_listeners);
816
817 /* Display dynamic modules loaded */
818 printf("\n");
819 for (m = ap_loaded_modules; *m != NULL; m++) {
820 if (((module*)*m)->dynamic_load_handle) {
821 printf(" Loaded dynamic module %s\n", ((module*)*m)->name);
822 }
823 }
824}
825
826
828{
830 int sockdes;
831
832 if (ap_setup_listeners(s) < 1 ) {
834 "no listening sockets available, shutting down");
835 return -1;
836 }
837
838 listenmaxfd = -1;
840 for (lr = ap_listeners; lr; lr = lr->next) {
843 if (sockdes > listenmaxfd) {
845 }
846 }
847 return 0;
848}
849
851{
853
854 for (lr = ap_listeners; lr; lr = lr->next) {
855 apr_socket_close(lr->sd);
856 }
858 return 0;
859}
860
861/*****************************************************************
862 * Executive routines.
863 */
864
866{
868
869 pconf = _pconf;
871
872 if (setup_listeners(s)) {
874 "no listening sockets available, shutting down");
875 return !OK;
876 }
877
880
881 if (!is_graceful) {
882 if (ap_run_pre_mpm(s->process->pool, SB_NOT_SHARED) != OK) {
883 return !OK;
884 }
885 }
886
887 /* Only set slot 0 since that is all NetWare will ever have. */
893 0,
895
896 set_signals();
897
899 apr_pool_tag(pmain, "pmain");
901
902 if (ap_threads_max_free < ap_threads_min_free + 1) /* Don't thrash... */
904 request_count = 0;
905
907
908 /* Allow the Apache screen to be closed normally on exit() only if it
909 has not been explicitly forced to close on exit(). (ie. the -E flag
910 was specified at startup) */
911 if (hold_screen_on_exit > 0) {
913 }
914
916 "%s configured -- resuming normal operations",
919 "Server built: %s", ap_get_server_built());
923
925 while (!restart_pending && !shutdown_pending) {
927 if (show_settings)
931 }
933
937 0,
939
940 /* Shutdown the listen sockets so that we don't get stuck in a blocking call.
941 shutdown_listeners();*/
942
943 if (shutdown_pending) { /* Got an unload from the console */
945 "caught SIGTERM, shutting down");
946
947 while (worker_thread_count > 0) {
948 printf ("\rShutdown pending. Waiting for %lu thread(s) to terminate...",
951 }
952
954 return DONE;
955 }
956 else { /* the only other way out is a restart */
957 /* advance to the next generation */
958 /* XXX: we really need to make sure this new generation number isn't in
959 * use by any of the children.
960 */
963
965 "Graceful restart requested, doing restart");
966
967 /* Wait for all of the threads to terminate before initiating the restart */
968 while (worker_thread_count > 0) {
969 printf ("\rRestart pending. Waiting for %lu thread(s) to terminate...",
972 }
973 printf ("\nRestarting...\n");
974 }
975
977 return OK;
978}
979
981{
982 char *addrname = NULL;
983
985
986 is_graceful = 0;
987 ap_my_pid = getpid();
989 if (addrname) {
991 free (addrname);
992 }
993
994#ifndef USE_WINSOCK
995 /* The following call has been moved to the mod_nw_ssl pre-config handler */
997#endif
998
1004
1005 /* override core's default thread stacksize */
1007
1008 return OK;
1009}
1010
1012 apr_pool_t *ptemp, server_rec *s)
1013{
1014 static int restart_num = 0;
1015 int startup = 0;
1016
1017 /* we want this only the first time around */
1018 if (restart_num++ == 0) {
1019 startup = 1;
1020 }
1021
1023 if (startup) {
1025 "WARNING: MaxThreads of %d exceeds compile-time "
1026 "limit of %d threads, decreasing to %d. "
1027 "To increase, please see the HARD_THREAD_LIMIT "
1028 "define in server/mpm/netware%s.",
1031 } else {
1033 "MaxThreads of %d exceeds compile-time limit "
1034 "of %d, decreasing to match",
1036 }
1038 }
1039 else if (ap_threads_limit < 1) {
1040 if (startup) {
1042 "WARNING: MaxThreads of %d not allowed, "
1043 "increasing to 1.", ap_threads_limit);
1044 } else {
1046 "MaxThreads of %d not allowed, increasing to 1",
1048 }
1049 ap_threads_limit = 1;
1050 }
1051
1052 /* ap_threads_to_start > ap_threads_limit effectively checked in
1053 * call to startup_workers(ap_threads_to_start) in ap_mpm_run()
1054 */
1055 if (ap_threads_to_start < 0) {
1056 if (startup) {
1058 "WARNING: StartThreads of %d not allowed, "
1059 "increasing to 1.", ap_threads_to_start);
1060 } else {
1062 "StartThreads of %d not allowed, increasing to 1",
1064 }
1066 }
1067
1068 if (ap_threads_min_free < 1) {
1069 if (startup) {
1071 "WARNING: MinSpareThreads of %d not allowed, "
1072 "increasing to 1 to avoid almost certain server failure. "
1073 "Please read the documentation.", ap_threads_min_free);
1074 } else {
1076 "MinSpareThreads of %d not allowed, increasing to 1",
1078 }
1080 }
1081
1082 /* ap_threads_max_free < ap_threads_min_free + 1 checked in ap_mpm_run() */
1083
1084 return OK;
1085}
1086
1088{
1089 /* Run the pre-config hook after core's so that it can override the
1090 * default setting of ThreadStackSize for NetWare.
1091 */
1092 static const char * const predecessors[] = {"core.c", NULL};
1093
1096 //ap_hook_post_config(netware_post_config, NULL, NULL, 0);
1097 //ap_hook_child_init(netware_child_init, NULL, NULL, APR_HOOK_MIDDLE);
1098 //ap_hook_open_logs(netware_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST);
1102}
1103
1105{
1106 char *def_server_root;
1107 char optbuf[3];
1108 const char *opt_arg;
1111
1112
1113 atexit (mpm_term);
1115
1116 /* Make sure to hold the Apache screen open if exit() is called */
1118
1119 /* Rewrite process->argv[];
1120 *
1121 * add default -d serverroot from the path of this executable
1122 *
1123 * The end result will look like:
1124 * The -d serverroot default from the running executable
1125 */
1126 if (process->argc > 0) {
1127 char *s = apr_pstrdup (process->pconf, process->argv[0]);
1128 if (s) {
1129 int i, len = strlen(s);
1130
1131 for (i=len; i; i--) {
1132 if (s[i] == '\\' || s[i] == '/') {
1133 s[i] = '\0';
1135 APR_FILEPATH_TRUENAME, process->pool);
1136 break;
1137 }
1138 }
1139 /* Use process->pool so that the rewritten argv
1140 * lasts for the lifetime of the server process,
1141 * because pconf will be destroyed after the
1142 * initial pre-flight of the config parser.
1143 */
1144 mpm_new_argv = apr_array_make(process->pool, process->argc + 2,
1145 sizeof(const char *));
1146 *(const char **)apr_array_push(mpm_new_argv) = process->argv[0];
1147 *(const char **)apr_array_push(mpm_new_argv) = "-d";
1148 *(const char **)apr_array_push(mpm_new_argv) = def_server_root;
1149
1150 optbuf[0] = '-';
1151 optbuf[2] = '\0';
1152 apr_getopt_init(&opt, process->pool, process->argc, process->argv);
1153 while (apr_getopt(opt, AP_SERVER_BASEARGS"n:", optbuf + 1, &opt_arg) == APR_SUCCESS) {
1154 switch (optbuf[1]) {
1155 case 'n':
1156 if (opt_arg) {
1158 }
1159 break;
1160 case 'E':
1161 /* Don't need to hold the screen open if the output is going to a file */
1163 default:
1164 *(const char **)apr_array_push(mpm_new_argv) =
1165 apr_pstrdup(process->pool, optbuf);
1166
1167 if (opt_arg) {
1168 *(const char **)apr_array_push(mpm_new_argv) = opt_arg;
1169 }
1170 break;
1171 }
1172 }
1173 process->argc = mpm_new_argv->nelts;
1174 process->argv = (const char * const *) mpm_new_argv->elts;
1175 }
1176 }
1177}
1178
1180{
1181 char *szCommand = "APACHE2 ";
1182 int iCommandLen = 8;
1183 char szcommandLine[256];
1184 char *pID;
1186
1187
1188 if (commandLine == NULL)
1189 return NOTMYCOMMAND;
1190 if (strlen(commandLine) <= strlen(szCommand))
1191 return NOTMYCOMMAND;
1192
1194
1195 /* All added commands begin with "APACHE2 " */
1196
1199
1200 /* If an instance id was not given but the nlm is loaded in
1201 protected space, then the command belongs to the
1202 OS address space instance to pass it on. */
1203 pID = strstr (szcommandLine, "-p");
1204 if ((pID == NULL) && nlmisloadedprotected())
1205 return NOTMYCOMMAND;
1206
1207 /* If we got an instance id but it doesn't match this
1208 instance of the nlm, pass it on. */
1209 if (pID) {
1210 pID = &pID[2];
1211 while (*pID && (*pID == ' '))
1212 pID++;
1213 }
1215 return NOTMYCOMMAND;
1216
1217 /* If we have determined that this command belongs to this
1218 instance of the nlm, then handle it. */
1219 if (!strnicmp("RESTART",&szcommandLine[iCommandLen],3)) {
1220 printf("Restart Requested...\n");
1221 restart();
1222 }
1223 else if (!strnicmp("VERSION",&szcommandLine[iCommandLen],3)) {
1224 printf("Server version: %s\n", ap_get_server_description());
1225 printf("Server built: %s\n", ap_get_server_built());
1226 }
1227 else if (!strnicmp("MODULES",&szcommandLine[iCommandLen],3)) {
1229 }
1230 else if (!strnicmp("DIRECTIVES",&szcommandLine[iCommandLen],3)) {
1232 }
1233 else if (!strnicmp("SHUTDOWN",&szcommandLine[iCommandLen],3)) {
1234 printf("Shutdown Requested...\n");
1235 shutdown_pending = 1;
1236 }
1237 else if (!strnicmp("SETTINGS",&szcommandLine[iCommandLen],3)) {
1238 if (show_settings) {
1239 show_settings = 0;
1242 }
1243 else {
1244 show_settings = 1;
1246 }
1247 }
1248 else {
1249 show_settings = 0;
1250 if (strnicmp("HELP",&szcommandLine[iCommandLen],3))
1251 printf("Unknown APACHE2 command %s\n", &szcommandLine[iCommandLen]);
1252 printf("Usage: APACHE2 [command] [-p <instance ID>]\n");
1253 printf("Commands:\n");
1254 printf("\tDIRECTIVES - Show directives\n");
1255 printf("\tHELP - Display this help information\n");
1256 printf("\tMODULES - Show a list of the loaded modules\n");
1257 printf("\tRESTART - Reread the configuration file and restart Apache\n");
1258 printf("\tSETTINGS - Show current thread status\n");
1259 printf("\tSHUTDOWN - Shutdown Apache\n");
1260 printf("\tVERSION - Display the server version information\n");
1261 }
1262
1263 /* Tell NetWare we handled the command */
1264 return HANDLEDCOMMAND;
1265 }
1266
1267 /* Tell NetWare that the command isn't mine */
1268 return NOTMYCOMMAND;
1269}
1270
1272{
1273 /* Our command line handler interfaces the system operator
1274 with this NLM */
1275
1277
1278 ConsoleHandler.rTag = AllocateResourceTag(getnlmhandle(), "Command Line Processor",
1280 if (!ConsoleHandler.rTag)
1281 {
1282 printf("Error on allocate resource tag\n");
1283 return 1;
1284 }
1285
1287
1288 /* The Remove procedure unregisters the console handler */
1289
1290 return 0;
1291}
1292
1298
1299static const char *set_threads_to_start(cmd_parms *cmd, void *dummy, const char *arg)
1300{
1301 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1302 if (err != NULL) {
1303 return err;
1304 }
1305
1307 return NULL;
1308}
1309
1310static const char *set_min_free_threads(cmd_parms *cmd, void *dummy, const char *arg)
1311{
1312 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1313 if (err != NULL) {
1314 return err;
1315 }
1316
1318 return NULL;
1319}
1320
1321static const char *set_max_free_threads(cmd_parms *cmd, void *dummy, const char *arg)
1322{
1323 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1324 if (err != NULL) {
1325 return err;
1326 }
1327
1329 return NULL;
1330}
1331
1332static const char *set_thread_limit (cmd_parms *cmd, void *dummy, const char *arg)
1333{
1334 const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
1335 if (err != NULL) {
1336 return err;
1337 }
1338
1340 return NULL;
1341}
1342
1346 "Number of worker threads launched at server startup"),
1348 "Minimum number of idle threads, to handle request spikes"),
1350 "Maximum number of idle threads"),
1352 "Maximum number of worker threads alive at the same time"),
1353{ NULL }
1354};
1355
1358 netware_rewrite_args, /* hook to run before apache parses args */
1359 NULL, /* create per-directory config structure */
1360 NULL, /* merge per-directory config structures */
1361 NULL, /* create per-server config structure */
1362 NULL, /* merge per-server config structures */
1363 netware_mpm_cmds, /* command apr_table_t */
1364 netware_mpm_hooks, /* register hooks */
1365};
Symbol export macros and hook functions.
Apache Listeners Library.
Module Magic Number.
Apache Multi-Processing Module library.
const char apr_size_t len
Definition ap_regex.h:187
#define select
char * strstr(char *s1, char *s2)
APR Command Arguments (getopt)
APR Portability Routines.
APR Signal Handling.
APR Strings library.
APR Table library.
APR Thread Mutex Routines.
APR Thread and Process Library.
APR Standard Headers Support.
void apr_thread_yield()
Definition thread.c:161
void ap_process_connection(conn_rec *c, void *csd)
Definition connection.c:210
void ap_lingering_close(conn_rec *c)
Definition connection.c:149
conn_rec * ap_run_create_connection(apr_pool_t *p, server_rec *server, apr_socket_t *csd, long conn_id, void *sbh, apr_bucket_alloc_t *alloc)
Definition connection.c:41
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
void ap_run_child_init(apr_pool_t *pchild, server_rec *s)
Definition config.c:167
#define AP_DECLARE_MODULE(foo)
void ap_show_directives(void)
Definition config.c:2482
void ap_hook_check_config(ap_HOOK_check_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:96
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
void ap_show_modules(void)
Definition config.c:2500
void * csd
const char * ap_get_server_built(void)
Definition buildmark.c:26
const char * ap_get_server_description(void)
Definition core.c:3587
#define OK
Definition httpd.h:456
#define DONE
Definition httpd.h:458
#define APEXIT_CHILDFATAL
Definition httpd.h:341
#define LISTEN_COMMANDS
Definition ap_listen.h:146
void ap_listen_pre_config(void)
Definition listen.c:804
ap_listen_rec * ap_listeners
Definition listen.c:42
int ap_setup_listeners(server_rec *s)
Definition listen.c:610
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define APLOG_STARTUP
Definition http_log.h:105
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_WARNING
Definition http_log.h:68
#define APLOG_ALERT
Definition http_log.h:65
#define APLOG_EMERG
Definition http_log.h:64
void ap_log_mpm_common(server_rec *s)
Definition log.c:1603
void ap_log_command_line(apr_pool_t *p, server_rec *s)
Definition log.c:1575
#define AP_SERVER_BASEARGS
Definition http_main.h:36
server_rec * ap_server_conf
Definition config.c:62
void ap_run_child_status(server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status state)
Definition mpm_common.c:109
void ap_hook_mpm(ap_HOOK_mpm_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:97
@ MPM_CHILD_EXITED
Definition ap_mpm.h:207
@ MPM_CHILD_STARTED
Definition ap_mpm.h:206
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define DEFAULT_THREAD_STACKSIZE
Definition mpm_default.h:74
#define DEFAULT_START_THREADS
Definition mpm_default.h:47
#define DEFAULT_MAX_FREE_THREADS
Definition mpm_default.h:55
#define DEFAULT_MIN_FREE_THREADS
Definition mpm_default.h:61
#define SCOREBOARD_MAINTENANCE_INTERVAL
Definition mpm_default.h:53
int ap_max_requests_per_child
Definition mpm_common.c:151
void ap_hook_mpm_get_name(ap_HOOK_mpm_get_name_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:136
void ap_hook_mpm_query(ap_HOOK_mpm_query_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:100
apr_size_t ap_thread_stacksize
Definition mpm_common.c:156
apr_uint32_t ap_max_mem_free
Definition mpm_common.c:155
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EINIT
Definition apr_errno.h:474
#define APR_STATUS_IS_ENETUNREACH(s)
Definition apr_errno.h:1315
#define APR_STATUS_IS_ETIMEDOUT(s)
Definition apr_errno.h:1311
#define APR_STATUS_IS_ECONNRESET(s)
Definition apr_errno.h:1308
#define APR_STATUS_IS_EAGAIN(s)
Definition apr_errno.h:1272
#define APR_STATUS_IS_EHOSTUNREACH(s)
Definition apr_errno.h:1313
apr_brigade_flush void * ctx
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define RSRC_CONF
#define MPM20_MODULE_STUFF
#define GLOBAL_ONLY
const char * ap_check_cmd_context(cmd_parms *cmd, unsigned forbidden)
Definition core.c:1301
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
#define APR_FILEPATH_TRUENAME
apr_array_header_t ** result
apr_int32_t opt
apr_abortfunc_t apr_allocator_t * allocator
Definition apr_pools.h:208
const char apr_status_t(*) apr_pool_t *poo __attribute__)((nonnull(2, 4)))
Definition apr_pools.h:567
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_signal(a, b)
Definition apr_signal.h:71
#define APR_SO_NONBLOCK
const char * s
Definition apr_strings.h:95
const void * m
apr_int32_t apr_int32_t apr_int32_t err
int sig
apr_cmdtype_e cmd
int int status
#define AP_MPMQ_IS_FORKED
Definition ap_mpm.h:154
#define AP_MPMQ_MPM_STATE
Definition ap_mpm.h:174
#define AP_MPMQ_MAX_DAEMON_USED
Definition ap_mpm.h:150
#define AP_MPMQ_MAX_SPARE_DAEMONS
Definition ap_mpm.h:166
#define AP_MPMQ_MIN_SPARE_THREADS
Definition ap_mpm.h:164
#define AP_MPMQ_HARD_LIMIT_THREADS
Definition ap_mpm.h:158
#define AP_MPMQ_IS_THREADED
Definition ap_mpm.h:152
#define AP_MPMQ_MAX_THREADS
Definition ap_mpm.h:160
#define AP_MPMQ_MAX_REQUESTS_DAEMON
Definition ap_mpm.h:170
#define AP_MPMQ_MAX_SPARE_THREADS
Definition ap_mpm.h:168
#define AP_MPMQ_GENERATION
Definition ap_mpm.h:178
#define AP_MPMQ_MAX_DAEMONS
Definition ap_mpm.h:172
#define AP_MPMQ_HARD_LIMIT_DAEMONS
Definition ap_mpm.h:156
#define AP_MPMQ_MIN_SPARE_DAEMONS
Definition ap_mpm.h:162
#define AP_MPMQ_STARTING
Definition ap_mpm.h:140
#define AP_MPMQ_RUNNING
Definition ap_mpm.h:141
#define AP_MPMQ_STOPPING
Definition ap_mpm.h:142
#define AP_MPMQ_DYNAMIC
Definition ap_mpm.h:131
#define AP_MPMQ_NOT_SUPPORTED
Definition ap_mpm.h:125
Apache Configuration.
Apache connection library.
CORE HTTP Daemon.
Apache Logging library.
Command line options.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
Multi-Processing Modules functions.
static char * ap_my_addrspace
int nlmUnloadSignaled(int wait)
static void set_signals(void)
static int ap_threads_min_free
static ap_generation_t volatile ap_my_generation
static int request_count
static void sig_term(int sig)
static void perform_idle_server_maintenance(apr_pool_t *p)
static void show_server_data()
static int ap_threads_per_child
#define MAX_SPAWN_RATE
static int netware_check_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static void restart(void)
#define WORKER_STARTING
static void RemoveConsoleHandler(void)
static int InstallConsoleHandler(void)
#define DBPRINT1(s, v1)
#define HARD_SERVER_LIMIT
#define MAX_WB_RETRIES
static const char * set_min_free_threads(cmd_parms *cmd, void *dummy, const char *arg)
#define NOTMYCOMMAND
static void netware_rewrite_args(process_rec *process)
static int volatile restart_pending
static apr_pool_t * pmain
static apr_pool_t * pconf
#define WORKER_IDLE_KILL
static int ap_threads_limit
static const char * netware_get_name(void)
static int hold_off_on_exponential_spawning
static int die_now
void worker_main(void *arg)
static int setup_listeners(server_rec *s)
static void clean_child_exit(int code, int worker_num, apr_pool_t *ptrans, apr_bucket_alloc_t *bucket_alloc) __attribute__((noreturn))
static int netware_query(int query_code, int *result, apr_status_t *rv)
static const char * set_max_free_threads(cmd_parms *cmd, void *dummy, const char *arg)
static const char * set_thread_limit(cmd_parms *cmd, void *dummy, const char *arg)
#define MPM_HARD_LIMITS_FILE
static const char * set_threads_to_start(cmd_parms *cmd, void *dummy, const char *arg)
static int mpm_state
static unsigned long worker_thread_count
static int ap_threads_to_start
static int CommandLineInterpreter(scr_t screenID, const char *commandLine)
static int shutdown_listeners()
static int ap_threads_max_free
static pid_t ap_my_pid
static int listenmaxfd
static int make_child(server_rec *s, int slot)
static CommandParser_t ConsoleHandler
static void mpm_main_cleanup(void)
static int netware_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s)
static void display_settings()
static int ap_max_workers_limit
static int volatile is_graceful
static fd_set listenfds
#define DBPRINT0(s)
#define HANDLEDCOMMAND
static int netware_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
static void netware_mpm_hooks(apr_pool_t *p)
static void startup_workers(int number_to_start)
static const command_rec netware_mpm_cmds[]
static int volatile shutdown_pending
#define WORKER_DEAD
int hold_screen_on_exit
static int volatile wait_to_finish
static int idle_spawn_rate
#define WORKER_READY
#define DBPRINT2(s, v1, v2)
static void mpm_term(void)
static int show_settings
#define HARD_THREAD_LIMIT
Definition mpmt_os2.c:68
apr_os_thread_t apr_os_thread_current()
Definition thread.c:142
static int requests_this_child
Definition prefork.c:380
Apache scoreboard library.
void ap_create_sb_handle(ap_sb_handle_t **new_sbh, apr_pool_t *p, int child_num, int thread_num)
Definition scoreboard.c:432
int ap_run_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type)
Definition scoreboard.c:102
#define SERVER_STARTING
Definition scoreboard.h:57
#define SERVER_CLOSING
Definition scoreboard.h:64
#define SERVER_BUSY_LOG
Definition scoreboard.h:62
int ap_generation_t
Definition scoreboard.h:78
#define SERVER_BUSY_WRITE
Definition scoreboard.h:60
#define SERVER_BUSY_READ
Definition scoreboard.h:59
scoreboard * ap_scoreboard_image
Definition scoreboard.c:44
int ap_extended_status
Definition scoreboard.c:61
@ SB_NOT_SHARED
Definition scoreboard.h:84
#define SERVER_GRACEFUL
Definition scoreboard.h:65
#define SERVER_DEAD
Definition scoreboard.h:56
int ap_update_child_status_from_indexes(int child_num, int thread_num, int status, request_rec *r)
Definition scoreboard.c:575
#define SERVER_IDLE_KILL
Definition scoreboard.h:66
#define SERVER_NUM_STATUS
Definition scoreboard.h:67
#define SERVER_BUSY_KEEPALIVE
Definition scoreboard.h:61
#define SERVER_READY
Definition scoreboard.h:58
#define SERVER_BUSY_DNS
Definition scoreboard.h:63
apr_array_header_t * mpm_new_argv
char * name
Apache's listeners record.
Definition ap_listen.h:47
ap_listen_rec * next
Definition ap_listen.h:51
Structure to store things which are per connection.
Definition httpd.h:1152
ap_generation_t running_generation
Definition scoreboard.h:126
A structure that represents one process.
Definition httpd.h:829
int argc
Definition httpd.h:839
apr_pool_t * pool
Definition httpd.h:831
apr_pool_t * pconf
Definition httpd.h:833
const char *const * argv
Definition httpd.h:837
ap_generation_t generation
Definition scoreboard.h:139
A structure that represents the current request.
Definition httpd.h:845
worker_score ** servers
Definition scoreboard.h:163
process_score * parent
Definition scoreboard.h:162
global_score * global
Definition scoreboard.h:161
A structure to store information for each virtual server.
Definition httpd.h:1322
unsigned char status
Definition scoreboard.h:102
apr_status_t apr_os_sock_get(apr_os_sock_t *thesock, apr_socket_t *sock)
Definition sockets.c:506
apr_status_t apr_socket_accept(apr_socket_t **new, apr_socket_t *sock, apr_pool_t *connection_context)
Definition sockets.c:247
apr_status_t apr_socket_close(apr_socket_t *thesocket)
Definition sockets.c:211
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
Definition sockopt.c:113
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray
Worker MPM defaults.