1 /* $NetBSD: mutex.h,v 1.20 2010/02/08 09:54:27 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2002, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef _SYS_MUTEX_H_ 33 #define _SYS_MUTEX_H_ 34 35 /* 36 * There are 2 types of mutexes: 37 * 38 * * Adaptive -- If the lock is already held, the thread attempting 39 * to acquire the lock determines if the thread that holds it is 40 * currently running. If so, it spins, else it sleeps. 41 * 42 * * Spin -- If the lock is already held, the thread attempting to 43 * acquire the lock spins. The IPL will be raised on entry. 44 * 45 * Machine dependent code must provide the following: 46 * 47 * struct mutex 48 * The actual mutex structure. This structure is mostly 49 * opaque to machine-independent code; most access are done 50 * through macros. However, machine-independent code must 51 * be able to access the following members: 52 * 53 * uintptr_t mtx_owner 54 * ipl_cookie_t mtx_ipl 55 * __cpu_simple_lock_t mtx_lock 56 * 57 * If an architecture can be considered 'simple' (no interlock required in 58 * the MP case, or no MP) it need only define __HAVE_SIMPLE_MUTEXES and 59 * provide the following: 60 * 61 * struct mutex 62 * 63 * [additionally:] 64 * volatile integer mtx_id 65 * 66 * MUTEX_RECEIVE(mtx) 67 * Post a load fence after acquiring the mutex, if necessary. 68 * 69 * MUTEX_GIVE(mtx) 70 * Post a load/store fence after releasing the mutex, if 71 * necessary. 72 * 73 * MUTEX_CAS(ptr, old, new) 74 * Perform an atomic "compare and swap" operation and 75 * evaluate to true or false according to the success 76 * 77 * Otherwise, the following must be defined: 78 * 79 * MUTEX_INITIALIZE_SPIN(mtx, dodebug, minipl) 80 * Initialize a spin mutex. 81 * 82 * MUTEX_INITIALIZE_ADAPTIVE(mtx, dodebug) 83 * Initialize an adaptive mutex. 84 * 85 * MUTEX_DESTROY(mtx) 86 * Tear down a mutex. 87 * 88 * MUTEX_ADAPTIVE_P(mtx) 89 * Evaluates to true if the mutex is an adaptive mutex. 90 * 91 * MUTEX_SPIN_P(mtx) 92 * Evaluates to true if the mutex is a spin mutex. 93 * 94 * MUTEX_OWNER(owner) 95 * Returns the owner of the adaptive mutex (LWP address). 96 * 97 * MUTEX_OWNED(owner) 98 * Returns non-zero if an adaptive mutex is currently 99 * held by an LWP. 100 * 101 * MUTEX_HAS_WAITERS(mtx) 102 * Returns true if the mutex has waiters. 103 * 104 * MUTEX_SET_WAITERS(mtx) 105 * Mark the mutex has having waiters. 106 * 107 * MUTEX_ACQUIRE(mtx, owner) 108 * Try to acquire an adaptive mutex such that: 109 * if (lock held OR waiters) 110 * return 0; 111 * else 112 * return 1; 113 * Must be MP/interrupt atomic. 114 * 115 * MUTEX_RELEASE(mtx) 116 * Release the lock and clear the "has waiters" indication. 117 * Must be interrupt atomic, need not be MP safe. 118 * 119 * MUTEX_DEBUG_P(mtx) 120 * Evaluates to true if the mutex is initialized with 121 * dodebug==true. Only used in the LOCKDEBUG case. 122 * 123 * Machine dependent code may optionally provide stubs for the following 124 * functions to implement the easy (unlocked / no waiters) cases. If 125 * these stubs are provided, __HAVE_MUTEX_STUBS should be defined. 126 * 127 * mutex_enter() 128 * mutex_exit() 129 * 130 * Two additional stubs may be implemented that handle only the spinlock 131 * case, primarily for the scheduler. __HAVE_SPIN_MUTEX_STUBS should be 132 * defined if these are provided: 133 * 134 * mutex_spin_enter() 135 * mutex_spin_exit() 136 */ 137 138 #if defined(_KERNEL_OPT) 139 #include "opt_lockdebug.h" 140 #endif 141 142 #if !defined(_KERNEL) 143 #include <sys/types.h> 144 #include <sys/inttypes.h> 145 #endif 146 147 typedef enum kmutex_type_t { 148 MUTEX_SPIN = 0, /* To get a spin mutex at IPL_NONE */ 149 MUTEX_ADAPTIVE = 1, /* For porting code written for Solaris */ 150 MUTEX_DEFAULT = 2, /* The only native, endorsed type */ 151 MUTEX_DRIVER = 3, /* For porting code written for Solaris */ 152 MUTEX_NODEBUG = 4 /* Disables LOCKDEBUG; use with care */ 153 } kmutex_type_t; 154 155 typedef struct kmutex kmutex_t; 156 157 #if defined(__MUTEX_PRIVATE) 158 159 #define MUTEX_THREAD ((uintptr_t)-16L) 160 161 #define MUTEX_BIT_SPIN 0x01 162 #define MUTEX_BIT_WAITERS 0x02 163 164 #if defined(LOCKDEBUG) 165 #define MUTEX_BIT_NODEBUG 0x04 /* LOCKDEBUG disabled */ 166 #else 167 #define MUTEX_BIT_NODEBUG 0x00 /* do nothing */ 168 #endif /* LOCKDEBUG */ 169 170 #define MUTEX_SPIN_IPL(mtx) ((mtx)->mtx_ipl) 171 #define MUTEX_SPIN_OLDSPL(ci) ((ci)->ci_mtx_oldspl) 172 173 void mutex_vector_enter(kmutex_t *); 174 void mutex_vector_exit(kmutex_t *); 175 void mutex_spin_retry(kmutex_t *); 176 void mutex_wakeup(kmutex_t *); 177 178 #endif /* __MUTEX_PRIVATE */ 179 180 #ifdef _KERNEL 181 #include <sys/intr.h> 182 #endif 183 184 #include <machine/mutex.h> 185 186 /* 187 * Return true if no spin mutexes are held by the current CPU. 188 */ 189 #ifndef MUTEX_NO_SPIN_ACTIVE_P 190 #define MUTEX_NO_SPIN_ACTIVE_P(ci) ((ci)->ci_mtx_count == 0) 191 #endif 192 193 #ifdef _KERNEL 194 195 void mutex_init(kmutex_t *, kmutex_type_t, int); 196 void mutex_destroy(kmutex_t *); 197 198 void mutex_enter(kmutex_t *); 199 void mutex_exit(kmutex_t *); 200 201 void mutex_spin_enter(kmutex_t *); 202 void mutex_spin_exit(kmutex_t *); 203 204 int mutex_tryenter(kmutex_t *); 205 206 int mutex_owned(kmutex_t *); 207 lwp_t *mutex_owner(kmutex_t *); 208 209 void mutex_obj_init(void); 210 kmutex_t *mutex_obj_alloc(kmutex_type_t, int); 211 void mutex_obj_hold(kmutex_t *); 212 bool mutex_obj_free(kmutex_t *); 213 214 #endif /* _KERNEL */ 215 216 #endif /* _SYS_MUTEX_H_ */ 217