135509Sjb/* 235509Sjb * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>. 335509Sjb * All rights reserved. 435509Sjb * 535509Sjb * Redistribution and use in source and binary forms, with or without 635509Sjb * modification, are permitted provided that the following conditions 735509Sjb * are met: 835509Sjb * 1. Redistributions of source code must retain the above copyright 935509Sjb * notice, this list of conditions and the following disclaimer. 1035509Sjb * 2. Redistributions in binary form must reproduce the above copyright 1135509Sjb * notice, this list of conditions and the following disclaimer in the 1235509Sjb * documentation and/or other materials provided with the distribution. 13165967Simp * 3. Neither the name of the author nor the names of any co-contributors 1435509Sjb * may be used to endorse or promote products derived from this software 1535509Sjb * without specific prior written permission. 1635509Sjb * 1735509Sjb * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 1835509Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1935509Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2049439Sdeischen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2135509Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2235509Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2335509Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2435509Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2535509Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2635509Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2735509Sjb * SUCH DAMAGE. 2835509Sjb * 2950476Speter * $FreeBSD$ 3035509Sjb * 3135509Sjb */ 3235509Sjb 33174112Sdeischen#include "namespace.h" 34114187Sdeischen#include <sys/types.h> 35114187Sdeischen#include <machine/atomic.h> 36174112Sdeischen#include <pthread.h> 3793399Smarkm#include <libc_private.h> 38174112Sdeischen#include "un-namespace.h" 39113658Sdeischen#include "spinlock.h" 40103388Smini#include "thr_private.h" 4135509Sjb 42154288Sjasone#define MAX_SPINLOCKS 72 43115381Sdeischen 44115381Sdeischenstruct spinlock_extra { 45122073Sdeischen spinlock_t *owner; 46123314Sdavidxu pthread_mutex_t lock; 47115381Sdeischen}; 48115381Sdeischen 49174112Sdeischenstruct nv_spinlock { 50174112Sdeischen long access_lock; 51174112Sdeischen long lock_owner; 52174112Sdeischen struct spinlock_extra *extra; /* overlays fname in spinlock_t */ 53174112Sdeischen int lineno; 54174112Sdeischen}; 55174112Sdeischentypedef struct nv_spinlock nv_spinlock_t; 56174112Sdeischen 57115381Sdeischenstatic void init_spinlock(spinlock_t *lck); 58115381Sdeischen 59139023Sdeischenstatic struct pthread_mutex_attr static_mutex_attr = 60139023Sdeischen PTHREAD_MUTEXATTR_STATIC_INITIALIZER; 61139023Sdeischenstatic pthread_mutexattr_t static_mattr = &static_mutex_attr; 62139023Sdeischen 63123314Sdavidxustatic pthread_mutex_t spinlock_static_lock; 64115381Sdeischenstatic struct spinlock_extra extra[MAX_SPINLOCKS]; 65115381Sdeischenstatic int spinlock_count = 0; 66115381Sdeischenstatic int initialized = 0; 67115381Sdeischen 68113658Sdeischen/* 69113658Sdeischen * These are for compatability only. Spinlocks of this type 70113658Sdeischen * are deprecated. 71113658Sdeischen */ 72113658Sdeischen 73112665Sjeffvoid 74112665Sjeff_spinunlock(spinlock_t *lck) 75112665Sjeff{ 76174112Sdeischen struct spinlock_extra *sl_extra; 77114187Sdeischen 78174112Sdeischen sl_extra = ((nv_spinlock_t *)lck)->extra; 79174112Sdeischen _pthread_mutex_unlock(&sl_extra->lock); 80112665Sjeff} 81112665Sjeff 8235509Sjb/* 8335509Sjb * Lock a location for the running thread. Yield to allow other 8435509Sjb * threads to run if this thread is blocked because the lock is 8535509Sjb * not available. Note that this function does not sleep. It 8635509Sjb * assumes that the lock will be available very soon. 8735509Sjb */ 8835509Sjbvoid 8936828Sjb_spinlock(spinlock_t *lck) 9035509Sjb{ 91174112Sdeischen struct spinlock_extra *sl_extra; 92114187Sdeischen 93123314Sdavidxu if (!__isthreaded) 94123314Sdavidxu PANIC("Spinlock called when not threaded."); 95123314Sdavidxu if (!initialized) 96123314Sdavidxu PANIC("Spinlocks not initialized."); 9736828Sjb /* 9836828Sjb * Try to grab the lock and loop if another thread grabs 9936828Sjb * it before we do. 10036828Sjb */ 101115381Sdeischen if (lck->fname == NULL) 102115381Sdeischen init_spinlock(lck); 103174112Sdeischen sl_extra = ((nv_spinlock_t *)lck)->extra; 104174112Sdeischen _pthread_mutex_lock(&sl_extra->lock); 10536828Sjb} 10636828Sjb 10736828Sjb/* 10836828Sjb * Lock a location for the running thread. Yield to allow other 10936828Sjb * threads to run if this thread is blocked because the lock is 11036828Sjb * not available. Note that this function does not sleep. It 11136828Sjb * assumes that the lock will be available very soon. 11236828Sjb * 11336828Sjb * This function checks if the running thread has already locked the 11436828Sjb * location, warns if this occurs and creates a thread dump before 11536828Sjb * returning. 11636828Sjb */ 11736828Sjbvoid 118174112Sdeischen_spinlock_debug(spinlock_t *lck, char *fname __unused, int lineno __unused) 11936828Sjb{ 120114187Sdeischen _spinlock(lck); 12135509Sjb} 122115381Sdeischen 123115381Sdeischenstatic void 124115381Sdeischeninit_spinlock(spinlock_t *lck) 125115381Sdeischen{ 126139023Sdeischen _pthread_mutex_lock(&spinlock_static_lock); 127115381Sdeischen if ((lck->fname == NULL) && (spinlock_count < MAX_SPINLOCKS)) { 128115381Sdeischen lck->fname = (char *)&extra[spinlock_count]; 129122073Sdeischen extra[spinlock_count].owner = lck; 130115381Sdeischen spinlock_count++; 131115381Sdeischen } 132139023Sdeischen _pthread_mutex_unlock(&spinlock_static_lock); 133123314Sdavidxu if (lck->fname == NULL) 134123314Sdavidxu PANIC("Exceeded max spinlocks"); 135115381Sdeischen} 136115381Sdeischen 137115381Sdeischenvoid 138115381Sdeischen_thr_spinlock_init(void) 139115381Sdeischen{ 140115381Sdeischen int i; 141115381Sdeischen 142115381Sdeischen if (initialized != 0) { 143123314Sdavidxu _thr_mutex_reinit(&spinlock_static_lock); 144123314Sdavidxu for (i = 0; i < spinlock_count; i++) 145123314Sdavidxu _thr_mutex_reinit(&extra[i].lock); 146122073Sdeischen } else { 147139023Sdeischen if (_pthread_mutex_init(&spinlock_static_lock, &static_mattr)) 148122073Sdeischen PANIC("Cannot initialize spinlock_static_lock"); 149115381Sdeischen for (i = 0; i < MAX_SPINLOCKS; i++) { 150139023Sdeischen if (_pthread_mutex_init(&extra[i].lock, &static_mattr)) 151122073Sdeischen PANIC("Cannot initialize spinlock extra"); 152115381Sdeischen } 153122073Sdeischen initialized = 1; 154115381Sdeischen } 155115381Sdeischen} 156