thr_pspinlock.c revision 122071
110122SJordan.Brown@Sun.COM/*-
210122SJordan.Brown@Sun.COM * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
310122SJordan.Brown@Sun.COM * All rights reserved.
410122SJordan.Brown@Sun.COM *
510122SJordan.Brown@Sun.COM * Redistribution and use in source and binary forms, with or without
610122SJordan.Brown@Sun.COM * modification, are permitted provided that the following conditions
710122SJordan.Brown@Sun.COM * are met:
810122SJordan.Brown@Sun.COM * 1. Redistributions of source code must retain the above copyright
910122SJordan.Brown@Sun.COM *    notice, this list of conditions and the following disclaimer.
1010122SJordan.Brown@Sun.COM * 2. Redistributions in binary form must reproduce the above copyright
1110122SJordan.Brown@Sun.COM *    notice, this list of conditions and the following disclaimer in the
1210122SJordan.Brown@Sun.COM *    documentation and/or other materials provided with the distribution.
1310122SJordan.Brown@Sun.COM *
1410122SJordan.Brown@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1510122SJordan.Brown@Sun.COM * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1610122SJordan.Brown@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1710122SJordan.Brown@Sun.COM * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1810122SJordan.Brown@Sun.COM * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1910122SJordan.Brown@Sun.COM * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2010122SJordan.Brown@Sun.COM * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2110122SJordan.Brown@Sun.COM * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2210122SJordan.Brown@Sun.COM * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2312890SJoyce.McIntosh@Sun.COM * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2410122SJordan.Brown@Sun.COM * SUCH DAMAGE.
2510122SJordan.Brown@Sun.COM *
2610122SJordan.Brown@Sun.COM * $FreeBSD: head/lib/libkse/thread/thr_pspinlock.c 122071 2003-11-04 19:56:12Z deischen $
2710122SJordan.Brown@Sun.COM */
2810122SJordan.Brown@Sun.COM
2910122SJordan.Brown@Sun.COM#include <errno.h>
3010122SJordan.Brown@Sun.COM#include <stdlib.h>
3110122SJordan.Brown@Sun.COM#include <pthread.h>
3210122SJordan.Brown@Sun.COM#include <atomic_ops.h>
3310122SJordan.Brown@Sun.COM#include "thr_private.h"
3410122SJordan.Brown@Sun.COM
3510122SJordan.Brown@Sun.COM#define SPIN_COUNT 10000
3610122SJordan.Brown@Sun.COM
3712890SJoyce.McIntosh@Sun.COM__weak_reference(_pthread_spin_init, pthread_spin_init);
3810122SJordan.Brown@Sun.COM__weak_reference(_pthread_spin_destroy, pthread_spin_destroy);
3910122SJordan.Brown@Sun.COM__weak_reference(_pthread_spin_trylock, pthread_spin_trylock);
4010122SJordan.Brown@Sun.COM__weak_reference(_pthread_spin_lock, pthread_spin_lock);
4110122SJordan.Brown@Sun.COM__weak_reference(_pthread_spin_unlock, pthread_spin_unlock);
4210122SJordan.Brown@Sun.COM
4310122SJordan.Brown@Sun.COMint
4410122SJordan.Brown@Sun.COM_pthread_spin_init(pthread_spinlock_t *lock, int pshared)
4510122SJordan.Brown@Sun.COM{
4610122SJordan.Brown@Sun.COM	struct pthread_spinlock	*lck;
4710122SJordan.Brown@Sun.COM	int ret;
4810122SJordan.Brown@Sun.COM
4910122SJordan.Brown@Sun.COM	if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE)
5010122SJordan.Brown@Sun.COM		ret = EINVAL;
5110122SJordan.Brown@Sun.COM	else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL)
5210122SJordan.Brown@Sun.COM		ret = ENOMEM;
5310122SJordan.Brown@Sun.COM	else {
5410122SJordan.Brown@Sun.COM		lck->s_lock = 0;
5510122SJordan.Brown@Sun.COM		lck->s_owner= NULL;
5610122SJordan.Brown@Sun.COM		*lock = lck;
5710122SJordan.Brown@Sun.COM		ret = 0;
5810122SJordan.Brown@Sun.COM	}
5910122SJordan.Brown@Sun.COM
6010122SJordan.Brown@Sun.COM	return (ret);
6110122SJordan.Brown@Sun.COM}
6210122SJordan.Brown@Sun.COM
6310122SJordan.Brown@Sun.COMint
6410122SJordan.Brown@Sun.COM_pthread_spin_destroy(pthread_spinlock_t *lock)
6510122SJordan.Brown@Sun.COM{
6610122SJordan.Brown@Sun.COM	int ret;
6710122SJordan.Brown@Sun.COM
6810122SJordan.Brown@Sun.COM	if (lock == NULL || *lock == NULL)
6910122SJordan.Brown@Sun.COM		ret = EINVAL;
7010122SJordan.Brown@Sun.COM	else if ((*lock)->s_owner != NULL)
7110122SJordan.Brown@Sun.COM		ret = EBUSY;
7210122SJordan.Brown@Sun.COM	else {
7310122SJordan.Brown@Sun.COM		free(*lock);
7410122SJordan.Brown@Sun.COM		*lock = NULL;
7510122SJordan.Brown@Sun.COM		ret = 0;
7610122SJordan.Brown@Sun.COM	}
7710122SJordan.Brown@Sun.COM
7810122SJordan.Brown@Sun.COM	return (ret);
7910122SJordan.Brown@Sun.COM}
8010122SJordan.Brown@Sun.COM
8110122SJordan.Brown@Sun.COMint
8210122SJordan.Brown@Sun.COM_pthread_spin_trylock(pthread_spinlock_t *lock)
8310122SJordan.Brown@Sun.COM{
8410122SJordan.Brown@Sun.COM	struct pthread_spinlock	*lck;
8510122SJordan.Brown@Sun.COM	struct pthread *self = _pthread_self();
8610122SJordan.Brown@Sun.COM	int oldval, ret;
8710122SJordan.Brown@Sun.COM
8810122SJordan.Brown@Sun.COM	if (lock == NULL || (lck = *lock) == NULL)
8910122SJordan.Brown@Sun.COM		ret = EINVAL;
9010122SJordan.Brown@Sun.COM	else if (lck->s_owner == self)
9110122SJordan.Brown@Sun.COM		ret = EDEADLK;
9210122SJordan.Brown@Sun.COM	else if (lck->s_lock != 0)
9310122SJordan.Brown@Sun.COM		ret = EBUSY;
9410122SJordan.Brown@Sun.COM	else {
9510122SJordan.Brown@Sun.COM		atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
9610122SJordan.Brown@Sun.COM		if (oldval)
9710122SJordan.Brown@Sun.COM			ret = EBUSY;
9810122SJordan.Brown@Sun.COM		else {
9910122SJordan.Brown@Sun.COM			lck->s_owner = _pthread_self();
10010122SJordan.Brown@Sun.COM			ret = 0;
10110122SJordan.Brown@Sun.COM		}
10210122SJordan.Brown@Sun.COM	}
10310122SJordan.Brown@Sun.COM	return (ret);
10410122SJordan.Brown@Sun.COM}
10510122SJordan.Brown@Sun.COM
10610122SJordan.Brown@Sun.COMint
10710122SJordan.Brown@Sun.COM_pthread_spin_lock(pthread_spinlock_t *lock)
10810122SJordan.Brown@Sun.COM{
10910122SJordan.Brown@Sun.COM	struct pthread_spinlock	*lck;
11010122SJordan.Brown@Sun.COM	struct pthread *self = _pthread_self();
11110122SJordan.Brown@Sun.COM	int count, oldval, ret;
11210122SJordan.Brown@Sun.COM
11310122SJordan.Brown@Sun.COM	if (lock == NULL || (lck = *lock) == NULL)
11410122SJordan.Brown@Sun.COM		ret = EINVAL;
11510122SJordan.Brown@Sun.COM	else if (lck->s_owner == self)
11610122SJordan.Brown@Sun.COM		ret = EDEADLK;
11710122SJordan.Brown@Sun.COM	else {
11810122SJordan.Brown@Sun.COM		do {
11910122SJordan.Brown@Sun.COM			count = SPIN_COUNT;
12010122SJordan.Brown@Sun.COM			while (lck->s_lock) {
12110122SJordan.Brown@Sun.COM#ifdef __i386__
12210122SJordan.Brown@Sun.COM				/* tell cpu we are spinning */
12310122SJordan.Brown@Sun.COM				__asm __volatile("pause");
12410122SJordan.Brown@Sun.COM#endif
12510122SJordan.Brown@Sun.COM				if (--count <= 0) {
12610122SJordan.Brown@Sun.COM					count = SPIN_COUNT;
12710122SJordan.Brown@Sun.COM					_pthread_yield();
12810122SJordan.Brown@Sun.COM				}
12910122SJordan.Brown@Sun.COM			}
13010122SJordan.Brown@Sun.COM			atomic_swap_int((int *)&(lck)->s_lock, 1, &oldval);
13110122SJordan.Brown@Sun.COM		} while (oldval);
13210122SJordan.Brown@Sun.COM
13310122SJordan.Brown@Sun.COM		lck->s_owner = self;
13410122SJordan.Brown@Sun.COM		ret = 0;
13510122SJordan.Brown@Sun.COM	}
13610122SJordan.Brown@Sun.COM
13710122SJordan.Brown@Sun.COM	return (ret);
13810122SJordan.Brown@Sun.COM}
13910122SJordan.Brown@Sun.COM
14010122SJordan.Brown@Sun.COMint
14110122SJordan.Brown@Sun.COM_pthread_spin_unlock(pthread_spinlock_t *lock)
14210122SJordan.Brown@Sun.COM{
14310122SJordan.Brown@Sun.COM	struct pthread_spinlock	*lck;
14410122SJordan.Brown@Sun.COM	int ret;
14510122SJordan.Brown@Sun.COM
14610122SJordan.Brown@Sun.COM	if (lock == NULL || (lck = *lock) == NULL)
14710122SJordan.Brown@Sun.COM		ret = EINVAL;
14810122SJordan.Brown@Sun.COM	else {
14910122SJordan.Brown@Sun.COM		if (lck->s_owner != _pthread_self())
15010122SJordan.Brown@Sun.COM			ret = EPERM;
15110122SJordan.Brown@Sun.COM		else {
15210122SJordan.Brown@Sun.COM			lck->s_owner = NULL;
15310122SJordan.Brown@Sun.COM			atomic_swap_int((int *)&lck->s_lock, 0, &ret);
15410122SJordan.Brown@Sun.COM			ret = 0;
15510122SJordan.Brown@Sun.COM		}
15610122SJordan.Brown@Sun.COM	}
15710122SJordan.Brown@Sun.COM
15810122SJordan.Brown@Sun.COM	return (ret);
15910122SJordan.Brown@Sun.COM}
16010122SJordan.Brown@Sun.COM
16110122SJordan.Brown@Sun.COM