Blame test/time-sem.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
time-sem.c has the basics of the semaphores we use in http_main.c.  It's
Packit 90a5c9
intended for timing differences between various methods on an
Packit 90a5c9
architecture.  In practice we've found many things affect which semaphore
Packit 90a5c9
to be used:
Packit 90a5c9
Packit 90a5c9
    - NFS filesystems absolutely suck for fcntl() and flock()
Packit 90a5c9
Packit 90a5c9
    - uslock absolutely sucks on single-processor IRIX boxes, but
Packit 90a5c9
        absolutely rocks on multi-processor boxes.  The converse
Packit 90a5c9
        is true for fcntl.  sysvsem seems a moderate balance.
Packit 90a5c9
Packit 90a5c9
    - Under Solaris you can't have too many processes use SEM_UNDO, there
Packit 90a5c9
        might be a tuneable somewhere that increases the limit from 29.
Packit 90a5c9
        We're not sure what the tunable is, so there's a define
Packit 90a5c9
        NO_SEM_UNDO which can be used to simulate us trapping/blocking
Packit 90a5c9
        signals to be able to properly release the semaphore on a clean
Packit 90a5c9
        child death.  You'll also need to define NEED_UNION_SEMUN
Packit 90a5c9
        under solaris.
Packit 90a5c9
Packit 90a5c9
You'll need to define USE_SHMGET_SCOREBOARD if anonymous shared mmap()
Packit 90a5c9
doesn't work on your system (i.e. linux).
Packit 90a5c9
Packit 90a5c9
argv[1] is the #children, argv[2] is the #iterations per child
Packit 90a5c9
Packit 90a5c9
You should run each over many different #children inputs, and choose
Packit 90a5c9
#iter such that the program runs for at least a second or so... or even
Packit 90a5c9
longer depending on your patience.
Packit 90a5c9
Packit 90a5c9
compile with:
Packit 90a5c9
Packit 90a5c9
gcc -o time-FCNTL -Wall -O time-sem.c -DUSE_FCNTL_SERIALIZED_ACCEPT
Packit 90a5c9
gcc -o time-FLOCK -Wall -O time-sem.c -DUSE_FLOCK_SERIALIZED_ACCEPT
Packit 90a5c9
gcc -o time-SYSVSEM -Wall -O time-sem.c -DUSE_SYSVSEM_SERIALIZED_ACCEPT
Packit 90a5c9
gcc -o time-SYSVSEM2 -Wall -O time-sem.c -DUSE_SYSVSEM_SERIALIZED_ACCEPT -DNO_SEM_UNDO
Packit 90a5c9
gcc -o time-PTHREAD -Wall -O time-sem.c -DUSE_PTHREAD_SERIALIZED_ACCEPT -lpthread
Packit 90a5c9
gcc -o time-USLOCK -Wall -O time-sem.c -DUSE_USLOCK_SERIALIZED_ACCEPT
Packit 90a5c9
Packit 90a5c9
not all versions work on all systems.
Packit 90a5c9
*/
Packit 90a5c9
Packit 90a5c9
#include <errno.h>
Packit 90a5c9
#include <sys/time.h>
Packit 90a5c9
#include <unistd.h>
Packit 90a5c9
#include <stdio.h>
Packit 90a5c9
#include <string.h>
Packit 90a5c9
#include <stdlib.h>
Packit 90a5c9
#include <sys/types.h>
Packit 90a5c9
#include <sys/stat.h>
Packit 90a5c9
#include <fcntl.h>
Packit 90a5c9
#include <sys/wait.h>
Packit 90a5c9
#include <sys/mman.h>
Packit 90a5c9
#include <signal.h>
Packit 90a5c9
Packit 90a5c9
#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
Packit 90a5c9
Packit 90a5c9
static struct flock lock_it;
Packit 90a5c9
static struct flock unlock_it;
Packit 90a5c9
Packit 90a5c9
static int fcntl_fd=-1;
Packit 90a5c9
Packit 90a5c9
#define accept_mutex_child_init()
Packit 90a5c9
#define accept_mutex_cleanup()
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Initialize mutex lock.
Packit 90a5c9
 * Must be safe to call this on a restart.
Packit 90a5c9
 */
Packit 90a5c9
void
Packit 90a5c9
accept_mutex_init(void)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    lock_it.l_whence = SEEK_SET;   /* from current point */
Packit 90a5c9
    lock_it.l_start  = 0;          /* -"- */
Packit 90a5c9
    lock_it.l_len    = 0;          /* until end of file */
Packit 90a5c9
    lock_it.l_type   = F_WRLCK;    /* set exclusive/write lock */
Packit 90a5c9
    lock_it.l_pid    = 0;          /* pid not actually interesting */
Packit 90a5c9
    unlock_it.l_whence = SEEK_SET; /* from current point */
Packit 90a5c9
    unlock_it.l_start  = 0;        /* -"- */
Packit 90a5c9
    unlock_it.l_len    = 0;        /* until end of file */
Packit 90a5c9
    unlock_it.l_type   = F_UNLCK;  /* set exclusive/write lock */
Packit 90a5c9
    unlock_it.l_pid    = 0;        /* pid not actually interesting */
Packit 90a5c9
Packit 90a5c9
    printf("opening test-lock-thing in current directory\n");
Packit 90a5c9
    fcntl_fd = open("test-lock-thing", O_CREAT | O_WRONLY | O_EXCL, 0644);
Packit 90a5c9
    if (fcntl_fd == -1)
Packit 90a5c9
    {
Packit 90a5c9
        perror ("open");
Packit 90a5c9
        fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    unlink("test-lock-thing");
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_on(void)
Packit 90a5c9
{
Packit 90a5c9
    int ret;
Packit 90a5c9
Packit 90a5c9
    while ((ret = fcntl(fcntl_fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR)
Packit 90a5c9
        continue;
Packit 90a5c9
Packit 90a5c9
    if (ret < 0) {
Packit 90a5c9
        perror ("fcntl lock_it");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_off(void)
Packit 90a5c9
{
Packit 90a5c9
    if (fcntl (fcntl_fd, F_SETLKW, &unlock_it) < 0)
Packit 90a5c9
    {
Packit 90a5c9
        perror ("fcntl unlock_it");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#elif defined(USE_FLOCK_SERIALIZED_ACCEPT)
Packit 90a5c9
Packit 90a5c9
#include <sys/file.h>
Packit 90a5c9
Packit 90a5c9
static int flock_fd=-1;
Packit 90a5c9
Packit 90a5c9
#define FNAME "test-lock-thing"
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Initialize mutex lock.
Packit 90a5c9
 * Must be safe to call this on a restart.
Packit 90a5c9
 */
Packit 90a5c9
void accept_mutex_init(void)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
    printf("opening " FNAME " in current directory\n");
Packit 90a5c9
    flock_fd = open(FNAME, O_CREAT | O_WRONLY | O_EXCL, 0644);
Packit 90a5c9
    if (flock_fd == -1)
Packit 90a5c9
    {
Packit 90a5c9
        perror ("open");
Packit 90a5c9
        fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_child_init(void)
Packit 90a5c9
{
Packit 90a5c9
    flock_fd = open(FNAME, O_WRONLY, 0600);
Packit 90a5c9
    if (flock_fd == -1) {
Packit 90a5c9
        perror("open");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_cleanup(void)
Packit 90a5c9
{
Packit 90a5c9
    unlink(FNAME);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_on(void)
Packit 90a5c9
{
Packit 90a5c9
    int ret;
Packit 90a5c9
Packit 90a5c9
    while ((ret = flock(flock_fd, LOCK_EX)) < 0 && errno == EINTR)
Packit 90a5c9
        continue;
Packit 90a5c9
Packit 90a5c9
    if (ret < 0) {
Packit 90a5c9
        perror ("flock(LOCK_EX)");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_off(void)
Packit 90a5c9
{
Packit 90a5c9
    if (flock (flock_fd, LOCK_UN) < 0)
Packit 90a5c9
    {
Packit 90a5c9
        perror ("flock(LOCK_UN)");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#elif defined (USE_SYSVSEM_SERIALIZED_ACCEPT)
Packit 90a5c9
Packit 90a5c9
#include <sys/types.h>
Packit 90a5c9
#include <sys/ipc.h>
Packit 90a5c9
#include <sys/sem.h>
Packit 90a5c9
Packit 90a5c9
static   int sem_id = -1;
Packit 90a5c9
#ifdef NO_SEM_UNDO
Packit 90a5c9
static sigset_t accept_block_mask;
Packit 90a5c9
static sigset_t accept_previous_mask;
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#define accept_mutex_child_init()
Packit 90a5c9
#define accept_mutex_cleanup()
Packit 90a5c9
Packit 90a5c9
void accept_mutex_init(void)
Packit 90a5c9
{
Packit 90a5c9
#ifdef NEED_UNION_SEMUN
Packit 90a5c9
    /* believe it or not, you need to define this under solaris */
Packit 90a5c9
    union semun {
Packit 90a5c9
        int val;
Packit 90a5c9
        struct semid_ds *buf;
Packit 90a5c9
        ushort *array;
Packit 90a5c9
    };
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    union semun ick;
Packit 90a5c9
Packit 90a5c9
    sem_id = semget(999, 1, IPC_CREAT | 0666);
Packit 90a5c9
    if (sem_id < 0) {
Packit 90a5c9
       perror ("semget");
Packit 90a5c9
       exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    ick.val = 1;
Packit 90a5c9
    if (semctl(sem_id, 0, SETVAL, ick) < 0) {
Packit 90a5c9
       perror ("semctl");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
#ifdef NO_SEM_UNDO
Packit 90a5c9
    sigfillset(&accept_block_mask);
Packit 90a5c9
    sigdelset(&accept_block_mask, SIGHUP);
Packit 90a5c9
    sigdelset(&accept_block_mask, SIGTERM);
Packit 90a5c9
    sigdelset(&accept_block_mask, SIGUSR1);
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_on()
Packit 90a5c9
{
Packit 90a5c9
    struct sembuf op;
Packit 90a5c9
Packit 90a5c9
#ifdef NO_SEM_UNDO
Packit 90a5c9
    if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) {
Packit 90a5c9
        perror("sigprocmask(SIG_BLOCK)");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    op.sem_flg = 0;
Packit 90a5c9
#else
Packit 90a5c9
    op.sem_flg = SEM_UNDO;
Packit 90a5c9
#endif
Packit 90a5c9
    op.sem_num = 0;
Packit 90a5c9
    op.sem_op  = -1;
Packit 90a5c9
    if (semop(sem_id, &op, 1) < 0) {
Packit 90a5c9
        perror ("accept_mutex_on");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_off()
Packit 90a5c9
{
Packit 90a5c9
    struct sembuf op;
Packit 90a5c9
Packit 90a5c9
    op.sem_num = 0;
Packit 90a5c9
    op.sem_op  = 1;
Packit 90a5c9
#ifdef NO_SEM_UNDO
Packit 90a5c9
    op.sem_flg = 0;
Packit 90a5c9
#else
Packit 90a5c9
    op.sem_flg = SEM_UNDO;
Packit 90a5c9
#endif
Packit 90a5c9
    if (semop(sem_id, &op, 1) < 0) {
Packit 90a5c9
        perror ("accept_mutex_off");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
#ifdef NO_SEM_UNDO
Packit 90a5c9
    if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) {
Packit 90a5c9
        perror("sigprocmask(SIG_SETMASK)");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#elif defined (USE_PTHREAD_SERIALIZED_ACCEPT)
Packit 90a5c9
Packit 90a5c9
/* note: pthread mutexes aren't released on child death, hence the
Packit 90a5c9
 * signal goop ... in a real implementation we'd do special things
Packit 90a5c9
 * during hup, term, usr1.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include <pthread.h>
Packit 90a5c9
Packit 90a5c9
static pthread_mutex_t *mutex;
Packit 90a5c9
static sigset_t accept_block_mask;
Packit 90a5c9
static sigset_t accept_previous_mask;
Packit 90a5c9
Packit 90a5c9
#define accept_mutex_child_init()
Packit 90a5c9
#define accept_mutex_cleanup()
Packit 90a5c9
Packit 90a5c9
void accept_mutex_init(void)
Packit 90a5c9
{
Packit 90a5c9
    pthread_mutexattr_t mattr;
Packit 90a5c9
    int fd;
Packit 90a5c9
Packit 90a5c9
    fd = open ("/dev/zero", O_RDWR);
Packit 90a5c9
    if (fd == -1) {
Packit 90a5c9
        perror ("open(/dev/zero)");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    mutex = (pthread_mutex_t *)mmap ((caddr_t)0, sizeof (*mutex),
Packit 90a5c9
                    PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
Packit 90a5c9
    if (mutex == (void *)(caddr_t)-1) {
Packit 90a5c9
        perror ("mmap");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    close (fd);
Packit 90a5c9
    if (pthread_mutexattr_init(&mattr)) {
Packit 90a5c9
        perror ("pthread_mutexattr_init");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) {
Packit 90a5c9
        perror ("pthread_mutexattr_setpshared");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    if (pthread_mutex_init(mutex, &mattr)) {
Packit 90a5c9
        perror ("pthread_mutex_init");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    sigfillset(&accept_block_mask);
Packit 90a5c9
    sigdelset(&accept_block_mask, SIGHUP);
Packit 90a5c9
    sigdelset(&accept_block_mask, SIGTERM);
Packit 90a5c9
    sigdelset(&accept_block_mask, SIGUSR1);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_on()
Packit 90a5c9
{
Packit 90a5c9
    if (sigprocmask(SIG_BLOCK, &accept_block_mask, &accept_previous_mask)) {
Packit 90a5c9
        perror("sigprocmask(SIG_BLOCK)");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    if (pthread_mutex_lock (mutex)) {
Packit 90a5c9
        perror ("pthread_mutex_lock");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
void accept_mutex_off()
Packit 90a5c9
{
Packit 90a5c9
    if (pthread_mutex_unlock (mutex)) {
Packit 90a5c9
        perror ("pthread_mutex_unlock");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    if (sigprocmask(SIG_SETMASK, &accept_previous_mask, NULL)) {
Packit 90a5c9
        perror("sigprocmask(SIG_SETMASK)");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#elif defined (USE_USLOCK_SERIALIZED_ACCEPT)
Packit 90a5c9
Packit 90a5c9
#include <ulocks.h>
Packit 90a5c9
Packit 90a5c9
static usptr_t *us = NULL;
Packit 90a5c9
static ulock_t uslock = NULL;
Packit 90a5c9
Packit 90a5c9
#define accept_mutex_child_init()
Packit 90a5c9
#define accept_mutex_cleanup()
Packit 90a5c9
Packit 90a5c9
void accept_mutex_init(void)
Packit 90a5c9
{
Packit 90a5c9
    ptrdiff_t old;
Packit 90a5c9
    /* default is 8 */
Packit 90a5c9
#define CONF_INITUSERS_MAX 15
Packit 90a5c9
    if ((old = usconfig(CONF_INITUSERS, CONF_INITUSERS_MAX)) == -1) {
Packit 90a5c9
        perror("usconfig");
Packit 90a5c9
        exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
    if ((old = usconfig(CONF_LOCKTYPE, US_NODEBUG)) == -1) {
Packit 90a5c9
        perror("usconfig");
Packit 90a5c9
        exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
    if ((old = usconfig(CONF_ARENATYPE, US_SHAREDONLY)) == -1) {
Packit 90a5c9
        perror("usconfig");
Packit 90a5c9
        exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
    if ((us = usinit("/dev/zero")) == NULL) {
Packit 90a5c9
        perror("usinit");
Packit 90a5c9
        exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
    if ((uslock = usnewlock(us)) == NULL) {
Packit 90a5c9
        perror("usnewlock");
Packit 90a5c9
        exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
void accept_mutex_on()
Packit 90a5c9
{
Packit 90a5c9
    switch(ussetlock(uslock)) {
Packit 90a5c9
        case 1:
Packit 90a5c9
            /* got lock */
Packit 90a5c9
            break;
Packit 90a5c9
        case 0:
Packit 90a5c9
            fprintf(stderr, "didn't get lock\n");
Packit 90a5c9
            exit(-1);
Packit 90a5c9
        case -1:
Packit 90a5c9
            perror("ussetlock");
Packit 90a5c9
            exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
void accept_mutex_off()
Packit 90a5c9
{
Packit 90a5c9
    if (usunsetlock(uslock) == -1) {
Packit 90a5c9
        perror("usunsetlock");
Packit 90a5c9
        exit(-1);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
#ifndef USE_SHMGET_SCOREBOARD
Packit 90a5c9
static void *get_shared_mem(apr_size_t size)
Packit 90a5c9
{
Packit 90a5c9
    void *result;
Packit 90a5c9
Packit 90a5c9
    /* allocate shared memory for the shared_counter */
Packit 90a5c9
    result = (unsigned long *)mmap ((caddr_t)0, size,
Packit 90a5c9
                    PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
Packit 90a5c9
    if (result == (void *)(caddr_t)-1) {
Packit 90a5c9
        perror ("mmap");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
#else
Packit 90a5c9
#include <sys/types.h>
Packit 90a5c9
#include <sys/ipc.h>
Packit 90a5c9
#ifdef HAVE_SYS_MUTEX_H
Packit 90a5c9
#include <sys/mutex.h>
Packit 90a5c9
#endif
Packit 90a5c9
#include <sys/shm.h>
Packit 90a5c9
Packit 90a5c9
static void *get_shared_mem(apr_size_t size)
Packit 90a5c9
{
Packit 90a5c9
    key_t shmkey = IPC_PRIVATE;
Packit 90a5c9
    int shmid = -1;
Packit 90a5c9
    void *result;
Packit 90a5c9
#ifdef MOVEBREAK
Packit 90a5c9
    char *obrk;
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
    if ((shmid = shmget(shmkey, size, IPC_CREAT | SHM_R | SHM_W)) == -1) {
Packit 90a5c9
        perror("shmget");
Packit 90a5c9
        exit(1);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
#ifdef MOVEBREAK
Packit 90a5c9
    /*
Packit 90a5c9
     * Some SysV systems place the shared segment WAY too close
Packit 90a5c9
     * to the dynamic memory break point (sbrk(0)). This severely
Packit 90a5c9
     * limits the use of malloc/sbrk in the program since sbrk will
Packit 90a5c9
     * refuse to move past that point.
Packit 90a5c9
     *
Packit 90a5c9
     * To get around this, we move the break point "way up there",
Packit 90a5c9
     * attach the segment and then move break back down. Ugly
Packit 90a5c9
     */
Packit 90a5c9
    if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) {
Packit 90a5c9
        perror("sbrk");
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#define BADSHMAT  ((void *)(-1))
Packit 90a5c9
    if ((result = shmat(shmid, 0, 0)) == BADSHMAT) {
Packit 90a5c9
        perror("shmat");
Packit 90a5c9
    }
Packit 90a5c9
    /*
Packit 90a5c9
     * We must avoid leaving segments in the kernel's
Packit 90a5c9
     * (small) tables.
Packit 90a5c9
     */
Packit 90a5c9
    if (shmctl(shmid, IPC_RMID, NULL) != 0) {
Packit 90a5c9
        perror("shmctl(IPC_RMID)");
Packit 90a5c9
    }
Packit 90a5c9
    if (result == BADSHMAT)  /* now bailout */
Packit 90a5c9
        exit(1);
Packit 90a5c9
Packit 90a5c9
#ifdef MOVEBREAK
Packit 90a5c9
    if (obrk == (char *) -1)
Packit 90a5c9
        return;  /* nothing else to do */
Packit 90a5c9
    if (sbrk(-(MOVEBREAK)) == (char *) -1) {
Packit 90a5c9
        perror("sbrk 2");
Packit 90a5c9
    }
Packit 90a5c9
#endif
Packit 90a5c9
    return result;
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
#ifdef _POSIX_PRIORITY_SCHEDULING
Packit 90a5c9
/* don't ask */
Packit 90a5c9
#define _P __P
Packit 90a5c9
#include <sched.h>
Packit 90a5c9
#define YIELD  sched_yield()
Packit 90a5c9
#else
Packit 90a5c9
#define YIELD  do { struct timeval zero; zero.tv_sec = zero.tv_usec = 0; select(0,0,0,0,&zero); } while(0)
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
void main (int argc, char **argv)
Packit 90a5c9
{
Packit 90a5c9
    int num_iter;
Packit 90a5c9
    int num_child;
Packit 90a5c9
    int i;
Packit 90a5c9
    struct timeval first;
Packit 90a5c9
    struct timeval last;
Packit 90a5c9
    long ms;
Packit 90a5c9
    int pid;
Packit 90a5c9
    unsigned long *shared_counter;
Packit 90a5c9
Packit 90a5c9
    if (argc != 3) {
Packit 90a5c9
        fprintf (stderr, "Usage: time-sem num-child num iter\n");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    num_child = atoi (argv[1]);
Packit 90a5c9
    num_iter = atoi (argv[2]);
Packit 90a5c9
Packit 90a5c9
    /* allocate shared memory for the shared_counter */
Packit 90a5c9
    shared_counter = get_shared_mem(sizeof(*shared_counter));
Packit 90a5c9
Packit 90a5c9
    /* initialize counter to 0 */
Packit 90a5c9
    *shared_counter = 0;
Packit 90a5c9
Packit 90a5c9
    accept_mutex_init ();
Packit 90a5c9
Packit 90a5c9
    /* parent grabs mutex until done spawning children */
Packit 90a5c9
    accept_mutex_on ();
Packit 90a5c9
Packit 90a5c9
    for (i = 0; i < num_child; ++i) {
Packit 90a5c9
        pid = fork();
Packit 90a5c9
        if (pid == 0) {
Packit 90a5c9
            /* child, do our thing */
Packit 90a5c9
            accept_mutex_child_init();
Packit 90a5c9
            for (i = 0; i < num_iter; ++i) {
Packit 90a5c9
                unsigned long tmp;
Packit 90a5c9
Packit 90a5c9
                accept_mutex_on ();
Packit 90a5c9
                tmp = *shared_counter;
Packit 90a5c9
                YIELD;
Packit 90a5c9
                *shared_counter = tmp + 1;
Packit 90a5c9
                accept_mutex_off ();
Packit 90a5c9
            }
Packit 90a5c9
            exit (0);
Packit 90a5c9
        } else if (pid == -1) {
Packit 90a5c9
            perror ("fork");
Packit 90a5c9
            exit (1);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* a quick test to see that nothing is screwed up */
Packit 90a5c9
    if (*shared_counter != 0) {
Packit 90a5c9
        puts ("WTF! shared_counter != 0 before the children have been started!");
Packit 90a5c9
        exit (1);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    gettimeofday (&first, NULL);
Packit 90a5c9
    /* launch children into action */
Packit 90a5c9
    accept_mutex_off ();
Packit 90a5c9
    for (i = 0; i < num_child; ++i) {
Packit 90a5c9
        if (wait(NULL) == -1) {
Packit 90a5c9
            perror ("wait");
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    gettimeofday (&last, NULL);
Packit 90a5c9
Packit 90a5c9
    if (*shared_counter != num_child * num_iter) {
Packit 90a5c9
        printf ("WTF! shared_counter != num_child * num_iter!\n"
Packit 90a5c9
                "shared_counter = %lu\nnum_child = %d\nnum_iter=%d\n",
Packit 90a5c9
                *shared_counter,
Packit 90a5c9
                num_child, num_iter);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    last.tv_sec -= first.tv_sec;
Packit 90a5c9
    ms = last.tv_usec - first.tv_usec;
Packit 90a5c9
    if (ms < 0) {
Packit 90a5c9
        --last.tv_sec;
Packit 90a5c9
        ms += 1000000;
Packit 90a5c9
    }
Packit 90a5c9
    last.tv_usec = ms;
Packit 90a5c9
    printf ("%8lu.%06lu\n", last.tv_sec, last.tv_usec);
Packit 90a5c9
Packit 90a5c9
    accept_mutex_cleanup();
Packit 90a5c9
Packit 90a5c9
    exit(0);
Packit 90a5c9
}
Packit 90a5c9