httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dean Gaudet <dgau...@arctic.org>
Subject Re: [PATCH] SysV semaphores
Date Wed, 06 Aug 1997 11:34:14 GMT
Ok, here's some data.  The test machine is running solaris 2.5.1 and has
two processors: 

cpu0: SUNW,UltraSPARC (upaid 0 impl 0x10 ver 0x40 clock 168 MHz)
cpu1: SUNW,UltraSPARC (upaid 1 impl 0x10 ver 0x22 clock 168 MHz)

The timing program is below.  I timed fcntl, sysv semaphores, and posix
mutexes (posix pthread mutexes apply to processes as well as threads, so
say the docs). 

I ran 10 children, with varying numbers of iterations.  And the
lock/unlock op times averaged out to:

fcntl 45 us
sysv  25 us
posix 1.5 us

And to make things even better, the posix stuff has far fewer gotchas than
sysv semaphores.  Essentially no gotchas, it just takes a mmap(). 

Linux pthreads don't seem to implement inter-process locking (or I screwed
up trying to get the right type of shared memory).  But for the other
three types, sysv is the slowest, then fcntl, and flock is the fastest. We
currently use fcntl on linux, switching to flock would be a nice thing. 

Someone want to time FreeBSD, or anything else that warrants it for that
matter. 

Dean

/*
time-sem.c:

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>

#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;

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

void accept_mutex_on()
{
    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);
    }
}

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



Mime
View raw message