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