summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2003-09-09 06:57:51 +0000
committerdavidxu <davidxu@FreeBSD.org>2003-09-09 06:57:51 +0000
commitf2dd9e63652a559e3a0a5f9fa41d402bbdeb0215 (patch)
tree82a69e66f42a65516c9e48853458619c41d3b72e
parent03f1b3ffefcb275dbd07b776e3ca01bf2467597b (diff)
downloadFreeBSD-src-f2dd9e63652a559e3a0a5f9fa41d402bbdeb0215.zip
FreeBSD-src-f2dd9e63652a559e3a0a5f9fa41d402bbdeb0215.tar.gz
Add code to support pthread spin lock.
Reviewed by: deischen
-rw-r--r--include/pthread.h7
-rw-r--r--lib/libkse/thread/Makefile.inc1
-rw-r--r--lib/libkse/thread/thr_private.h6
-rw-r--r--lib/libkse/thread/thr_pspinlock.c154
-rw-r--r--lib/libpthread/pthread.map10
-rw-r--r--lib/libpthread/thread/Makefile.inc1
-rw-r--r--lib/libpthread/thread/thr_private.h6
-rw-r--r--lib/libpthread/thread/thr_pspinlock.c154
8 files changed, 339 insertions, 0 deletions
diff --git a/include/pthread.h b/include/pthread.h
index 417e78f..e86b318 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -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 *);
diff --git a/lib/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc
index 70f88cd..52c342c 100644
--- a/lib/libkse/thread/Makefile.inc
+++ b/lib/libkse/thread/Makefile.inc
@@ -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 \
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
index 2127619..12ebe90 100644
--- a/lib/libkse/thread/thr_private.h
+++ b/lib/libkse/thread/thr_private.h
@@ -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);
diff --git a/lib/libkse/thread/thr_pspinlock.c b/lib/libkse/thread/thr_pspinlock.c
new file mode 100644
index 0000000..de26750
--- /dev/null
+++ b/lib/libkse/thread/thr_pspinlock.c
@@ -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);
+}
+
diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map
index c424218..ce46f96 100644
--- a/lib/libpthread/pthread.map
+++ b/lib/libpthread/pthread.map
@@ -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;
diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc
index 70f88cd..52c342c 100644
--- a/lib/libpthread/thread/Makefile.inc
+++ b/lib/libpthread/thread/Makefile.inc
@@ -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 \
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 2127619..12ebe90 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -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);
diff --git a/lib/libpthread/thread/thr_pspinlock.c b/lib/libpthread/thread/thr_pspinlock.c
new file mode 100644
index 0000000..de26750
--- /dev/null
+++ b/lib/libpthread/thread/thr_pspinlock.c
@@ -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);
+}
+
OpenPOWER on IntegriCloud