diff options
author | Ted Unangst <tedu@cvs.openbsd.org> | 2005-12-03 18:16:20 +0000 |
---|---|---|
committer | Ted Unangst <tedu@cvs.openbsd.org> | 2005-12-03 18:16:20 +0000 |
commit | f8598074c9df8821312f2c4a7cea9ba772625f82 (patch) | |
tree | 919fd1834c7d3b53c19dbfd42833240e246d4d45 /lib/librthread/rthread_sync.c | |
parent | e9242d9ec62b39f3a6284080e22c1dc917876df5 (diff) |
add userland thread library. incomplete, but functional
Diffstat (limited to 'lib/librthread/rthread_sync.c')
-rw-r--r-- | lib/librthread/rthread_sync.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/lib/librthread/rthread_sync.c b/lib/librthread/rthread_sync.c new file mode 100644 index 00000000000..a2d7faf01cd --- /dev/null +++ b/lib/librthread/rthread_sync.c @@ -0,0 +1,477 @@ +/* $OpenBSD: rthread_sync.c,v 1.1 2005/12/03 18:16:19 tedu Exp $ */ +/* + * Copyright (c) 2004 Ted Unangst <tedu@openbsd.org> + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Mutexes, conditions, rwlocks, and semaphores - synchronization functions. + */ + + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <machine/spinlock.h> + +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <pthread.h> + +#include "rthread.h" + +int thrsleep(long, int, void *); +int thrwakeup(long); + +/* + * Internal implementation of semaphores + */ +int +_sem_wait(sem_t sem, int tryonly, int timo) +{ + int sleep; + + _spinlock(&sem->lock); +again: + if (sem->value == 0) { + if (tryonly) { + _spinunlock(&sem->lock); + return (0); + } + sem->waitcount++; + sleep = 1; + } else { + sem->value--; + sleep = 0; + } + + if (sleep) { + if (thrsleep((long)sem, timo, &sem->lock) == EWOULDBLOCK) + return (0); + _spinlock(&sem->lock); + sem->waitcount--; + goto again; + } + _spinunlock(&sem->lock); + return (1); +} + +int +_sem_wakeup(sem_t sem) +{ + int rv = 0; + + _spinlock(&sem->lock); + sem->value++; + if (sem->waitcount) { + thrwakeup((long)sem); + rv = 1; + } + _spinunlock(&sem->lock); + return (rv); +} + +int +_sem_wakeall(sem_t sem) +{ + int rv; + + _spinlock(&sem->lock); + rv = sem->waitcount; + sem->value += rv; + thrwakeup((long)sem); + _spinunlock(&sem->lock); + + return (rv); +} + +/* + * mutexen + */ +int +pthread_mutex_init(pthread_mutex_t *mutexp, const pthread_mutexattr_t *attr) +{ + pthread_mutex_t mutex; + + mutex = malloc(sizeof(*mutex)); + if (!mutex) + return (errno); + memset((void *)mutex, 0, sizeof(*mutex)); + mutex->sem.value = 1; /* unlocked */ + mutex->type = attr ? (*attr)->type : PTHREAD_MUTEX_ERRORCHECK; + *mutexp = mutex; + + return (0); +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutexp) +{ + + /* check for waiters */ + free((void *)*mutexp); + *mutexp = NULL; + return (0); +} + +int +rthread_mutex_lock(pthread_mutex_t *mutexp, int trywait) +{ + pthread_mutex_t mutex = *mutexp; + pthread_t thread = pthread_self(); + + if (!mutex) { + pthread_mutex_init(mutexp, NULL); + mutex = *mutexp; + } + if (mutex->owner == thread) { + if (mutex->type == PTHREAD_MUTEX_RECURSIVE) { + mutex->count++; + return (0); + } + if (mutex->type == PTHREAD_MUTEX_ERRORCHECK) + return (EDEADLK); + } + if (!_sem_wait((void *)&mutex->sem, trywait, 0)) + return (EBUSY); + mutex->owner = thread; + mutex->count = 1; + + return (0); +} + +int +pthread_mutex_lock(pthread_mutex_t *p) +{ + return (rthread_mutex_lock(p, 0)); +} + +int +pthread_mutex_trylock(pthread_mutex_t *p) +{ + return (rthread_mutex_lock(p, 1)); +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutexp) +{ + pthread_t thread = pthread_self(); + pthread_mutex_t mutex = *mutexp; + + if (mutex->owner != thread) + return (EPERM); + + if (--mutex->count == 0) { + mutex->owner = NULL; + _sem_wakeup((void *)&mutex->sem); + } + + return (0); +} + +/* + * mutexen attributes + */ +int +pthread_mutexattr_init(pthread_mutexattr_t *attrp) +{ + pthread_mutexattr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + attr->type = PTHREAD_MUTEX_ERRORCHECK; + *attrp = attr; + + return (0); +} + +int +pthread_mutexattr_destroy(pthread_mutexattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +int +pthread_mutexattr_settype(pthread_mutexattr_t *attrp, int type) +{ + (*attrp)->type = type; + + return (0); +} + +/* + * condition variables + */ +int +pthread_cond_init(pthread_cond_t *condp, const pthread_condattr_t *attrp) +{ + pthread_cond_t cond; + + cond = malloc(sizeof(*cond)); + if (!cond) + return (errno); + memset(cond, 0, sizeof(*cond)); + + *condp = cond; + + return (0); +} + +int +pthread_cond_destroy(pthread_cond_t *condp) +{ + + free(*condp); + *condp = NULL; + + return (0); +} + +int +pthread_cond_timedwait(pthread_cond_t *condp, pthread_mutex_t *mutexp, + const struct timespec *abstime) +{ + int error; + + if (!*condp) + if ((error = pthread_cond_init(condp, NULL))) + return (error); + + pthread_mutex_unlock(mutexp); + _sem_wait(&(*condp)->sem, 0, (abstime ? + abstime->tv_sec * 100 + abstime->tv_nsec / 10000000 : 0)); + error = pthread_mutex_lock(mutexp); + + return (error); +} + +int +pthread_cond_wait(pthread_cond_t *condp, pthread_mutex_t *mutexp) +{ + return (pthread_cond_timedwait(condp, mutexp, NULL)); +} + +int +pthread_cond_signal(pthread_cond_t *condp) +{ + int error; + + if (!*condp) + if ((error = pthread_cond_init(condp, NULL))) + return (error); + + _sem_wakeup(&(*condp)->sem); + + return (0); +} + +int +pthread_cond_broadcast(pthread_cond_t *condp) +{ + if (!*condp) + pthread_cond_init(condp, NULL); + + _sem_wakeall(&(*condp)->sem); + + return (0); +} + +/* + * condition variable attributes + */ +int +pthread_condattr_init(pthread_condattr_t *attrp) +{ + pthread_condattr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + *attrp = attr; + + return (0); +} + +int +pthread_condattr_destroy(pthread_condattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} + +/* + * rwlocks + */ +int +pthread_rwlock_init(pthread_rwlock_t *lockp, const pthread_rwlockattr_t *attrp) +{ + pthread_rwlock_t lock; + + lock = malloc(sizeof(*lock)); + if (!lock) + return (errno); + memset(lock, 0, sizeof(*lock)); + *lockp = lock; + + return (0); +} + +int +pthread_rwlock_destroy(pthread_rwlock_t *lockp) +{ + free(*lockp); + *lockp = NULL; + + return (0); +} + +int +pthread_rwlock_rdlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; +again: + _spinlock(&lock->lock); + if (lock->writer) { + _spinunlock(&lock->lock); + _sem_wait(&lock->sem, 0, 0); + goto again; + } + lock->readers++; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_tryrdlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + + _spinlock(&lock->lock); + if (lock->writer) { + _spinunlock(&lock->lock); + return (EBUSY); + } + lock->readers++; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_wrlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + +again: + _spinlock(&lock->lock); + lock->writer++; + if (lock->readers) { + _spinunlock(&lock->lock); + _sem_wait(&lock->sem, 0, 0); + goto again; + } + lock->readers = -pthread_self()->tid; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_trywrlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + + _spinlock(&lock->lock); + if (lock->readers || lock->writer) { + _spinunlock(&lock->lock); + return (EBUSY); + } + lock->writer = 1; + lock->readers = -pthread_self()->tid; + _spinunlock(&lock->lock); + + return (0); +} + +int +pthread_rwlock_unlock(pthread_rwlock_t *lockp) +{ + pthread_rwlock_t lock; + + lock = *lockp; + + _spinlock(&lock->lock); + if (lock->readers == -pthread_self()->tid) { + lock->readers = 0; + lock->writer--; + } else if (lock->readers > 0) { + lock->readers--; + } else { + _spinunlock(&lock->lock); + return (EPERM); + } + _spinunlock(&lock->lock); + _sem_wakeall(&lock->sem); + + return (0); +} + +/* + * rwlock attributes + */ +int +pthread_rwlockattr_init(pthread_rwlockattr_t *attrp) +{ + pthread_rwlockattr_t attr; + + attr = malloc(sizeof(*attr)); + if (!attr) + return (errno); + memset(attr, 0, sizeof(*attr)); + *attrp = attr; + + return (0); +} + +int +pthread_rwlockattr_destory(pthread_rwlockattr_t *attrp) +{ + free(*attrp); + *attrp = NULL; + + return (0); +} |