fielding    97/11/03 18:47:14

  Added:       src/test README test_date.c test_select.c time-sem.c
  Log:
  Test harnesses are an important part of project knowledge that
  needs to be kept around where we can find it.  Whether or not we
  should distribute this code is an open question.
  
  Revision  Changes    Path
  1.1                  apachen/src/test/README
  
  Index: README
  ===================================================================
  This directory contains useful test code for testing various bits
  of Apache functionality.  This stuff is for the developers only,
  so we might remove it on public releases.
  
  
  
  1.1                  apachen/src/test/test_date.c
  
  Index: test_date.c
  ===================================================================
  /* This program tests the parseHTTPdate routine in ../main/util_date.c.
   *
   * It is only semiautomated in that I would run it, modify the code to
   * use a different algorithm or seed, recompile and run again, etc.
   * Obviously it should use an argument for that, but I never got around
   * to changing the implementation.
   * 
   *     gcc -g -O2 -I../main -o test_date ../main/util_date.o test_date.c
   *     test_date | egrep '^No '
   * 
   * Roy Fielding, 1996
   */
  #define API_EXPORT(x) x
  
  #include <stdio.h>
  #include <stdlib.h>
  #include "util_date.h"
  
  static const long year2secs[] = {
               0L,    /* 1970 */
        31536000L,    /* 1971 */
        63072000L,    /* 1972 */
        94694400L,    /* 1973 */
       126230400L,    /* 1974 */
       157766400L,    /* 1975 */
       189302400L,    /* 1976 */
       220924800L,    /* 1977 */
       252460800L,    /* 1978 */
       283996800L,    /* 1979 */
       315532800L,    /* 1980 */
       347155200L,    /* 1981 */
       378691200L,    /* 1982 */
       410227200L,    /* 1983 */
       441763200L,    /* 1984 */
       473385600L,    /* 1985 */
       504921600L,    /* 1986 */
       536457600L,    /* 1987 */
       567993600L,    /* 1988 */
       599616000L,    /* 1989 */
       631152000L,    /* 1990 */
       662688000L,    /* 1991 */
       694224000L,    /* 1992 */
       725846400L,    /* 1993 */
       757382400L,    /* 1994 */
       788918400L,    /* 1995 */
       820454400L,    /* 1996 */
       852076800L,    /* 1997 */
       883612800L,    /* 1998 */
       915148800L,    /* 1999 */
       946684800L,    /* 2000 */
       978307200L,    /* 2001 */
      1009843200L,    /* 2002 */
      1041379200L,    /* 2003 */
      1072915200L,    /* 2004 */
      1104537600L,    /* 2005 */
      1136073600L,    /* 2006 */
      1167609600L,    /* 2007 */
      1199145600L,    /* 2008 */
      1230768000L,    /* 2009 */
      1262304000L,    /* 2010 */
      1293840000L,    /* 2011 */
      1325376000L,    /* 2012 */
      1356998400L,    /* 2013 */
      1388534400L,    /* 2014 */
      1420070400L,    /* 2015 */
      1451606400L,    /* 2016 */
      1483228800L,    /* 2017 */
      1514764800L,    /* 2018 */
      1546300800L,    /* 2019 */
      1577836800L,    /* 2020 */
      1609459200L,    /* 2021 */
      1640995200L,    /* 2022 */
      1672531200L,    /* 2023 */
      1704067200L,    /* 2024 */
      1735689600L,    /* 2025 */
      1767225600L,    /* 2026 */
      1798761600L,    /* 2027 */
      1830297600L,    /* 2028 */
      1861920000L,    /* 2029 */
      1893456000L,    /* 2030 */
      1924992000L,    /* 2031 */
      1956528000L,    /* 2032 */
      1988150400L,    /* 2033 */
      2019686400L,    /* 2034 */
      2051222400L,    /* 2035 */
      2082758400L,    /* 2036 */
      2114380800L,    /* 2037 */
      2145916800L     /* 2038 */
  };
  
  const char month_snames[12][4] = {
      "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
  };
  
  void gm_timestr_822(char *ts, time_t sec)
  {
      static const char *const days[7]=
         {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
      struct tm *tms;
   
      tms = gmtime(&sec);
   
      sprintf(ts, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday],
              tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900,
              tms->tm_hour, tms->tm_min, tms->tm_sec);
  }
  
  void gm_timestr_850(char *ts, time_t sec)
  {
      static const char *const days[7]=
   {"Sunday","Monday", "Tuesday", "Wednesday", "Thursday", "Friday", 
"Saturday"};
      struct tm *tms;
      int year;
   
      tms = gmtime(&sec);
  
      year = tms->tm_year;
      if (year >= 100) year -= 100;
   
      sprintf(ts, "%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT", days[tms->tm_wday],
              tms->tm_mday, month_snames[tms->tm_mon], year,
              tms->tm_hour, tms->tm_min, tms->tm_sec);
  }
  
  void gm_timestr_ccc(char *ts, time_t sec)
  {
      static const char *const days[7]=
         {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
      struct tm *tms;
   
      tms = gmtime(&sec);
   
      sprintf(ts, "%s %s %2d %.2d:%.2d:%.2d %d", days[tms->tm_wday],
              month_snames[tms->tm_mon], tms->tm_mday, 
              tms->tm_hour, tms->tm_min, tms->tm_sec, tms->tm_year + 1900);
  }
  
  int main (void)
  {
      int year, i;
      time_t guess;
      time_t offset = 0;
   /* time_t offset = 0; */
   /* time_t offset = ((31 + 28) * 24 * 3600) - 1; */
      time_t secstodate, newsecs;
      char datestr[50];
  
      for (year = 1970; year < 2038; ++year) {
          secstodate = (time_t)year2secs[year - 1970] + offset;
          gm_timestr_822(datestr, secstodate);
          newsecs = parseHTTPdate(datestr);
          if (secstodate == newsecs)
              printf("Yes %4d %11ld  %s\n", year, (long)secstodate, datestr);
          else if (newsecs == BAD_DATE)
              printf("No  %4d %11ld %11ld %s\n", year, (long)secstodate, 
                     (long)newsecs, datestr);
          else
              printf("No* %4d %11ld %11ld %s\n", year, (long)secstodate, 
                     (long)newsecs, datestr);
      }
      
      srand48(978245L);
  
      for (i = 0; i < 10000; ++i) {
          guess = (time_t)mrand48();
          if (guess < 0) guess *= -1;
          secstodate = guess + offset;
          gm_timestr_822(datestr, secstodate);
          newsecs = parseHTTPdate(datestr);
          if (secstodate == newsecs)
              printf("Yes %11ld  %s\n", (long)secstodate, datestr);
          else if (newsecs == BAD_DATE)
              printf("No  %11ld %11ld %s\n", (long)secstodate, 
                     (long)newsecs, datestr);
          else
              printf("No* %11ld %11ld %s\n", (long)secstodate, 
                     (long)newsecs, datestr);
      }
      exit(0);
  }
  
  
  
  1.1                  apachen/src/test/test_select.c
  
  Index: test_select.c
  ===================================================================
  /* This is just a quick test program to see how long a wait is
   * produced by a select loop with an exponential backoff.
   *
   *   gcc -g -O2 -o test_select test_select.c
   *   test_select
   *
   * Roy Fielding, 1996
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <sys/time.h>
  
  int main (void)
  {
      int srv;
      long waittime = 4096;
      struct timeval tv;
  
      printf("Start\n");
      while ((waittime > 0) && (waittime < 3000000)) {
          printf("%d\n", waittime);
          tv.tv_sec  = waittime/1000000;
          tv.tv_usec = waittime%1000000;
          waittime <<= 1;
          srv = select(0, NULL, NULL, NULL, &tv);
      }
      printf("End\n");
      exit(0);
  }
  
  
  
  1.1                  apachen/src/test/time-sem.c
  
  Index: time-sem.c
  ===================================================================
  /*
  Date: Sat, 1 Nov 1997 16:53:52 -0800 (PST)
  From: Dean Gaudet <[EMAIL PROTECTED]>
  
  This time-sem.c includes the necessary signal manipulations to allow us to
  continue to use pthreads.  It appears to still be and order of magnitude
  faster than fcntl locking.  I'm a little too busy to make a patch though,
  so if someone could take the pthread code in time-sem.c here and compare
  it against the server ... and generate a patch, that'd be great.  You also
  have to properly release the mutex on any of the three unblocked signals --
  which you should do in the handlers we already have for those signals,
  so that we don't have to also instate a handler during the critical
  section ...
  
  Dean
  
  gcc -o time-FCNTL -Wall -O time-sem.c -DUSE_FCNTL_SERIALIZED_ACCEPT
  gcc -o time-FLOCK -Wall -O time-sem.c -DUSE_FLOCK_SERIALIZED_ACCEPT
  gcc -o time-SEM -Wall -O time-sem.c -DUSE_SYSVSEM_SERIALIZED_ACCEPT
  gcc -o time-PTHREAD -Wall -O time-sem.c -DUSE_PTHREAD_SERIALIZED_ACCEPT 
-lpthread
  */
  
  #include <errno.h>
  #include <sys/time.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <sys/wait.h>
  #include <sys/mman.h>
  #include <signal.h>
  
  #if defined(USE_FCNTL_SERIALIZED_ACCEPT)
  
  static struct flock lock_it;
  static struct flock unlock_it;
  
  static int fcntl_fd=-1;
  
  /*
   * Initialize mutex lock.
   * Must be safe to call this on a restart.
   */
  void
  accept_mutex_init(void)
  {
  
      lock_it.l_whence = SEEK_SET;   /* from current point */
      lock_it.l_start  = 0;          /* -"- */
      lock_it.l_len    = 0;          /* until end of file */
      lock_it.l_type   = F_WRLCK;    /* set exclusive/write lock */
      lock_it.l_pid    = 0;          /* pid not actually interesting */
      unlock_it.l_whence = SEEK_SET; /* from current point */
      unlock_it.l_start  = 0;        /* -"- */
      unlock_it.l_len    = 0;        /* until end of file */
      unlock_it.l_type   = F_UNLCK;  /* set exclusive/write lock */
      unlock_it.l_pid    = 0;        /* pid not actually interesting */
  
      fcntl_fd = open("test-lock-thing", O_CREAT | O_WRONLY | O_EXCL, 0644);
      if (fcntl_fd == -1)
      {
        perror ("open");
        fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing");
        exit (1);
      }
      unlink("test-lock-thing");
  }
  
  void accept_mutex_on(void)
  {
      int ret;
      
      while ((ret = fcntl(fcntl_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
        continue;
  
      if (ret < 0) {
        perror ("fcntl lock_it");
        exit(1);
      }
  }
  
  void accept_mutex_off(void)
  {
      if (fcntl (fcntl_fd, F_SETLKW, &unlock_it) < 0)
      {
        perror ("fcntl unlock_it");
        exit(1);
      }
  }
  
  #elif defined(USE_FLOCK_SERIALIZED_ACCEPT)
  
  #include <sys/file.h>
  
  static int flock_fd=-1;
  
  /*
   * Initialize mutex lock.
   * Must be safe to call this on a restart.
   */
  void
  accept_mutex_init(void)
  {
  
      flock_fd = open("test-lock-thing", O_CREAT | O_WRONLY | O_EXCL, 0644);
      if (flock_fd == -1)
      {
        perror ("open");
        fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing");
        exit (1);
      }
      unlink("test-lock-thing");
  }
  
  void accept_mutex_on(void)
  {
      int ret;
      
      while ((ret = flock(flock_fd, LOCK_EX)) < 0 && errno == EINTR)
        continue;
  
      if (ret < 0) {
        perror ("flock(LOCK_EX)");
        exit(1);
      }
  }
  
  void accept_mutex_off(void)
  {
      if (flock (flock_fd, LOCK_UN) < 0)
      {
        perror ("flock(LOCK_UN)");
        exit(1);
      }
  }
  
  #elif defined (USE_SYSVSEM_SERIALIZED_ACCEPT)
  
  #include <sys/types.h>
  #include <sys/ipc.h>
  #include <sys/sem.h>
  
  static   int sem_id = -1;
  
  void accept_mutex_init(void)
  {
            union semun {
                 int val;
                 struct semid_ds *buf;
                 ushort *array;
            };
  
      union semun ick;
  
      sem_id = semget(999, 1, IPC_CREAT | 0666);
      if (sem_id < 0) {
         perror ("semget");
         exit (1);
      }
      ick.val = 1;
      if (semctl(sem_id, 0, SETVAL, ick) < 0) {
         perror ("semctl");
          exit(1);
      }
  }
  
  void accept_mutex_on()
  {
      struct sembuf op;
  
      op.sem_num = 0;
      op.sem_op  = -1;
      op.sem_flg = SEM_UNDO;
      if (semop(sem_id, &op, 1) < 0) {
        perror ("accept_mutex_on");
        exit (1);
      }
  }
  
  void accept_mutex_off()
  {
      struct sembuf op;
  
      op.sem_num = 0;
      op.sem_op  = 1;
      op.sem_flg = SEM_UNDO;
      if (semop(sem_id, &op, 1) < 0) {
        perror ("accept_mutex_off");
          exit (1);
      }
  }
  
  #elif defined (USE_PTHREAD_SERIALIZED_ACCEPT)
  
  #include <pthread.h>
  
  static pthread_mutex_t *mutex;
  static sigset_t accept_block_mask;
  static sigset_t accept_previous_mask;
  
  void accept_mutex_init(void)
  {
      pthread_mutexattr_t mattr;
      int fd;
  
      fd = open ("/dev/zero", O_RDWR);
      if (fd == -1) {
        perror ("open(/dev/zero)");
        exit (1);
      }
      mutex = (pthread_mutex_t *)mmap ((caddr_t)0, sizeof (*mutex),
                    PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
      if (mutex == (void *)(caddr_t)-1) {
        perror ("mmap");
        exit (1);
      }
      close (fd);
      if (pthread_mutexattr_init(&mattr)) {
        perror ("pthread_mutexattr_init");
        exit (1);
      }
      if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) {
        perror ("pthread_mutexattr_setpshared");
        exit (1);
      }
      if (pthread_mutex_init(mutex, &mattr)) {
        perror ("pthread_mutex_init");
        exit (1);
      }
      sigfillset(&accept_block_mask);
      sigdelset(&accept_block_mask, SIGHUP);
      sigdelset(&accept_block_mask, SIGTERM);
      sigdelset(&accept_block_mask, SIGUSR1);
  }
  
  void accept_mutex_on()
  {
      if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) {
        perror("sigprocmask(SIG_BLOCK)");
        exit (1);
      }
      if (pthread_mutex_lock (mutex)) {
        perror ("pthread_mutex_lock");
        exit (1);
      }
  }
  
  void accept_mutex_off()
  {
      if (pthread_mutex_unlock (mutex)) {
        perror ("pthread_mutex_unlock");
        exit (1);
      }
      if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) {
        perror("sigprocmask(SIG_SETMASK)");
        exit (1);
      }
  }
  
  #elif defined (USE_USLOCK_SERIALIZED_ACCEPT)
  #include <ulocks.h>
  static usptr_t *us = NULL;
  static ulock_t uslock = NULL;
  void accept_mutex_init(void)
  {
      ptrdiff_t old;
      /* default is 8 */
  #define CONF_INITUSERS_MAX 15
      if ((old = usconfig(CONF_INITUSERS, CONF_INITUSERS_MAX)) == -1) {
          perror("usconfig");
          exit(-1);
      }
      if ((old = usconfig(CONF_LOCKTYPE, US_NODEBUG)) == -1) {
          perror("usconfig");
          exit(-1);
      }
      if ((old = usconfig(CONF_ARENATYPE, US_SHAREDONLY)) == -1) {
          perror("usconfig");
          exit(-1);
      }
      if ((us = usinit("/dev/zero")) == NULL) {
          perror("usinit");
          exit(-1);
      }
      if ((uslock = usnewlock(us)) == NULL) {
          perror("usnewlock");
          exit(-1);
      }
  }
  void accept_mutex_on()
  {
      switch(ussetlock(uslock)) {
          case 1:
              /* got lock */
              break;
          case 0:
              fprintf(stderr, "didn't get lock\n");
              exit(-1);
          case -1:
              perror("ussetlock");
              exit(-1);
      }
  }
  void accept_mutex_off()
  {
      if (usunsetlock(uslock) == -1) {
          perror("usunsetlock");
          exit(-1);
      }
  }
  #endif
  
  
  
  void main (int argc, char **argv)
  {
      int num_iter;
      int num_child;
      int i;
      struct timeval first;
      struct timeval last;
      long ms;
      int pid;
      unsigned long *shared_counter;
  
      if (argc != 3) {
        fprintf (stderr, "Usage: time-sem num-child num-iter\n");
        exit (1);
      }
  
      num_child = atoi (argv[1]);
      num_iter = atoi (argv[2]);
  
      /* allocate shared memory for the shared_counter */
      i = open ("/dev/zero", O_RDWR);
      if (i == -1) {
        perror ("open");
        exit (1);
      }
      shared_counter = (unsigned long *)mmap ((caddr_t)0,
                    sizeof (*shared_counter),
                    PROT_READ|PROT_WRITE, MAP_SHARED, i, 0);
      if (shared_counter == (void *)(caddr_t)-1) {
        perror ("mmap");
        exit (1);
      }
      close (i);
  
      /* initialize counter to 0 */
      *shared_counter = 0;
  
      accept_mutex_init ();
  
      /* parent grabs mutex until done spawning children */
      accept_mutex_on ();
  
      for (i = 0; i < num_child; ++i) {
        pid = fork();
        if (pid == 0) {
            /* child, do our thing */
            for (i = 0; i < num_iter; ++i) {
                accept_mutex_on ();
                ++*shared_counter;
                accept_mutex_off ();
            }
            exit (0);
        } else if (pid == -1) {
            perror ("fork");
            exit (1);
        }
      }
  
      /* a quick test to see that nothing is screwed up */
      if (*shared_counter != 0) {
        puts ("WTF! shared_counter != 0 before the children have been 
started!");
        exit (1);
      }
  
      gettimeofday (&first, NULL);
      /* launch children into action */
      accept_mutex_off ();
      for (i = 0; i < num_child; ++i) {
        if (wait(NULL) == -1) {
            perror ("wait");
        }
      }
      gettimeofday (&last, NULL);
  
      if (*shared_counter != num_child * num_iter) {
        puts ("WTF! shared_counter != num_child * num_iter!");
      }
  
      last.tv_sec -= first.tv_sec;
      ms = last.tv_usec - first.tv_usec;
      if (ms < 0) {
        --last.tv_sec;
        ms += 1000000;
      }
      last.tv_usec = ms;
      printf ("%8lu.%06lu\n", last.tv_sec, last.tv_usec);
  }
  
  
  
  

Reply via email to