1 /* $OpenBSD: mutex.c,v 1.17 2019/04/23 13:35:12 visa 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 #ifdef MULTIPROCESSOR 38 /* Note: lock must be 16-byte aligned. */ 39 #define __mtx_lock(mtx) ((int *)(((vaddr_t)mtx->mtx_lock + 0xf) & ~0xf)) 40 #endif 41 42 void 43 __mtx_init(struct mutex *mtx, int wantipl) 44 { 45 #ifdef MULTIPROCESSOR 46 mtx->mtx_lock[0] = 1; 47 mtx->mtx_lock[1] = 1; 48 mtx->mtx_lock[2] = 1; 49 mtx->mtx_lock[3] = 1; 50 #endif 51 mtx->mtx_wantipl = wantipl; 52 mtx->mtx_oldipl = IPL_NONE; 53 mtx->mtx_owner = NULL; 54 } 55 56 #ifdef MULTIPROCESSOR 57 void 58 mtx_enter(struct mutex *mtx) 59 { 60 while (mtx_enter_try(mtx) == 0) 61 ; 62 } 63 64 int 65 mtx_enter_try(struct mutex *mtx) 66 { 67 struct cpu_info *ci = curcpu(); 68 volatile int *lock = __mtx_lock(mtx); 69 int ret; 70 int s; 71 72 if (mtx->mtx_wantipl != IPL_NONE) 73 s = splraise(mtx->mtx_wantipl); 74 75 #ifdef DIAGNOSTIC 76 if (__predict_false(mtx->mtx_owner == ci)) 77 panic("mtx %p: locking against myself", mtx); 78 #endif 79 80 asm volatile ( 81 "ldcws 0(%2), %0" 82 : "=&r" (ret), "+m" (lock) 83 : "r" (lock) 84 ); 85 86 if (ret) { 87 membar_enter(); 88 mtx->mtx_owner = ci; 89 if (mtx->mtx_wantipl != IPL_NONE) 90 mtx->mtx_oldipl = s; 91 #ifdef DIAGNOSTIC 92 ci->ci_mutex_level++; 93 #endif 94 95 return (1); 96 } 97 98 if (mtx->mtx_wantipl != IPL_NONE) 99 splx(s); 100 101 return (0); 102 } 103 #else 104 void 105 mtx_enter(struct mutex *mtx) 106 { 107 struct cpu_info *ci = curcpu(); 108 109 #ifdef DIAGNOSTIC 110 if (__predict_false(mtx->mtx_owner == ci)) 111 panic("mtx %p: locking against myself", mtx); 112 #endif 113 114 if (mtx->mtx_wantipl != IPL_NONE) 115 mtx->mtx_oldipl = splraise(mtx->mtx_wantipl); 116 117 mtx->mtx_owner = ci; 118 119 #ifdef DIAGNOSTIC 120 ci->ci_mutex_level++; 121 #endif 122 } 123 124 int 125 mtx_enter_try(struct mutex *mtx) 126 { 127 mtx_enter(mtx); 128 return (1); 129 } 130 #endif 131 132 void 133 mtx_leave(struct mutex *mtx) 134 { 135 #ifdef MULTIPROCESSOR 136 volatile int *lock = __mtx_lock(mtx); 137 #endif 138 int s; 139 140 MUTEX_ASSERT_LOCKED(mtx); 141 142 #ifdef DIAGNOSTIC 143 curcpu()->ci_mutex_level--; 144 #endif 145 s = mtx->mtx_oldipl; 146 mtx->mtx_owner = NULL; 147 #ifdef MULTIPROCESSOR 148 membar_exit(); 149 *lock = 1; 150 #endif 151 152 if (mtx->mtx_wantipl != IPL_NONE) 153 splx(s); 154 } 155