1/* 2 * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 * 31 */ 32 33#include "namespace.h" 34#include <sys/types.h> 35#include <machine/atomic.h> 36#include <pthread.h> 37#include <libc_private.h> 38#include "un-namespace.h" 39#include "spinlock.h" 40#include "thr_private.h" 41 42#define MAX_SPINLOCKS 72 43 44struct spinlock_extra { 45 spinlock_t *owner; 46 pthread_mutex_t lock; 47}; 48 49struct nv_spinlock { 50 long access_lock; 51 long lock_owner; 52 struct spinlock_extra *extra; /* overlays fname in spinlock_t */ 53 int lineno; 54}; 55typedef struct nv_spinlock nv_spinlock_t; 56 57static void init_spinlock(spinlock_t *lck); 58 59static struct pthread_mutex_attr static_mutex_attr = 60 PTHREAD_MUTEXATTR_STATIC_INITIALIZER; 61static pthread_mutexattr_t static_mattr = &static_mutex_attr; 62 63static pthread_mutex_t spinlock_static_lock; 64static struct spinlock_extra extra[MAX_SPINLOCKS]; 65static int spinlock_count = 0; 66static int initialized = 0; 67 68/* 69 * These are for compatability only. Spinlocks of this type 70 * are deprecated. 71 */ 72 73void 74_spinunlock(spinlock_t *lck) 75{ 76 struct spinlock_extra *sl_extra; 77 78 sl_extra = ((nv_spinlock_t *)lck)->extra; 79 _pthread_mutex_unlock(&sl_extra->lock); 80} 81 82/* 83 * Lock a location for the running thread. Yield to allow other 84 * threads to run if this thread is blocked because the lock is 85 * not available. Note that this function does not sleep. It 86 * assumes that the lock will be available very soon. 87 */ 88void 89_spinlock(spinlock_t *lck) 90{ 91 struct spinlock_extra *sl_extra; 92 93 if (!__isthreaded) 94 PANIC("Spinlock called when not threaded."); 95 if (!initialized) 96 PANIC("Spinlocks not initialized."); 97 /* 98 * Try to grab the lock and loop if another thread grabs 99 * it before we do. 100 */ 101 if (lck->fname == NULL) 102 init_spinlock(lck); 103 sl_extra = ((nv_spinlock_t *)lck)->extra; 104 _pthread_mutex_lock(&sl_extra->lock); 105} 106 107/* 108 * Lock a location for the running thread. Yield to allow other 109 * threads to run if this thread is blocked because the lock is 110 * not available. Note that this function does not sleep. It 111 * assumes that the lock will be available very soon. 112 * 113 * This function checks if the running thread has already locked the 114 * location, warns if this occurs and creates a thread dump before 115 * returning. 116 */ 117void 118_spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused) 119{ 120 _spinlock(lck); 121} 122 123static void 124init_spinlock(spinlock_t *lck) 125{ 126 _pthread_mutex_lock(&spinlock_static_lock); 127 if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) { 128 lck->fname = (char *)&extra[spinlock_count]; 129 extra[spinlock_count].owner = lck; 130 spinlock_count++; 131 } 132 _pthread_mutex_unlock(&spinlock_static_lock); 133 if (lck->fname == NULL) 134 PANIC("Exceeded max spinlocks"); 135} 136 137void 138_thr_spinlock_init(void) 139{ 140 int i; 141 142 if (initialized != 0) { 143 _thr_mutex_reinit(&spinlock_static_lock); 144 for (i = 0; i < spinlock_count; i++) 145 _thr_mutex_reinit(&extra[i].lock); 146 } else { 147 if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr)) 148 PANIC("Cannot initialize spinlock_static_lock"); 149 for (i = 0; i < MAX_SPINLOCKS; i++) { 150 if (_pthread_mutex_init(&extra[i].lock, &static_mattr)) 151 PANIC("Cannot initialize spinlock extra"); 152 } 153 initialized = 1; 154 } 155} 156