thr_pspinlock.c revision 119909
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 119909 2003-09-09 06:57:51Z davidxu $
27119909Sdavidxu */
28119909Sdavidxu
29119909Sdavidxu#include <errno.h>
30119909Sdavidxu#include <stdlib.h>
31119909Sdavidxu#include <pthread.h>
32119909Sdavidxu#include <atomic_ops.h>
33119909Sdavidxu#include "thr_private.h"
34119909Sdavidxu
35119909Sdavidxu#define SPIN_COUNT 10000
36119909Sdavidxu
37119909Sdavidxuint
38119909Sdavidxupthread_spin_init(pthread_spinlock_t *lock, int pshared)
39119909Sdavidxu{
40119909Sdavidxu	struct pthread_spinlock	*lck;
41119909Sdavidxu	int ret;
42119909Sdavidxu
43119909Sdavidxu	if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
44119909Sdavidxu		ret = EINVAL;
45119909Sdavidxu	else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
46119909Sdavidxu		ret = ENOMEM;
47119909Sdavidxu	else {
48119909Sdavidxu		lck->s_lock = 0;
49119909Sdavidxu		lck->s_owner= NULL;
50119909Sdavidxu		*lock = lck;
51119909Sdavidxu		ret = 0;
52119909Sdavidxu	}
53119909Sdavidxu
54119909Sdavidxu	return (ret);
55119909Sdavidxu}
56119909Sdavidxu
57119909Sdavidxuint
58119909Sdavidxupthread_spin_destroy(pthread_spinlock_t *lock)
59119909Sdavidxu{
60119909Sdavidxu	int ret;
61119909Sdavidxu
62119909Sdavidxu	if (lock == NULL || *lock == NULL)
63119909Sdavidxu		ret = EINVAL;
64119909Sdavidxu	else if ((*lock)->s_owner != NULL)
65119909Sdavidxu		ret = EBUSY;
66119909Sdavidxu	else {
67119909Sdavidxu		free(*lock);
68119909Sdavidxu		*lock = NULL;
69119909Sdavidxu		ret = 0;
70119909Sdavidxu	}
71119909Sdavidxu
72119909Sdavidxu	return (ret);
73119909Sdavidxu}
74119909Sdavidxu
75119909Sdavidxuint
76119909Sdavidxupthread_spin_trylock(pthread_spinlock_t *lock)
77119909Sdavidxu{
78119909Sdavidxu	struct pthread_spinlock	*lck;
79119909Sdavidxu	struct pthread *self = _pthread_self();
80119909Sdavidxu	int oldval, ret;
81119909Sdavidxu
82119909Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
83119909Sdavidxu		ret = EINVAL;
84119909Sdavidxu	else if (lck->s_owner == self)
85119909Sdavidxu		ret = EDEADLK;
86119909Sdavidxu	else if (lck->s_lock != 0)
87119909Sdavidxu		ret = EBUSY;
88119909Sdavidxu	else {
89119909Sdavidxu		atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
90119909Sdavidxu		if (oldval)
91119909Sdavidxu			ret = EBUSY;
92119909Sdavidxu		else {
93119909Sdavidxu			lck->s_owner = _pthread_self();
94119909Sdavidxu			ret = 0;
95119909Sdavidxu		}
96119909Sdavidxu	}
97119909Sdavidxu	return (ret);
98119909Sdavidxu}
99119909Sdavidxu
100119909Sdavidxuint
101119909Sdavidxupthread_spin_lock(pthread_spinlock_t *lock)
102119909Sdavidxu{
103119909Sdavidxu	struct pthread_spinlock	*lck;
104119909Sdavidxu	struct pthread *self = _pthread_self();
105119909Sdavidxu	int count, oldval, ret;
106119909Sdavidxu
107119909Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
108119909Sdavidxu		ret = EINVAL;
109119909Sdavidxu	else if (lck->s_owner == self)
110119909Sdavidxu		ret = EDEADLK;
111119909Sdavidxu	else {
112119909Sdavidxu		do {
113119909Sdavidxu			count = SPIN_COUNT;
114119909Sdavidxu			while (lck->s_lock) {
115119909Sdavidxu#ifdef __i386__
116119909Sdavidxu				/* tell cpu we are spinning */
117119909Sdavidxu				__asm __volatile("pause");
118119909Sdavidxu#endif
119119909Sdavidxu				if (--count <= 0) {
120119909Sdavidxu					count = SPIN_COUNT;
121119909Sdavidxu					_pthread_yield();
122119909Sdavidxu				}
123119909Sdavidxu			}
124119909Sdavidxu			atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
125119909Sdavidxu		} while (oldval);
126119909Sdavidxu
127119909Sdavidxu		lck->s_owner = self;
128119909Sdavidxu		ret = 0;
129119909Sdavidxu	}
130119909Sdavidxu
131119909Sdavidxu	return (ret);
132119909Sdavidxu}
133119909Sdavidxu
134119909Sdavidxuint
135119909Sdavidxupthread_spin_unlock(pthread_spinlock_t *lock)
136119909Sdavidxu{
137119909Sdavidxu	struct pthread_spinlock	*lck;
138119909Sdavidxu	int ret;
139119909Sdavidxu
140119909Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
141119909Sdavidxu		ret = EINVAL;
142119909Sdavidxu	else {
143119909Sdavidxu		if (lck->s_owner != _pthread_self())
144119909Sdavidxu			ret = EPERM;
145119909Sdavidxu		else {
146119909Sdavidxu			lck->s_owner = NULL;
147119909Sdavidxu			atomic_swap_int((int *)&lck->s_lock, 0, &ret);
148119909Sdavidxu			ret = 0;
149119909Sdavidxu		}
150119909Sdavidxu	}
151119909Sdavidxu
152119909Sdavidxu	return (ret);
153119909Sdavidxu}
154119909Sdavidxu
155