Add code to support pthread spin lock.

Reviewed by: deischen
This commit is contained in:
David Xu 2003-09-09 06:57:51 +00:00
parent 5b80c0d74d
commit c095b4a999
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=119909
8 changed files with 339 additions and 0 deletions

View File

@ -98,6 +98,7 @@ struct pthread_rwlock;
struct pthread_rwlockattr;
struct pthread_barrier;
struct pthread_barrier_attr;
struct pthread_spinlock;
/*
* Primitive system data type definitions required by P1003.1c.
@ -118,6 +119,7 @@ typedef struct pthread_rwlock *pthread_rwlock_t;
typedef struct pthread_rwlockattr *pthread_rwlockattr_t;
typedef struct pthread_barrier *pthread_barrier_t;
typedef struct pthread_barrierattr *pthread_barrierattr_t;
typedef struct pthread_spinlock *pthread_spinlock_t;
/*
* Additional type definitions:
@ -275,6 +277,11 @@ pthread_t pthread_self(void);
int pthread_setspecific(pthread_key_t, const void *);
int pthread_sigmask(int, const sigset_t *, sigset_t *);
int pthread_spin_init(pthread_spinlock_t *, int);
int pthread_spin_destroy(pthread_spinlock_t *);
int pthread_spin_lock(pthread_spinlock_t *);
int pthread_spin_trylock(pthread_spinlock_t *);
int pthread_spin_unlock(pthread_spinlock_t *);
int pthread_cancel(pthread_t);
int pthread_setcancelstate(int, int *);
int pthread_setcanceltype(int, int *);

View File

@ -70,6 +70,7 @@ SRCS+= \
thr_printf.c \
thr_priority_queue.c \
thr_pselect.c \
thr_pspinlock.c \
thr_raise.c \
thr_read.c \
thr_readv.c \

View File

@ -402,6 +402,11 @@ struct pthread_barrierattr {
int pshared;
};
struct pthread_spinlock {
volatile int s_lock;
pthread_t s_owner;
};
/*
* Flags for condition variables.
*/
@ -1093,6 +1098,7 @@ int _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
int _pthread_rwlock_destroy (pthread_rwlock_t *);
struct pthread *_pthread_self(void);
int _pthread_setspecific(pthread_key_t, const void *);
void _pthread_yield(void);
struct pthread *_thr_alloc(struct pthread *);
void _thr_exit(char *, int, char *);
void _thr_exit_cleanup(void);

View File

@ -0,0 +1,154 @@
/*-
* Copyright (c) 2003 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <atomic_ops.h>
#include "thr_private.h"
#define SPIN_COUNT 10000
int
pthread_spin_init(pthread_spinlock_t *lock, int pshared)
{
struct pthread_spinlock *lck;
int ret;
if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
ret = EINVAL;
else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
ret = ENOMEM;
else {
lck->s_lock = 0;
lck->s_owner= NULL;
*lock = lck;
ret = 0;
}
return (ret);
}
int
pthread_spin_destroy(pthread_spinlock_t *lock)
{
int ret;
if (lock == NULL || *lock == NULL)
ret = EINVAL;
else if ((*lock)->s_owner != NULL)
ret = EBUSY;
else {
free(*lock);
*lock = NULL;
ret = 0;
}
return (ret);
}
int
pthread_spin_trylock(pthread_spinlock_t *lock)
{
struct pthread_spinlock *lck;
struct pthread *self = _pthread_self();
int oldval, ret;
if (lock == NULL || (lck = *lock) == NULL)
ret = EINVAL;
else if (lck->s_owner == self)
ret = EDEADLK;
else if (lck->s_lock != 0)
ret = EBUSY;
else {
atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
if (oldval)
ret = EBUSY;
else {
lck->s_owner = _pthread_self();
ret = 0;
}
}
return (ret);
}
int
pthread_spin_lock(pthread_spinlock_t *lock)
{
struct pthread_spinlock *lck;
struct pthread *self = _pthread_self();
int count, oldval, ret;
if (lock == NULL || (lck = *lock) == NULL)
ret = EINVAL;
else if (lck->s_owner == self)
ret = EDEADLK;
else {
do {
count = SPIN_COUNT;
while (lck->s_lock) {
#ifdef __i386__
/* tell cpu we are spinning */
__asm __volatile("pause");
#endif
if (--count <= 0) {
count = SPIN_COUNT;
_pthread_yield();
}
}
atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
} while (oldval);
lck->s_owner = self;
ret = 0;
}
return (ret);
}
int
pthread_spin_unlock(pthread_spinlock_t *lock)
{
struct pthread_spinlock *lck;
int ret;
if (lock == NULL || (lck = *lock) == NULL)
ret = EINVAL;
else {
if (lck->s_owner != _pthread_self())
ret = EPERM;
else {
lck->s_owner = NULL;
atomic_swap_int((int *)&lck->s_lock, 0, &ret);
ret = 0;
}
}
return (ret);
}

View File

@ -128,6 +128,11 @@ global:
_pthread_setspecific;
_pthread_sigmask;
_pthread_single_np;
_pthread_spin_destroy;
_pthread_spin_init;
_pthread_spin_lock;
_pthread_spin_trylock;
_pthread_spin_unlock;
_pthread_suspend_all_np;
_pthread_suspend_np;
_pthread_switch_add_np;
@ -271,6 +276,11 @@ global:
pthread_setspecific;
pthread_sigmask;
pthread_single_np;
pthread_spin_destroy;
pthread_spin_init;
pthread_spin_lock;
pthread_spin_trylock;
pthread_spin_unlock;
pthread_suspend_all_np;
pthread_suspend_np;
pthread_switch_add_np;

View File

@ -70,6 +70,7 @@ SRCS+= \
thr_printf.c \
thr_priority_queue.c \
thr_pselect.c \
thr_pspinlock.c \
thr_raise.c \
thr_read.c \
thr_readv.c \

View File

@ -402,6 +402,11 @@ struct pthread_barrierattr {
int pshared;
};
struct pthread_spinlock {
volatile int s_lock;
pthread_t s_owner;
};
/*
* Flags for condition variables.
*/
@ -1093,6 +1098,7 @@ int _pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t *);
int _pthread_rwlock_destroy (pthread_rwlock_t *);
struct pthread *_pthread_self(void);
int _pthread_setspecific(pthread_key_t, const void *);
void _pthread_yield(void);
struct pthread *_thr_alloc(struct pthread *);
void _thr_exit(char *, int, char *);
void _thr_exit_cleanup(void);

View File

@ -0,0 +1,154 @@
/*-
* Copyright (c) 2003 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <atomic_ops.h>
#include "thr_private.h"
#define SPIN_COUNT 10000
int
pthread_spin_init(pthread_spinlock_t *lock, int pshared)
{
struct pthread_spinlock *lck;
int ret;
if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
ret = EINVAL;
else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
ret = ENOMEM;
else {
lck->s_lock = 0;
lck->s_owner= NULL;
*lock = lck;
ret = 0;
}
return (ret);
}
int
pthread_spin_destroy(pthread_spinlock_t *lock)
{
int ret;
if (lock == NULL || *lock == NULL)
ret = EINVAL;
else if ((*lock)->s_owner != NULL)
ret = EBUSY;
else {
free(*lock);
*lock = NULL;
ret = 0;
}
return (ret);
}
int
pthread_spin_trylock(pthread_spinlock_t *lock)
{
struct pthread_spinlock *lck;
struct pthread *self = _pthread_self();
int oldval, ret;
if (lock == NULL || (lck = *lock) == NULL)
ret = EINVAL;
else if (lck->s_owner == self)
ret = EDEADLK;
else if (lck->s_lock != 0)
ret = EBUSY;
else {
atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
if (oldval)
ret = EBUSY;
else {
lck->s_owner = _pthread_self();
ret = 0;
}
}
return (ret);
}
int
pthread_spin_lock(pthread_spinlock_t *lock)
{
struct pthread_spinlock *lck;
struct pthread *self = _pthread_self();
int count, oldval, ret;
if (lock == NULL || (lck = *lock) == NULL)
ret = EINVAL;
else if (lck->s_owner == self)
ret = EDEADLK;
else {
do {
count = SPIN_COUNT;
while (lck->s_lock) {
#ifdef __i386__
/* tell cpu we are spinning */
__asm __volatile("pause");
#endif
if (--count <= 0) {
count = SPIN_COUNT;
_pthread_yield();
}
}
atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
} while (oldval);
lck->s_owner = self;
ret = 0;
}
return (ret);
}
int
pthread_spin_unlock(pthread_spinlock_t *lock)
{
struct pthread_spinlock *lck;
int ret;
if (lock == NULL || (lck = *lock) == NULL)
ret = EINVAL;
else {
if (lck->s_owner != _pthread_self())
ret = EPERM;
else {
lck->s_owner = NULL;
atomic_swap_int((int *)&lck->s_lock, 0, &ret);
ret = 0;
}
}
return (ret);
}