thr_spinlock.c revision 174112
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: head/lib/libkse/thread/thr_spinlock.c 174112 2007-11-30 17:20:29Z deischen $ 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 68LT10_COMPAT_PRIVATE(_spinlock); 69LT10_COMPAT_PRIVATE(_spinlock_debug); 70LT10_COMPAT_PRIVATE(_spinunlock); 71 72/* 73 * These are for compatability only. Spinlocks of this type 74 * are deprecated. 75 */ 76 77void 78_spinunlock(spinlock_t *lck) 79{ 80 struct spinlock_extra *sl_extra; 81 82 sl_extra = ((nv_spinlock_t *)lck)->extra; 83 _pthread_mutex_unlock(&sl_extra->lock); 84} 85 86/* 87 * Lock a location for the running thread. Yield to allow other 88 * threads to run if this thread is blocked because the lock is 89 * not available. Note that this function does not sleep. It 90 * assumes that the lock will be available very soon. 91 */ 92void 93_spinlock(spinlock_t *lck) 94{ 95 struct spinlock_extra *sl_extra; 96 97 if (!__isthreaded) 98 PANIC("Spinlock called when not threaded."); 99 if (!initialized) 100 PANIC("Spinlocks not initialized."); 101 /* 102 * Try to grab the lock and loop if another thread grabs 103 * it before we do. 104 */ 105 if (lck->fname == NULL) 106 init_spinlock(lck); 107 sl_extra = ((nv_spinlock_t *)lck)->extra; 108 _pthread_mutex_lock(&sl_extra->lock); 109} 110 111/* 112 * Lock a location for the running thread. Yield to allow other 113 * threads to run if this thread is blocked because the lock is 114 * not available. Note that this function does not sleep. It 115 * assumes that the lock will be available very soon. 116 * 117 * This function checks if the running thread has already locked the 118 * location, warns if this occurs and creates a thread dump before 119 * returning. 120 */ 121void 122_spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused) 123{ 124 _spinlock(lck); 125} 126 127static void 128init_spinlock(spinlock_t *lck) 129{ 130 _pthread_mutex_lock(&spinlock_static_lock); 131 if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) { 132 lck->fname = (char *)&extra[spinlock_count]; 133 extra[spinlock_count].owner = lck; 134 spinlock_count++; 135 } 136 _pthread_mutex_unlock(&spinlock_static_lock); 137 if (lck->fname == NULL) 138 PANIC("Exceeded max spinlocks"); 139} 140 141void 142_thr_spinlock_init(void) 143{ 144 int i; 145 146 if (initialized != 0) { 147 _thr_mutex_reinit(&spinlock_static_lock); 148 for (i = 0; i < spinlock_count; i++) 149 _thr_mutex_reinit(&extra[i].lock); 150 } else { 151 if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr)) 152 PANIC("Cannot initialize spinlock_static_lock"); 153 for (i = 0; i < MAX_SPINLOCKS; i++) { 154 if (_pthread_mutex_init(&extra[i].lock, &static_mattr)) 155 PANIC("Cannot initialize spinlock extra"); 156 } 157 initialized = 1; 158 } 159} 160