1144518Sdavidxu/*-
2144518Sdavidxu * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
3144518Sdavidxu * All rights reserved.
4144518Sdavidxu *
5144518Sdavidxu * Redistribution and use in source and binary forms, with or without
6144518Sdavidxu * modification, are permitted provided that the following conditions
7144518Sdavidxu * are met:
8144518Sdavidxu * 1. Redistributions of source code must retain the above copyright
9144518Sdavidxu *    notice, this list of conditions and the following disclaimer.
10144518Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright
11144518Sdavidxu *    notice, this list of conditions and the following disclaimer in the
12144518Sdavidxu *    documentation and/or other materials provided with the distribution.
13144518Sdavidxu *
14144518Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15144518Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16144518Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17144518Sdavidxu * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18144518Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19144518Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20144518Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21144518Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22144518Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23144518Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24144518Sdavidxu * SUCH DAMAGE.
25144518Sdavidxu *
26144518Sdavidxu * $FreeBSD$
27144518Sdavidxu */
28144518Sdavidxu
29157457Sdavidxu#include "namespace.h"
30144518Sdavidxu#include <errno.h>
31144518Sdavidxu#include <stdlib.h>
32144518Sdavidxu#include <pthread.h>
33157457Sdavidxu#include "un-namespace.h"
34157457Sdavidxu
35144518Sdavidxu#include "thr_private.h"
36144518Sdavidxu
37144518Sdavidxu#define SPIN_COUNT 100000
38144518Sdavidxu
39144518Sdavidxu__weak_reference(_pthread_spin_init, pthread_spin_init);
40144518Sdavidxu__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
41144518Sdavidxu__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
42144518Sdavidxu__weak_reference(_pthread_spin_lock, pthread_spin_lock);
43144518Sdavidxu__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
44144518Sdavidxu
45144518Sdavidxuint
46144518Sdavidxu_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
47144518Sdavidxu{
48144518Sdavidxu	struct pthread_spinlock	*lck;
49144518Sdavidxu	int ret;
50144518Sdavidxu
51144518Sdavidxu	if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
52144518Sdavidxu		ret = EINVAL;
53144518Sdavidxu	else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
54144518Sdavidxu		ret = ENOMEM;
55144518Sdavidxu	else {
56162061Sdavidxu		_thr_umutex_init(&lck->s_lock);
57144518Sdavidxu		*lock = lck;
58144518Sdavidxu		ret = 0;
59144518Sdavidxu	}
60144518Sdavidxu
61144518Sdavidxu	return (ret);
62144518Sdavidxu}
63144518Sdavidxu
64144518Sdavidxuint
65144518Sdavidxu_pthread_spin_destroy(pthread_spinlock_t *lock)
66144518Sdavidxu{
67144518Sdavidxu	int ret;
68144518Sdavidxu
69144518Sdavidxu	if (lock == NULL || *lock == NULL)
70144518Sdavidxu		ret = EINVAL;
71144518Sdavidxu	else {
72144518Sdavidxu		free(*lock);
73144518Sdavidxu		*lock = NULL;
74144518Sdavidxu		ret = 0;
75144518Sdavidxu	}
76144518Sdavidxu
77144518Sdavidxu	return (ret);
78144518Sdavidxu}
79144518Sdavidxu
80144518Sdavidxuint
81144518Sdavidxu_pthread_spin_trylock(pthread_spinlock_t *lock)
82144518Sdavidxu{
83144518Sdavidxu	struct pthread *curthread = _get_curthread();
84144518Sdavidxu	struct pthread_spinlock	*lck;
85144518Sdavidxu	int ret;
86144518Sdavidxu
87144518Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
88144518Sdavidxu		ret = EINVAL;
89144518Sdavidxu	else
90162061Sdavidxu		ret = THR_UMUTEX_TRYLOCK(curthread, &lck->s_lock);
91144518Sdavidxu	return (ret);
92144518Sdavidxu}
93144518Sdavidxu
94144518Sdavidxuint
95144518Sdavidxu_pthread_spin_lock(pthread_spinlock_t *lock)
96144518Sdavidxu{
97144518Sdavidxu	struct pthread *curthread = _get_curthread();
98144518Sdavidxu	struct pthread_spinlock	*lck;
99144518Sdavidxu	int ret, count;
100144518Sdavidxu
101144518Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
102144518Sdavidxu		ret = EINVAL;
103144518Sdavidxu	else {
104144518Sdavidxu		count = SPIN_COUNT;
105162061Sdavidxu		while ((ret = THR_UMUTEX_TRYLOCK(curthread, &lck->s_lock)) != 0) {
106162061Sdavidxu			while (lck->s_lock.m_owner) {
107172694Sdavidxu				if (!_thr_is_smp) {
108161068Sdavidxu					_pthread_yield();
109161068Sdavidxu				} else {
110165241Sdavidxu					CPU_SPINWAIT;
111165241Sdavidxu
112161068Sdavidxu					if (--count <= 0) {
113161068Sdavidxu						count = SPIN_COUNT;
114161068Sdavidxu						_pthread_yield();
115161068Sdavidxu					}
116144518Sdavidxu				}
117144518Sdavidxu			}
118144518Sdavidxu		}
119144518Sdavidxu		ret = 0;
120144518Sdavidxu	}
121144518Sdavidxu
122144518Sdavidxu	return (ret);
123144518Sdavidxu}
124144518Sdavidxu
125144518Sdavidxuint
126144518Sdavidxu_pthread_spin_unlock(pthread_spinlock_t *lock)
127144518Sdavidxu{
128144518Sdavidxu	struct pthread *curthread = _get_curthread();
129144518Sdavidxu	struct pthread_spinlock	*lck;
130144518Sdavidxu	int ret;
131144518Sdavidxu
132144518Sdavidxu	if (lock == NULL || (lck = *lock) == NULL)
133144518Sdavidxu		ret = EINVAL;
134144518Sdavidxu	else {
135162061Sdavidxu		ret = THR_UMUTEX_UNLOCK(curthread, &lck->s_lock);
136144518Sdavidxu	}
137144518Sdavidxu	return (ret);
138144518Sdavidxu}
139