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);
}