thr_pspinlock.c revision 149691
1266733Speter/*-
2266733Speter * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
3266733Speter * All rights reserved.
4266733Speter *
5266733Speter * Redistribution and use in source and binary forms, with or without
6266733Speter * modification, are permitted provided that the following conditions
7266733Speter * are met:
8266733Speter * 1. Redistributions of source code must retain the above copyright
9266733Speter *    notice, this list of conditions and the following disclaimer.
10266733Speter * 2. Redistributions in binary form must reproduce the above copyright
11266733Speter *    notice, this list of conditions and the following disclaimer in the
12266733Speter *    documentation and/or other materials provided with the distribution.
13266733Speter *
14266733Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15266733Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16266733Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17266733Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18266733Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19266733Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20266733Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21266733Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22266733Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23266733Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24266733Speter * SUCH DAMAGE.
25266733Speter *
26266733Speter * $FreeBSD: head/lib/libkse/thread/thr_pspinlock.c 149691 2005-09-01 15:21:23Z stefanf $
27266733Speter */
28266733Speter
29266733Speter#include <sys/types.h>
30266733Speter#include <errno.h>
31266733Speter#include <pthread.h>
32266733Speter#include <stdint.h>
33266733Speter#include <stdlib.h>
34266733Speter
35266733Speter#include "atomic_ops.h"
36266733Speter#include "thr_private.h"
37266733Speter
38266733Speter#define SPIN_COUNT 10000
39266733Speter
40266733Speter__weak_reference(_pthread_spin_init, pthread_spin_init);
41266733Speter__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
42266733Speter__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
43266733Speter__weak_reference(_pthread_spin_lock, pthread_spin_lock);
44266733Speter__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
45266733Speter
46266733Speterint
47266733Speter_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
48266733Speter{
49266733Speter	struct pthread_spinlock	*lck;
50266733Speter	int ret;
51266733Speter
52266733Speter	if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
53266733Speter		ret = EINVAL;
54266733Speter	else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
55266733Speter		ret = ENOMEM;
56266733Speter	else {
57266733Speter		lck->s_lock = 0;
58266733Speter		lck->s_owner= NULL;
59266733Speter		*lock = lck;
60266733Speter		ret = 0;
61266733Speter	}
62266733Speter
63266733Speter	return (ret);
64266733Speter}
65266733Speter
66266733Speterint
67266733Speter_pthread_spin_destroy(pthread_spinlock_t *lock)
68266733Speter{
69266733Speter	int ret;
70266733Speter
71266733Speter	if (lock == NULL || *lock == NULL)
72266733Speter		ret = EINVAL;
73266733Speter	else if ((*lock)->s_owner != NULL)
74266733Speter		ret = EBUSY;
75266733Speter	else {
76266733Speter		free(*lock);
77266733Speter		*lock = NULL;
78266733Speter		ret = 0;
79266733Speter	}
80266733Speter
81266733Speter	return (ret);
82266733Speter}
83266733Speter
84266733Speterint
85266733Speter_pthread_spin_trylock(pthread_spinlock_t *lock)
86266733Speter{
87266733Speter	struct pthread_spinlock	*lck;
88266733Speter	struct pthread *self = _pthread_self();
89266733Speter	int oldval, ret;
90266733Speter
91266733Speter	if (lock == NULL || (lck = *lock) == NULL)
92266733Speter		ret = EINVAL;
93266733Speter	else if (lck->s_owner == self)
94266733Speter		ret = EDEADLK;
95266733Speter	else if (lck->s_lock != 0)
96266733Speter		ret = EBUSY;
97266733Speter	else {
98266733Speter		atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
99266733Speter		if (oldval)
100266733Speter			ret = EBUSY;
101266733Speter		else {
102266733Speter			lck->s_owner = _pthread_self();
103266733Speter			ret = 0;
104266733Speter		}
105266733Speter	}
106266733Speter	return (ret);
107266733Speter}
108266733Speter
109266733Speterint
110266733Speter_pthread_spin_lock(pthread_spinlock_t *lock)
111266733Speter{
112266733Speter	struct pthread_spinlock	*lck;
113266733Speter	struct pthread *self = _pthread_self();
114266733Speter	int count, oldval, ret;
115266733Speter
116266733Speter	if (lock == NULL || (lck = *lock) == NULL)
117266733Speter		ret = EINVAL;
118266733Speter	else if (lck->s_owner == self)
119266733Speter		ret = EDEADLK;
120266733Speter	else {
121266733Speter		do {
122266733Speter			count = SPIN_COUNT;
123266733Speter			while (lck->s_lock) {
124266733Speter#ifdef __i386__
125266733Speter				/* tell cpu we are spinning */
126266733Speter				__asm __volatile("pause");
127266733Speter#endif
128266733Speter				if (--count <= 0) {
129266733Speter					count = SPIN_COUNT;
130266733Speter					_pthread_yield();
131266733Speter				}
132266733Speter			}
133266733Speter			atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
134266733Speter		} while (oldval);
135266733Speter
136266733Speter		lck->s_owner = self;
137266733Speter		ret = 0;
138266733Speter	}
139266733Speter
140266733Speter	return (ret);
141266733Speter}
142266733Speter
143266733Speterint
144266733Speter_pthread_spin_unlock(pthread_spinlock_t *lock)
145266733Speter{
146266733Speter	struct pthread_spinlock	*lck;
147266733Speter	int ret;
148266733Speter
149266733Speter	if (lock == NULL || (lck = *lock) == NULL)
150266733Speter		ret = EINVAL;
151266733Speter	else {
152266733Speter		if (lck->s_owner != _pthread_self())
153266733Speter			ret = EPERM;
154266733Speter		else {
155266733Speter			lck->s_owner = NULL;
156266733Speter			atomic_swap_int((int *)&lck->s_lock, 0, &ret);
157266733Speter			ret = 0;
158266733Speter		}
159266733Speter	}
160266733Speter
161266733Speter	return (ret);
162266733Speter}
163266733Speter
164266733Speter