1 /* $OpenBSD: mutex.c,v 1.15 2015/09/20 19:19:03 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Artur Grabowski <art@openbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/mutex.h> 30 #include <sys/systm.h> 31 #include <sys/atomic.h> 32 33 #include <machine/intr.h> 34 35 #include <ddb/db_output.h> 36 37 int __mtx_enter_try(struct mutex *); 38 39 #ifdef MULTIPROCESSOR 40 /* Note: lock must be 16-byte aligned. */ 41 #define __mtx_lock(mtx) ((int *)(((vaddr_t)mtx->mtx_lock + 0xf) & ~0xf)) 42 #endif 43 44 void 45 __mtx_init(struct mutex *mtx, int wantipl) 46 { 47 #ifdef MULTIPROCESSOR 48 mtx->mtx_lock[0] = 1; 49 mtx->mtx_lock[1] = 1; 50 mtx->mtx_lock[2] = 1; 51 mtx->mtx_lock[3] = 1; 52 #endif 53 mtx->mtx_wantipl = wantipl; 54 mtx->mtx_oldipl = IPL_NONE; 55 mtx->mtx_owner = NULL; 56 } 57 58 #ifdef MULTIPROCESSOR 59 void 60 mtx_enter(struct mutex *mtx) 61 { 62 while (mtx_enter_try(mtx) == 0) 63 ; 64 } 65 66 int 67 mtx_enter_try(struct mutex *mtx) 68 { 69 struct cpu_info *ci = curcpu(); 70 volatile int *lock = __mtx_lock(mtx); 71 int ret; 72 int s; 73 74 if (mtx->mtx_wantipl != IPL_NONE) 75 s = splraise(mtx->mtx_wantipl); 76 77 #ifdef DIAGNOSTIC 78 if (__predict_false(mtx->mtx_owner == ci)) 79 panic("mtx %p: locking against myself", mtx); 80 #endif 81 82 asm volatile ( 83 "ldcws 0(%2), %0" 84 : "=&r" (ret), "+m" (lock) 85 : "r" (lock) 86 ); 87 88 if (ret) { 89 membar_enter(); 90 mtx->mtx_owner = ci; 91 if (mtx->mtx_wantipl != IPL_NONE) 92 mtx->mtx_oldipl = s; 93 #ifdef DIAGNOSTIC 94 ci->ci_mutex_level++; 95 #endif 96 97 return (1); 98 } 99 100 if (mtx->mtx_wantipl != IPL_NONE) 101 splx(s); 102 103 return (0); 104 } 105 #else 106 void 107 mtx_enter(struct mutex *mtx) 108 { 109 struct cpu_info *ci = curcpu(); 110 111 #ifdef DIAGNOSTIC 112 if (__predict_false(mtx->mtx_owner == ci)) 113 panic("mtx %p: locking against myself", mtx); 114 #endif 115 116 if (mtx->mtx_wantipl != IPL_NONE) 117 mtx->mtx_oldipl = splraise(mtx->mtx_wantipl); 118 119 mtx->mtx_owner = ci; 120 121 #ifdef DIAGNOSTIC 122 ci->ci_mutex_level++; 123 #endif 124 } 125 126 int 127 mtx_enter_try(struct mutex *mtx) 128 { 129 mtx_enter(mtx); 130 return (1); 131 } 132 #endif 133 134 void 135 mtx_leave(struct mutex *mtx) 136 { 137 #ifdef MULTIPROCESSOR 138 volatile int *lock = __mtx_lock(mtx); 139 #endif 140 int s; 141 142 MUTEX_ASSERT_LOCKED(mtx); 143 144 #ifdef DIAGNOSTIC 145 curcpu()->ci_mutex_level--; 146 #endif 147 s = mtx->mtx_oldipl; 148 mtx->mtx_owner = NULL; 149 #ifdef MULTIPROCESSOR 150 membar_exit(); 151 *lock = 1; 152 #endif 153 154 if (mtx->mtx_wantipl != IPL_NONE) 155 splx(s); 156 } 157