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
__mtx_init(struct mutex * mtx,int wantipl)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
mtx_enter(struct mutex * mtx)58 mtx_enter(struct mutex *mtx)
59 {
60 while (mtx_enter_try(mtx) == 0)
61 ;
62 }
63
64 int
mtx_enter_try(struct mutex * mtx)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
mtx_enter(struct mutex * mtx)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
mtx_enter_try(struct mutex * mtx)125 mtx_enter_try(struct mutex *mtx)
126 {
127 mtx_enter(mtx);
128 return (1);
129 }
130 #endif
131
132 void
mtx_leave(struct mutex * mtx)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