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