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