Under Cygwin, the apparent method to run a service is using
cygrunsrv.exe.  Unfortunately cygrunsrv's method of detecting if the
service stayed running or not is based on whether the process that it
spawned is still running or not.

The patch below adds an option -W (cygwin only) that modifies the
behavior of detach().  With this patch, httpd -W will keep an httpd
process running just waiting for httpd to exit or for it to be signalled
by cygrunsrv to shut down the service.

The only other behavior change that is introduced is SIGUSR2 is now
caught and ignored.  This is used to work around an apparent bug in
cygwin's waitpid() when the child process dies in a non-graceful way
(kill -9).

I welcome all comments.
Mike


Index: main/http_main.c
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/main/http_main.c,v
retrieving revision 1.576
diff -c -r1.576 http_main.c
*** main/http_main.c    26 Feb 2002 15:04:53 -0000      1.576
--- main/http_main.c    27 Feb 2002 21:31:28 -0000
***************
*** 341,346 ****
--- 341,357 ----
  
  static int one_process = 0;
  
+ /* parent_wait --- when running as a service under Cygwin, the first process
+  * should not die else cygrunsrv thinks that httpd has died when in reality it 
+  * has just gone into the background.  When parent_wait is non-zero
+  * (-W option, compiled under Cygnus only) the parent sits around just
+  * waiting for its first child to die.
+  */
+ 
+ #if defined(CYGWIN)
+ static int parent_wait = 0;
+ #endif
+ 
  /* set if timeouts are to be handled by the children and not by the parent.
   * i.e. child_timeouts = !standalone || one_process.
   */
***************
*** 396,401 ****
--- 407,434 ----
  /* Global, alas, so http_core can talk to us */
  enum server_token_type ap_server_tokens = SrvTk_FULL;
  
+ /* parentwait_pid --- contains the PID of the master httpd so that kill
+  * signals sent from cygrunsrv to httpd can be delivered to the master
+  * httpd.  Only used when compiled under Cygnus and the -W runtime flag
+  * is used.
+  */
+ #if defined(CYGWIN)
+ static pid_t parentwait_pid;
+ #endif
+ 
+ /* 
+  * This is a signal handler that passes signals on from cygrunsrv to the
+  * master httpd..  Only used when compiled under Cygnus and the -W 
+  * runtime flag is used.
+  */
+ #if defined(CYGWIN)
+ static void parentwait_kill(int signum) {
+     printf("Caught signal %d and passing it on to pid %d\n",
+                   parentwait_pid, signum);
+     kill(parentwait_pid, signum);
+ }
+ #endif
+ 
  /*
   * This routine is called when the pconf pool is vacuumed.  It resets the
   * server version string to a known value and [re]enables modifications
***************
*** 1358,1363 ****
--- 1391,1399 ----
  #endif
      fprintf(stderr, "       %s [-C \"directive\"] [-c \"directive\"]\n", pad);
      fprintf(stderr, "       %s [-v] [-V] [-h] [-l] [-L] [-S] [-t] [-T]\n", pad);
+ #if defined(CYGWIN)
+     fprintf(stderr, "       %s [-W]\n", pad);
+ #endif
      fprintf(stderr, "Options:\n");
  #ifdef SHARED_CORE
      fprintf(stderr, "  -R directory     : specify an alternate location for shared 
object files\n");
***************
*** 1389,1394 ****
--- 1425,1434 ----
      fprintf(stderr, "  -k uninstall | -u: uninstall an Apache service\n");
      fprintf(stderr, "  -W service       : after -k config|install; Apache starts 
after 'service'\n");
      fprintf(stderr, "  -w               : holds the window open for 30 seconds for 
fatal errors.\n");
+ #else /* !WIN32 */
+ #if defined(CYGWIN)
+     fprintf(stderr, "  -W               : one process just waits for signals from 
+cygrunsrv\n");
+ #endif
  #endif
  
  #if defined(NETWARE)
***************
*** 3369,3376 ****
      !defined(BONE)
  /* Don't detach for MPE because child processes can't survive the death of
     the parent. */
!     if ((x = fork()) > 0)
        exit(0);
      else if (x == -1) {
        perror("fork");
        fprintf(stderr, "%s: unable to fork new process\n", ap_server_argv0);
--- 3409,3469 ----
      !defined(BONE)
  /* Don't detach for MPE because child processes can't survive the death of
     the parent. */
! #if defined(CYGWIN)
!     if ( parent_wait ) {
!       signal(SIGUSR2, SIG_IGN);
!     }
! #endif
!     if ((x = fork()) > 0) {
! #if defined(CYGWIN)
!         int status, exitval = 0;
!         if ( parent_wait == 0 ) {
!             exit(0);
!         }
!         parentwait_pid = x;
!         signal(SIGHUP, parentwait_kill);
!         signal(SIGINT, parentwait_kill);
!         signal(SIGQUIT, parentwait_kill);
!         signal(SIGTERM, parentwait_kill);
!       while ( 1 ) {
!             waitpid(x, &status, WNOHANG);
!             if ( WIFEXITED(status) ) {
!                 exitval = WEXITSTATUS(status);
!                 printf("Child pid %d exited with status %d\n", x, exitval);
!               if ( WIFSIGNALED(status) ) {
!                       printf("Child pid %d received signal %d\n", x, 
!                                       WTERMSIG(status));
!               }
!               exit(exitval);
!             }
!             if ( WIFSIGNALED(status) ) {
!               /* Cygwin seems to have multiple problems with wait.
!                * If the child gets killed with -9, it does not
!                * the parent does not notice that it is gone.  It sees
!                * the signal 9, but does not see the exit status.
!                * Thus, it is necessary to try to send a signal to the
!                * master httpd to be sure it is still there.
!                * Also, for some reason, the child process gets a
!                * constant stream of signal 104.  The sleep below
!                * keeps this process for chewing up too much cpu time
!                * looking at the status.
!                */
!               if ( WTERMSIG(status) != 104 ) {
!                       printf("Child pid %d received signal %d\n", x, 
!                               WTERMSIG(status));
!               }
!               if ( kill(x, SIGUSR2) != 0 ) {
!                   printf("pid %d is gone.  Service closing down.\n", x);
!                   exit(0);
!               }
!               sleep(1);
!             }
!       }
        exit(0);
+ #else /* !CYGWIN */
+       exit(0);
+ #endif /* CYGWIN */
+     }
      else if (x == -1) {
        perror("fork");
        fprintf(stderr, "%s: unable to fork new process\n", ap_server_argv0);
***************
*** 5300,5305 ****
--- 5393,5401 ----
  #ifdef DEBUG_SIGSTOP
                                    "Z:"
  #endif
+ #ifdef CYGWIN
+                                   "W"
+ #endif
                        )) != -1) {
        char **new;
        switch (c) {
***************
*** 5373,5378 ****
--- 5469,5479 ----
            break;
        case 'h':
            usage(argv[0]);
+ #if defined(CYGWIN)
+         case 'W':
+             parent_wait++;
+             break;
+ #endif
        case '?':
            usage(argv[0]);
        }
***************
*** 7200,7206 ****
  
      while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLz:Z:wiuStThk:n:W:")) != -1) {
  #else /* !WIN32 */
!     while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLsStTh")) != -1) {
  #endif
          char **new;
        switch (c) {
--- 7301,7311 ----
  
      while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLz:Z:wiuStThk:n:W:")) != -1) {
  #else /* !WIN32 */
!     while ((c = getopt(argc, argv, "D:C:c:Xd:f:vVlLsStTh"
! #ifdef CYGWIN
!                                   "W"
! #endif
!                                   )) != -1) {
  #endif
          char **new;
        switch (c) {
***************
*** 7348,7353 ****
--- 7453,7464 ----
              clean_parent_exit(1);
  #else
              clean_parent_exit(0);
+ #endif
+ 
+ #if defined(CYGWIN)
+         case 'W':
+             parent_wait++;
+             break;
  #endif
  
        case 'X':
Index: support/httpd.8
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/support/httpd.8,v
retrieving revision 1.19
diff -c -r1.19 httpd.8
*** support/httpd.8     2 Mar 2001 07:42:35 -0000       1.19
--- support/httpd.8     27 Feb 2002 21:31:29 -0000
***************
*** 102,107 ****
--- 102,110 ----
  [
  .B \-T
  ]
+ [
+ .B \-W
+ ]
  
  .SH DESCRIPTION
  .B httpd
***************
*** 178,183 ****
--- 181,192 ----
  Same as option 
  .B \-t
  but does not check the configured document roots. 
+ .TP
+ .B \-W
+ Causes apache to run in multiple-process mode, but does not go into the
+ background.  This is useful on Windows when used with cygrunsrv.exe to allow
+ apache to run as a service.
+ This option is only available on Windows version compiled under Cygwin.
  .TP
  .B \-X
  Run in single-process mode, for internal debugging purposes only; the daemon


Reply via email to