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$ 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 42122071Sdeischen__weak_reference(_pthread_spin_init, pthread_spin_init); 43122071Sdeischen__weak_reference(_pthread_spin_destroy, pthread_spin_destroy); 44122071Sdeischen__weak_reference(_pthread_spin_trylock, pthread_spin_trylock); 45122071Sdeischen__weak_reference(_pthread_spin_lock, pthread_spin_lock); 46122071Sdeischen__weak_reference(_pthread_spin_unlock, pthread_spin_unlock); 47122071Sdeischen 48119909Sdavidxuint 49122071Sdeischen_pthread_spin_init(pthread_spinlock_t *lock, int pshared) 50119909Sdavidxu{ 51119909Sdavidxu struct pthread_spinlock *lck; 52119909Sdavidxu int ret; 53119909Sdavidxu 54119909Sdavidxu if (lock == NULL || pshared != PTHREAD_PROCESS_PRIVATE) 55119909Sdavidxu ret = EINVAL; 56119909Sdavidxu else if ((lck = malloc(sizeof(struct pthread_spinlock))) == NULL) 57119909Sdavidxu ret = ENOMEM; 58119909Sdavidxu else { 59119909Sdavidxu lck->s_lock = 0; 60119909Sdavidxu lck->s_owner= NULL; 61119909Sdavidxu *lock = lck; 62119909Sdavidxu ret = 0; 63119909Sdavidxu } 64119909Sdavidxu 65119909Sdavidxu return (ret); 66119909Sdavidxu} 67119909Sdavidxu 68119909Sdavidxuint 69122071Sdeischen_pthread_spin_destroy(pthread_spinlock_t *lock) 70119909Sdavidxu{ 71119909Sdavidxu int ret; 72119909Sdavidxu 73119909Sdavidxu if (lock == NULL || *lock == NULL) 74119909Sdavidxu ret = EINVAL; 75119909Sdavidxu else if ((*lock)->s_owner != NULL) 76119909Sdavidxu ret = EBUSY; 77119909Sdavidxu else { 78119909Sdavidxu free(*lock); 79119909Sdavidxu *lock = NULL; 80119909Sdavidxu ret = 0; 81119909Sdavidxu } 82119909Sdavidxu 83119909Sdavidxu return (ret); 84119909Sdavidxu} 85119909Sdavidxu 86119909Sdavidxuint 87122071Sdeischen_pthread_spin_trylock(pthread_spinlock_t *lock) 88119909Sdavidxu{ 89119909Sdavidxu struct pthread_spinlock *lck; 90119909Sdavidxu struct pthread *self = _pthread_self(); 91119909Sdavidxu int oldval, ret; 92119909Sdavidxu 93119909Sdavidxu if (lock == NULL || (lck = *lock) == NULL) 94119909Sdavidxu ret = EINVAL; 95119909Sdavidxu else if (lck->s_owner == self) 96119909Sdavidxu ret = EDEADLK; 97119909Sdavidxu else if (lck->s_lock != 0) 98119909Sdavidxu ret = EBUSY; 99119909Sdavidxu else { 100174112Sdeischen atomic_swap_int(&(lck)->s_lock, 1, &oldval); 101119909Sdavidxu if (oldval) 102119909Sdavidxu ret = EBUSY; 103119909Sdavidxu else { 104119909Sdavidxu lck->s_owner = _pthread_self(); 105119909Sdavidxu ret = 0; 106119909Sdavidxu } 107119909Sdavidxu } 108119909Sdavidxu return (ret); 109119909Sdavidxu} 110119909Sdavidxu 111119909Sdavidxuint 112122071Sdeischen_pthread_spin_lock(pthread_spinlock_t *lock) 113119909Sdavidxu{ 114119909Sdavidxu struct pthread_spinlock *lck; 115119909Sdavidxu struct pthread *self = _pthread_self(); 116119909Sdavidxu int count, oldval, ret; 117119909Sdavidxu 118119909Sdavidxu if (lock == NULL || (lck = *lock) == NULL) 119119909Sdavidxu ret = EINVAL; 120119909Sdavidxu else if (lck->s_owner == self) 121119909Sdavidxu ret = EDEADLK; 122119909Sdavidxu else { 123119909Sdavidxu do { 124119909Sdavidxu count = SPIN_COUNT; 125119909Sdavidxu while (lck->s_lock) { 126119909Sdavidxu#ifdef __i386__ 127119909Sdavidxu /* tell cpu we are spinning */ 128119909Sdavidxu __asm __volatile("pause"); 129119909Sdavidxu#endif 130119909Sdavidxu if (--count <= 0) { 131119909Sdavidxu count = SPIN_COUNT; 132119909Sdavidxu _pthread_yield(); 133119909Sdavidxu } 134119909Sdavidxu } 135174112Sdeischen atomic_swap_int(&(lck)->s_lock, 1, &oldval); 136119909Sdavidxu } while (oldval); 137119909Sdavidxu 138119909Sdavidxu lck->s_owner = self; 139119909Sdavidxu ret = 0; 140119909Sdavidxu } 141119909Sdavidxu 142119909Sdavidxu return (ret); 143119909Sdavidxu} 144119909Sdavidxu 145119909Sdavidxuint 146122071Sdeischen_pthread_spin_unlock(pthread_spinlock_t *lock) 147119909Sdavidxu{ 148119909Sdavidxu struct pthread_spinlock *lck; 149119909Sdavidxu int ret; 150119909Sdavidxu 151119909Sdavidxu if (lock == NULL || (lck = *lock) == NULL) 152119909Sdavidxu ret = EINVAL; 153119909Sdavidxu else { 154119909Sdavidxu if (lck->s_owner != _pthread_self()) 155119909Sdavidxu ret = EPERM; 156119909Sdavidxu else { 157119909Sdavidxu lck->s_owner = NULL; 158174112Sdeischen atomic_swap_int(&lck->s_lock, 0, &ret); 159119909Sdavidxu ret = 0; 160119909Sdavidxu } 161119909Sdavidxu } 162119909Sdavidxu 163119909Sdavidxu return (ret); 164119909Sdavidxu} 165119909Sdavidxu 166