You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Ben Laurie <be...@gonzo.ben.algroup.co.uk> on 1996/06/23 14:02:24 UTC

"Graceful Restart" patch

Guys,

I've worked up this patch to enable a graceful restart of Apache. Essentially
the idea is this: you send the main process a SIGINT (kill -2) and it invites
the children to die politely. It then waits until they all have (which they do
at the end of the _next_ request). Then it restarts as if it had a SIGHUP. I'm
not particularly proposing that this should go into 1.1, though it ought to be
pretty harmless unless actually used, but I'd appreciate it if people could
give it a try and let me know what they think.

Cheers,

Ben.

Index: http_main.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_main.c,v
retrieving revision 1.40
diff -c -r1.40 http_main.c
*** http_main.c	1996/06/22 13:58:34	1.40
--- http_main.c	1996/06/23 12:36:32
***************
*** 427,440 ****
   */
  
  #if defined(HAVE_MMAP)
! static short_score *scoreboard_image=NULL;
  
  static void setup_shared_mem(void)
  {
      caddr_t m;
  #if defined(MAP_ANON) || defined(MAP_FILE)
  /* BSD style */
!     m = mmap((caddr_t)0, HARD_SERVER_LIMIT*sizeof(short_score),
  	     PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
      if (m == (caddr_t)-1)
      {
--- 427,440 ----
   */
  
  #if defined(HAVE_MMAP)
! static scoreboard *scoreboard_image=NULL;
  
  static void setup_shared_mem(void)
  {
      caddr_t m;
  #if defined(MAP_ANON) || defined(MAP_FILE)
  /* BSD style */
!     m = mmap((caddr_t)0, SCOREBOARD_SIZE,
  	     PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0);
      if (m == (caddr_t)-1)
      {
***************
*** 453,459 ****
  	fprintf(stderr, "httpd: Could not open /dev/zero\n");
  	exit(1);
      }
!     m = mmap((caddr_t)0, HARD_SERVER_LIMIT*sizeof(short_score),
  	     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (m == (caddr_t)-1)
      {
--- 453,459 ----
  	fprintf(stderr, "httpd: Could not open /dev/zero\n");
  	exit(1);
      }
!     m = mmap((caddr_t)0, SCOREBOARD_SIZE,
  	     PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (m == (caddr_t)-1)
      {
***************
*** 463,486 ****
      }
      close(fd);
  #endif
!     scoreboard_image = (short_score *)m;
  }
  
  #elif defined(HAVE_SHMGET)
! static short_score *scoreboard_image=NULL;
  static key_t shmkey = IPC_PRIVATE;
  static int shmid = -1;
  
  static void setup_shared_mem(void)
  {
-     int score_size = HARD_SERVER_LIMIT*sizeof(short_score);
      char errstr[MAX_STRING_LEN];
      struct shmid_ds shmbuf;
  #ifdef MOVEBREAK
      char *obrk;
  #endif
  
!     if ((shmid = shmget(shmkey, score_size, IPC_CREAT|SHM_R|SHM_W)) == -1)
      {
  	perror("shmget");
  	fprintf(stderr, "httpd: Could not call shmget\n");
--- 463,485 ----
      }
      close(fd);
  #endif
!     scoreboard_image = (scoreboard *)m;
  }
  
  #elif defined(HAVE_SHMGET)
! static scoreboard *scoreboard_image=NULL;
  static key_t shmkey = IPC_PRIVATE;
  static int shmid = -1;
  
  static void setup_shared_mem(void)
  {
      char errstr[MAX_STRING_LEN];
      struct shmid_ds shmbuf;
  #ifdef MOVEBREAK
      char *obrk;
  #endif
  
!     if ((shmid = shmget(shmkey, SCOREBOARD_SIZE, IPC_CREAT|SHM_R|SHM_W)) == -1)
      {
  	perror("shmget");
  	fprintf(stderr, "httpd: Could not call shmget\n");
***************
*** 507,514 ****
      }
  #endif
  
! #define BADSHMAT	((short_score*)(-1))
!     if ((scoreboard_image = (short_score*)shmat(shmid, 0, 0)) == BADSHMAT)
      {
  	perror("shmat");
  	fprintf(stderr, "httpd: Could not call shmat\n");
--- 506,513 ----
      }
  #endif
  
! #define BADSHMAT	((scoreboard *)(-1))
!     if ((scoreboard_image = (scoreboard *)shmat(shmid, 0, 0)) == BADSHMAT)
      {
  	perror("shmat");
  	fprintf(stderr, "httpd: Could not call shmat\n");
***************
*** 557,563 ****
  }
  
  #else
! static short_score scoreboard_image[HARD_SERVER_LIMIT];
  static int have_scoreboard_fname = 0;
  static int scoreboard_fd;
  
--- 556,563 ----
  }
  
  #else
! static scoreboard _scoreboard_image;
! static scoreboard *scoreboard_image=&_scoreboard_image;
  static int have_scoreboard_fname = 0;
  static int scoreboard_fd;
  
***************
*** 600,606 ****
      {
  	setup_shared_mem();
      }
!     memset(scoreboard_image, 0, HARD_SERVER_LIMIT*sizeof(short_score));
  #else
      scoreboard_fname = server_root_relative (p, scoreboard_fname);
  
--- 600,606 ----
      {
  	setup_shared_mem();
      }
!     memset(scoreboard_image, 0, SCOREBOARD_SIZE);
  #else
      scoreboard_fname = server_root_relative (p, scoreboard_fname);
  
***************
*** 614,622 ****
  	exit (1);
      }
  
!     memset ((char*)scoreboard_image, 0, sizeof(scoreboard_image));
      force_write (scoreboard_fd, (char*)scoreboard_image,
! 		 sizeof(scoreboard_image));
  #endif
  }
  
--- 614,622 ----
  	exit (1);
      }
  
!     memset ((char*)scoreboard_image, 0, sizeof(*scoreboard_image));
      force_write (scoreboard_fd, (char*)scoreboard_image,
! 		 sizeof(*scoreboard_image));
  #endif
  }
  
***************
*** 659,665 ****
  #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
      lseek (scoreboard_fd, 0L, 0);
      force_read (scoreboard_fd, (char*)scoreboard_image,
! 		sizeof(scoreboard_image));
  #endif
  }
  
--- 659,665 ----
  #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
      lseek (scoreboard_fd, 0L, 0);
      force_read (scoreboard_fd, (char*)scoreboard_image,
! 		sizeof(*scoreboard_image));
  #endif
  }
  
***************
*** 671,677 ****
      if (child_num < 0)
  	return -1;
      
!     memcpy(&new_score_rec,&scoreboard_image[child_num],sizeof new_score_rec);
      new_score_rec.pid = getpid();
      old_status = new_score_rec.status;
      new_score_rec.status = status;
--- 671,677 ----
      if (child_num < 0)
  	return -1;
      
!     memcpy(&new_score_rec,&scoreboard_image->servers[child_num],sizeof new_score_rec);
      new_score_rec.pid = getpid();
      old_status = new_score_rec.status;
      new_score_rec.status = status;
***************
*** 702,708 ****
  #endif
  
  #if defined(HAVE_MMAP) || defined(HAVE_SHMGET)
!     memcpy(&scoreboard_image[child_num], &new_score_rec, sizeof(short_score));
  #else
      lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
      force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
--- 702,708 ----
  #endif
  
  #if defined(HAVE_MMAP) || defined(HAVE_SHMGET)
!     memcpy(&scoreboard_image->servers[child_num], &new_score_rec, sizeof new_score_rec);
  #else
      lseek (scoreboard_fd, (long)child_num * sizeof(short_score), 0);
      force_write (scoreboard_fd, (char*)&new_score_rec, sizeof(short_score));
***************
*** 711,722 ****
      return old_status;
  }
  
  int get_child_status (int child_num)
  {
      if (child_num<0 || child_num>=HARD_SERVER_LIMIT)
      	return -1;
      else
! 	return scoreboard_image[child_num].status;
  }
  
  int count_busy_servers ()
--- 711,732 ----
      return old_status;
  }
  
+ void update_scoreboard_global()
+     {
+ #if !defined(HAVE_MMAP) && !defined(HAVE_SHMGET)
+     lseek(scoreboard_fd,
+ 	  (char *)&scoreboard_image->global-(char *)scoreboard_image,0);
+     force_write(scoreboard_fd,(char *)&scoreboard_image->global,
+ 		sizeof scoreboard_image->global);
+ #endif
+     }
+ 
  int get_child_status (int child_num)
  {
      if (child_num<0 || child_num>=HARD_SERVER_LIMIT)
      	return -1;
      else
! 	return scoreboard_image->servers[child_num].status;
  }
  
  int count_busy_servers ()
***************
*** 725,742 ****
      int res = 0;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
!       if (scoreboard_image[i].status == SERVER_BUSY_READ ||
!               scoreboard_image[i].status == SERVER_BUSY_WRITE ||
!               scoreboard_image[i].status == SERVER_BUSY_KEEPALIVE ||
!               scoreboard_image[i].status == SERVER_BUSY_LOG ||
!               scoreboard_image[i].status == SERVER_BUSY_DNS)
            ++res;
      return res;
  }
  
  short_score get_scoreboard_info(int i)
  {
!     return (scoreboard_image[i]);
  }
  
  #if defined(STATUS)
--- 735,763 ----
      int res = 0;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
!       if (scoreboard_image->servers[i].status == SERVER_BUSY_READ ||
!               scoreboard_image->servers[i].status == SERVER_BUSY_WRITE ||
!               scoreboard_image->servers[i].status == SERVER_BUSY_KEEPALIVE ||
!               scoreboard_image->servers[i].status == SERVER_BUSY_LOG ||
!               scoreboard_image->servers[i].status == SERVER_BUSY_DNS)
            ++res;
      return res;
  }
  
+ int count_live_servers()
+     {
+     int i;
+     int res = 0;
+ 
+     for (i = 0; i < HARD_SERVER_LIMIT; ++i)
+       if (scoreboard_image->servers[i].status != SERVER_DEAD)
+ 	  ++res;
+     return res;
+     }
+ 
  short_score get_scoreboard_info(int i)
  {
!     return (scoreboard_image->servers[i]);
  }
  
  #if defined(STATUS)
***************
*** 776,783 ****
      int res = 0;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! 	if (scoreboard_image[i].status == SERVER_READY
! 	  || scoreboard_image[i].status == SERVER_STARTING)
  	    ++res;
  
      return res;
--- 797,804 ----
      int res = 0;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! 	if (scoreboard_image->servers[i].status == SERVER_READY
! 	  || scoreboard_image->servers[i].status == SERVER_STARTING)
  	    ++res;
  
      return res;
***************
*** 788,794 ****
      int i;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! 	if (scoreboard_image[i].status == SERVER_DEAD)
  	    return i;
  
      return -1;
--- 809,815 ----
      int i;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! 	if (scoreboard_image->servers[i].status == SERVER_DEAD)
  	    return i;
  
      return -1;
***************
*** 799,805 ****
      int i;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! 	if (scoreboard_image[i].pid == pid)
  	    return i;
  
      return -1;
--- 820,826 ----
      int i;
  
      for (i = 0; i < HARD_SERVER_LIMIT; ++i)
! 	if (scoreboard_image->servers[i].pid == pid)
  	    return i;
  
      return -1;
***************
*** 812,821 ****
  
      sync_scoreboard_image();
      for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
! 	int pid = scoreboard_image[i].pid;
  
  	if (pid != my_pid && pid != 0)
! 	    waitpid (scoreboard_image[i].pid, &status, 0);
      }
  }
  
--- 833,842 ----
  
      sync_scoreboard_image();
      for (i = 0; i < HARD_SERVER_LIMIT; ++i) {
! 	int pid = scoreboard_image->servers[i].pid;
  
  	if (pid != my_pid && pid != 0)
! 	    waitpid (scoreboard_image->servers[i].pid, &status, 0);
      }
  }
  
***************
*** 994,999 ****
--- 1015,1026 ----
  #endif
  }
  
+ void graceful_restart()
+     {
+     scoreboard_image->global.please_exit=1;
+     update_scoreboard_global();
+     }
+ 
  void set_signals() {
  #ifndef NO_USE_SIGACTION
      struct sigaction sa;
***************
*** 1006,1011 ****
--- 1033,1039 ----
  #ifdef NO_USE_SIGACTION
      signal(SIGTERM,(void (*)())sig_term);
      signal(SIGHUP,(void (*)())restart);
+     signal(SIGINT,(void (*)())graceful_restart);
  #else
      memset(&sa,0,sizeof sa);
      sa.sa_handler=(void (*)())sig_term;
***************
*** 1014,1019 ****
--- 1042,1050 ----
      sa.sa_handler=(void (*)())restart;
      if(sigaction(SIGHUP,&sa,NULL) < 0)
  	log_unixerr("sigaction(SIGHUP)", NULL, NULL, server_conf);
+     sa.sa_handler=(void (*)())graceful_restart;
+     if(sigaction(SIGINT,&sa,NULL) < 0)
+ 	log_unixerr("sigaction(SIGINT)", NULL, NULL, server_conf);
  #endif
  }
  
***************
*** 1166,1171 ****
--- 1197,1205 ----
  	clear_pool (ptrans);
  	
  	sync_scoreboard_image();
+ 
+ 	if(scoreboard_image->global.please_exit)
+ 	    exit(0);
  	
  	if ((count_idle_servers() >= daemons_max_free)
  	    || (max_requests_per_child > 0
***************
*** 1250,1255 ****
--- 1284,1293 ----
  #if defined(STATUS)
  	  if (r) increment_counts(child_num,r,0);
  #endif
+ 	  sync_scoreboard_image();
+ 	  if(scoreboard_image->global.please_exit)
+ 	      exit(0);
+ 
  	}
  #if 0	
  	if (bytes_in_pool (ptrans) > 80000)
***************
*** 1445,1457 ****
          }
  
  	sync_scoreboard_image();
! 	if ((count_idle_servers() < daemons_min_free)
  	 && (child_slot = find_free_child_num()) >= 0
  	 && child_slot <= daemons_limit) {
  	    (void)update_child_status(child_slot,SERVER_STARTING,
  	     (request_rec*)NULL);
  	    make_child(server_conf, child_slot);
  	}
      }
  
  } /* standalone_main */
--- 1483,1505 ----
          }
  
  	sync_scoreboard_image();
! 	if (!scoreboard_image->global.please_exit
! 	 && (count_idle_servers() < daemons_min_free)
  	 && (child_slot = find_free_child_num()) >= 0
  	 && child_slot <= daemons_limit) {
  	    (void)update_child_status(child_slot,SERVER_STARTING,
  	     (request_rec*)NULL);
  	    make_child(server_conf, child_slot);
+ 
  	}
+ 
+ 	if(scoreboard_image->global.please_exit && !count_live_servers())
+ #ifdef NEXT
+ 	    longjmp(restart_buffer,1);
+ #else
+ 	    siglongjmp(restart_buffer,1);
+ #endif
+ 	    
      }
  
  } /* standalone_main */
Index: scoreboard.h
===================================================================
RCS file: /export/home/cvs/apache/src/scoreboard.h,v
retrieving revision 1.12
diff -c -r1.12 scoreboard.h
*** scoreboard.h	1996/06/07 17:39:26	1.12
--- scoreboard.h	1996/06/23 12:36:33
***************
*** 90,94 ****
--- 90,109 ----
  #endif
  } short_score;
  
+ typedef struct
+     {
+     char please_exit;	/* Set by the main process if a graceful
+ 				   restart is required */
+     } global_score;
+ 
+ typedef struct
+     {
+     short_score servers[HARD_SERVER_LIMIT];
+     global_score global;
+     } scoreboard;
+ 
+ #define SCOREBOARD_SIZE		sizeof(scoreboard)
+ 
  extern void sync_scoreboard_image(void);
  short_score get_scoreboard_info(int x);
+ 

-- 
Ben Laurie                  Phone: +44 (181) 994 6435
Freelance Consultant and    Fax:   +44 (181) 994 6472
Technical Director          Email: ben@algroup.co.uk
A.L. Digital Ltd,           URL: http://www.algroup.co.uk
London, England.