thr_pspinlock.c revision 174112
1119909Sdavidxu/*-
2119909Sdavidxu * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
3119909Sdavidxu * All rights reserved.
4119909Sdavidxu *
5119909Sdavidxu * Redistribution and use in source and binary forms, with or without
6119909Sdavidxu * modification, are permitted provided that the following conditions
7119909Sdavidxu * are met:
8119909Sdavidxu * 1. Redistributions of source code must retain the above copyright
9119909Sdavidxu *    notice, this list of conditions and the following disclaimer.
10119909Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
11119909Sdavidxu *    notice, this list of conditions and the following disclaimer in the
12119909Sdavidxu *    documentation and/or other materials provided with the distribution.
13119909Sdavidxu *
14119909Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15119909Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16119909Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17119909Sdavidxu * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18119909Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19119909Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20119909Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21119909Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22119909Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23119909Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24119909Sdavidxu * SUCH DAMAGE.
25119909Sdavidxu *
26119909Sdavidxu * $FreeBSD: head/lib/libkse/thread/thr_pspinlock.c 174112 2007-11-30 17:20:29Z deischen $
27119909Sdavidxu */
28119909Sdavidxu
29174112Sdeischen#include "namespace.h"
30149691Sstefanf#include <sys/types.h>
31119909Sdavidxu#include <errno.h>
32149691Sstefanf#include <pthread.h>
33149691Sstefanf#include <stdint.h>
34119909Sdavidxu#include <stdlib.h>
35174112Sdeischen#include "un-namespace.h"
36149691Sstefanf
37149691Sstefanf#include "atomic_ops.h"
38119909Sdavidxu#include "thr_private.h"
39119909Sdavidxu
40119909Sdavidxu#define SPIN_COUNT 10000
41119909Sdavidxu
42156611SdeischenLT10_COMPAT_PRIVATE(_pthread_spin_init);
43156611SdeischenLT10_COMPAT_DEFAULT(pthread_spin_init);
44156611SdeischenLT10_COMPAT_PRIVATE(_pthread_spin_destroy);
45156611SdeischenLT10_COMPAT_DEFAULT(pthread_spin_destroy);
46156611SdeischenLT10_COMPAT_PRIVATE(_pthread_spin_trylock);
47156611SdeischenLT10_COMPAT_DEFAULT(pthread_spin_trylock);
48156611SdeischenLT10_COMPAT_PRIVATE(_pthread_spin_lock);
49156611SdeischenLT10_COMPAT_DEFAULT(pthread_spin_lock);
50156611SdeischenLT10_COMPAT_PRIVATE(_pthread_spin_unlock);
51156611SdeischenLT10_COMPAT_DEFAULT(pthread_spin_unlock);
52156611Sdeischen
53122071Sdeischen__weak_reference(_pthread_spin_init, pthread_spin_init);
54122071Sdeischen__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
55122071Sdeischen__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
56122071Sdeischen__weak_reference(_pthread_spin_lock, pthread_spin_lock);
57122071Sdeischen__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
58122071Sdeischen
59119909Sdavidxuint
60122071Sdeischen_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
61119909Sdavidxu{
62119909Sdavidxu	struct pthread_spinlock	*lck;
63119909Sdavidxu	int ret;
64119909Sdavidxu
65119909Sdavidxu	if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
66119909Sdavidxu		ret = EINVAL;
67119909Sdavidxu	else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
68119909Sdavidxu		ret = ENOMEM;
69119909Sdavidxu	else {
70119909Sdavidxu		lck->s_lock = 0;
71119909Sdavidxu		lck->s_owner= NULL;
72119909Sdavidxu		*lock = lck;
73119909Sdavidxu		ret = 0;
74119909Sdavidxu	}
75119909Sdavidxu
76119909Sdavidxu	return (ret);
77119909Sdavidxu}
78119909Sdavidxu
79119909Sdavidxuint
80122071Sdeischen_pthread_spin_destroy(pthread_spinlock_t *lock)
81119909Sdavidxu{
82119909Sdavidxu	int ret;
83119909Sdavidxu
84119909Sdavidxu	if (lock == NULL || *lock == NULL)
85119909Sdavidxu		ret = EINVAL;
86119909Sdavidxu	else if ((*lock)->s_owner != NULL)
87119909Sdavidxu		ret = EBUSY;
88119909Sdavidxu	else {
89119909Sdavidxu		free(*lock);
90119909Sdavidxu		*lock = NULL;
91119909Sdavidxu		ret = 0;
92119909Sdavidxu	}
93119909Sdavidxu
94119909Sdavidxu	return (ret);
95119909Sdavidxu}
96119909Sdavidxu
97119909Sdavidxuint
98122071Sdeischen_pthread_spin_trylock(pthread_spinlock_t *lock)
99119909Sdavidxu{
100119909Sdavidxu	struct pthread_spinlock	*lck;
101119909Sdavidxu	struct pthread *self = _pthread_self();
102119909Sdavidxu	int oldval, ret;
103119909Sdavidxu
104119909Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
105119909Sdavidxu		ret = EINVAL;
106119909Sdavidxu	else if (lck->s_owner == self)
107119909Sdavidxu		ret = EDEADLK;
108119909Sdavidxu	else if (lck->s_lock != 0)
109119909Sdavidxu		ret = EBUSY;
110119909Sdavidxu	else {
111174112Sdeischen		atomic_swap_int(&(lck)->s_lock, 1, &oldval);
112119909Sdavidxu		if (oldval)
113119909Sdavidxu			ret = EBUSY;
114119909Sdavidxu		else {
115119909Sdavidxu			lck->s_owner = _pthread_self();
116119909Sdavidxu			ret = 0;
117119909Sdavidxu		}
118119909Sdavidxu	}
119119909Sdavidxu	return (ret);
120119909Sdavidxu}
121119909Sdavidxu
122119909Sdavidxuint
123122071Sdeischen_pthread_spin_lock(pthread_spinlock_t *lock)
124119909Sdavidxu{
125119909Sdavidxu	struct pthread_spinlock	*lck;
126119909Sdavidxu	struct pthread *self = _pthread_self();
127119909Sdavidxu	int count, oldval, ret;
128119909Sdavidxu
129119909Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
130119909Sdavidxu		ret = EINVAL;
131119909Sdavidxu	else if (lck->s_owner == self)
132119909Sdavidxu		ret = EDEADLK;
133119909Sdavidxu	else {
134119909Sdavidxu		do {
135119909Sdavidxu			count = SPIN_COUNT;
136119909Sdavidxu			while (lck->s_lock) {
137119909Sdavidxu#ifdef __i386__
138119909Sdavidxu				/* tell cpu we are spinning */
139119909Sdavidxu				__asm __volatile("pause");
140119909Sdavidxu#endif
141119909Sdavidxu				if (--count <= 0) {
142119909Sdavidxu					count = SPIN_COUNT;
143119909Sdavidxu					_pthread_yield();
144119909Sdavidxu				}
145119909Sdavidxu			}
146174112Sdeischen			atomic_swap_int(&(lck)->s_lock, 1, &oldval);
147119909Sdavidxu		} while (oldval);
148119909Sdavidxu
149119909Sdavidxu		lck->s_owner = self;
150119909Sdavidxu		ret = 0;
151119909Sdavidxu	}
152119909Sdavidxu
153119909Sdavidxu	return (ret);
154119909Sdavidxu}
155119909Sdavidxu
156119909Sdavidxuint
157122071Sdeischen_pthread_spin_unlock(pthread_spinlock_t *lock)
158119909Sdavidxu{
159119909Sdavidxu	struct pthread_spinlock	*lck;
160119909Sdavidxu	int ret;
161119909Sdavidxu
162119909Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
163119909Sdavidxu		ret = EINVAL;
164119909Sdavidxu	else {
165119909Sdavidxu		if (lck->s_owner != _pthread_self())
166119909Sdavidxu			ret = EPERM;
167119909Sdavidxu		else {
168119909Sdavidxu			lck->s_owner = NULL;
169174112Sdeischen			atomic_swap_int(&lck->s_lock, 0, &ret);
170119909Sdavidxu			ret = 0;
171119909Sdavidxu		}
172119909Sdavidxu	}
173119909Sdavidxu
174119909Sdavidxu	return (ret);
175119909Sdavidxu}
176119909Sdavidxu
177