mutex.h revision 1.6
1/* $NetBSD: mutex.h,v 1.6 2007/03/09 11:30:28 skrll Exp $ */ 2 3/*- 4 * Copyright (c) 2002, 2007 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39#ifndef _ARM_MUTEX_H_ 40#define _ARM_MUTEX_H_ 41 42/* 43 * The ARM mutex implementation is troublesome, because pre-v6 ARM lacks a 44 * compare-and-set operation. However, there aren't any MP pre-v6 ARM 45 * systems to speak of. We are mostly concerned with atomicity with respect 46 * to interrupts. 47 * 48 * SMP for spin mutexes is easy - we don't need to know who owns the lock. 49 * For adaptive mutexes, we need an additional interlock. 50 * 51 * Unfortunately, not all ARM kernels are linked at the same address, 52 * meaning we cannot safely overlay the interlock with the MSB of the 53 * owner field. 54 * 55 * For a mutex acquisition, we first grab the interlock and then set the 56 * owner field. 57 * 58 * There is room in the owners field for a waiters bit, but we don't do 59 * that because it would be hard to synchronize using one without a CAS 60 * operation. Because the waiters bit is only needed for adaptive mutexes, 61 * we instead use the lock that is normally used by spin mutexes to indicate 62 * waiters. 63 * 64 * Spin mutexes are initialized with the interlock held to cause the 65 * assembly stub to go through mutex_vector_enter(). 66 * 67 * When releasing an adaptive mutex, we first clear the owners field, and 68 * then check to see if the waiters byte is set. This ensures that there 69 * will always be someone to wake any sleeping waiters up (even it the mutex 70 * is acquired immediately after we release it, or if we are preempted 71 * immediatley after clearing the owners field). The setting or clearing of 72 * the waiters byte is serialized by the turnstile chain lock associated 73 * with the mutex. 74 * 75 * See comments in kern_mutex.c about releasing adaptive mutexes without 76 * an interlocking step. 77 */ 78 79#ifndef __MUTEX_PRIVATE 80 81struct kmutex { 82 uintptr_t mtx_pad1; 83 uint32_t mtx_pad2[2]; 84}; 85 86#else /* __MUTEX_PRIVATE */ 87 88struct kmutex { 89 volatile uintptr_t mtx_owner; /* 0-3 */ 90 __cpu_simple_lock_t mtx_interlock; /* 4 */ 91 __cpu_simple_lock_t mtx_lock; /* 5 */ 92 ipl_cookie_t mtx_ipl; /* 6 */ 93 uint8_t mtx_pad; /* 7 */ 94 uint32_t mtx_id; /* 8-11 */ 95}; 96 97#if 0 98#define __HAVE_MUTEX_STUBS 1 99#define __HAVE_SPIN_MUTEX_STUBS 1 100#endif 101 102static inline uintptr_t 103MUTEX_OWNER(uintptr_t owner) 104{ 105 return owner; 106} 107 108static inline int 109MUTEX_OWNED(uintptr_t owner) 110{ 111 return owner != 0; 112} 113 114static inline int 115MUTEX_SET_WAITERS(kmutex_t *mtx, uintptr_t owner) 116{ 117 (void)__cpu_simple_lock_try(&mtx->mtx_lock); 118 return mtx->mtx_owner != 0; 119} 120 121static inline void 122MUTEX_CLEAR_WAITERS(kmutex_t *mtx) 123{ 124 __cpu_simple_unlock(&mtx->mtx_lock); 125} 126 127static inline int 128MUTEX_HAS_WAITERS(volatile kmutex_t *mtx) 129{ 130 if (mtx->mtx_owner == 0) 131 return 0; 132 return mtx->mtx_lock == __SIMPLELOCK_LOCKED; 133} 134 135static inline void 136MUTEX_INITIALIZE_SPIN(kmutex_t *mtx, u_int id, int ipl) 137{ 138 mtx->mtx_id = (id << 1) | 1; 139 mtx->mtx_ipl = makeiplcookie(ipl); 140 mtx->mtx_interlock = __SIMPLELOCK_LOCKED; 141 __cpu_simple_lock_init(&mtx->mtx_lock); 142} 143 144static inline void 145MUTEX_INITIALIZE_ADAPTIVE(kmutex_t *mtx, u_int id) 146{ 147 mtx->mtx_id = (id << 1) | 0; 148 __cpu_simple_lock_init(&mtx->mtx_interlock); 149 __cpu_simple_lock_init(&mtx->mtx_lock); 150} 151 152static inline void 153MUTEX_DESTROY(kmutex_t *mtx) 154{ 155 mtx->mtx_owner = (uintptr_t)-1L; 156 mtx->mtx_id = ~0; 157} 158 159static inline u_int 160MUTEX_GETID(kmutex_t *mtx) 161{ 162 return mtx->mtx_id >> 1; 163} 164 165static inline bool 166MUTEX_SPIN_P(volatile kmutex_t *mtx) 167{ 168 return (mtx->mtx_id & 1) == 1; 169} 170 171static inline bool 172MUTEX_ADAPTIVE_P(volatile kmutex_t *mtx) 173{ 174 return (mtx->mtx_id & 1) == 0; 175} 176 177static inline int 178MUTEX_ACQUIRE(kmutex_t *mtx, uintptr_t curthread) 179{ 180 if (!__cpu_simple_lock_try(&mtx->mtx_interlock)) 181 return 0; 182 mtx->mtx_owner = curthread; 183 return 1; 184} 185 186static inline void 187MUTEX_RELEASE(kmutex_t *mtx) 188{ 189 mtx->mtx_owner = 0; 190 __cpu_simple_unlock(&mtx->mtx_lock); 191 __cpu_simple_unlock(&mtx->mtx_interlock); 192} 193 194#endif /* __MUTEX_PRIVATE */ 195 196#endif /* _ARM_MUTEX_H_ */ 197