/
mutex.h
212 lines (187 loc) · 6.26 KB
/
mutex.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
/* $NetBSD: mutex.h,v 1.16 2008/04/28 20:24:11 martin Exp $ */
/*-
* Copyright (c) 2002, 2006, 2007, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe and Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_MUTEX_H_
#define _SYS_MUTEX_H_
/*
* There are 2 types of mutexes:
*
* * Adaptive -- If the lock is already held, the thread attempting
* to acquire the lock determines if the thread that holds it is
* currently running. If so, it spins, else it sleeps.
*
* * Spin -- If the lock is already held, the thread attempting to
* acquire the lock spins. The IPL will be raised on entry.
*
* Machine dependent code must provide the following:
*
* struct mutex
* The actual mutex structure. This structure is mostly
* opaque to machine-independent code; most access are done
* through macros. However, machine-independent code must
* be able to access the following members:
*
* uintptr_t mtx_owner
* ipl_cookie_t mtx_ipl
* __cpu_simple_lock_t mtx_lock
*
* If an architecture can be considered 'simple' (no interlock required in
* the MP case, or no MP) it need only define __HAVE_SIMPLE_MUTEXES and
* provide the following:
*
* struct mutex
*
* [additionally:]
* volatile integer mtx_id
*
* MUTEX_RECEIVE(mtx)
* Post a load fence after acquiring the mutex, if necessary.
*
* MUTEX_GIVE(mtx)
* Post a load/store fence after releasing the mutex, if
* necessary.
*
* MUTEX_CAS(ptr, old, new)
* Perform an atomic "compare and swap" operation and
* evaluate to true or false according to the success
*
* Otherwise, the following must be defined:
*
* MUTEX_INITIALIZE_SPIN(mtx, dodebug, minipl)
* Initialize a spin mutex.
*
* MUTEX_INITIALIZE_ADAPTIVE(mtx, dodebug)
* Initialize an adaptive mutex.
*
* MUTEX_DESTROY(mtx)
* Tear down a mutex.
*
* MUTEX_ADAPTIVE_P(mtx)
* Evaluates to true if the mutex is an adaptive mutex.
*
* MUTEX_SPIN_P(mtx)
* Evaluates to true if the mutex is a spin mutex.
*
* MUTEX_OWNER(owner)
* Returns the owner of the adaptive mutex (LWP address).
*
* MUTEX_OWNED(owner)
* Returns non-zero if an adaptive mutex is currently
* held by an LWP.
*
* MUTEX_HAS_WAITERS(mtx)
* Returns true if the mutex has waiters.
*
* MUTEX_SET_WAITERS(mtx)
* Mark the mutex has having waiters.
*
* MUTEX_ACQUIRE(mtx, owner)
* Try to acquire an adaptive mutex such that:
* if (lock held OR waiters)
* return 0;
* else
* return 1;
* Must be MP/interrupt atomic.
*
* MUTEX_RELEASE(mtx)
* Release the lock and clear the "has waiters" indication.
* Must be interrupt atomic, need not be MP safe.
*
* MUTEX_DEBUG_P(mtx)
* Evaluates to true if the mutex is initialized with
* dodebug==true. Only used in the LOCKDEBUG case.
*
* Machine dependent code may optionally provide stubs for the following
* functions to implement the easy (unlocked / no waiters) cases. If
* these stubs are provided, __HAVE_MUTEX_STUBS should be defined.
*
* mutex_enter()
* mutex_exit()
*
* Two additional stubs may be implemented that handle only the spinlock
* case, primarily for the scheduler. These should not be documented for
* or used by device drivers. __HAVE_SPIN_MUTEX_STUBS should be defined
* if these are provided:
*
* mutex_spin_enter()
* mutex_spin_exit()
*/
#if defined(_KERNEL_OPT)
#include "opt_lockdebug.h"
#endif
#if !defined(_KERNEL)
#include <sys/types.h>
#include <sys/inttypes.h>
#endif
typedef enum kmutex_type_t {
MUTEX_SPIN = 0, /* To get a spin mutex at IPL_NONE */
MUTEX_ADAPTIVE = 1, /* For porting code written for Solaris */
MUTEX_DEFAULT = 2, /* The only native, endorsed type */
MUTEX_DRIVER = 3, /* For porting code written for Solaris */
MUTEX_NODEBUG = 4 /* Disables LOCKDEBUG; use with care */
} kmutex_type_t;
typedef struct kmutex kmutex_t;
#if defined(__MUTEX_PRIVATE)
#define MUTEX_THREAD ((uintptr_t)-16L)
#define MUTEX_BIT_SPIN 0x01
#define MUTEX_BIT_WAITERS 0x02
#define MUTEX_BIT_DEBUG 0x04
#define MUTEX_SPIN_IPL(mtx) ((mtx)->mtx_ipl)
#define MUTEX_SPIN_OLDSPL(ci) ((ci)->ci_mtx_oldspl)
void mutex_vector_enter(kmutex_t *);
void mutex_vector_exit(kmutex_t *);
void mutex_spin_retry(kmutex_t *);
void mutex_wakeup(kmutex_t *);
#endif /* __MUTEX_PRIVATE */
#ifdef _KERNEL
#include <sys/intr.h>
#endif
#include <machine/mutex.h>
/*
* Return true if no spin mutexes are held by the current CPU.
*/
#ifndef MUTEX_NO_SPIN_ACTIVE_P
#define MUTEX_NO_SPIN_ACTIVE_P(ci) ((ci)->ci_mtx_count == 0)
#endif
#ifdef _KERNEL
void mutex_init(kmutex_t *, kmutex_type_t, int);
void mutex_destroy(kmutex_t *);
void mutex_enter(kmutex_t *);
void mutex_exit(kmutex_t *);
void mutex_spin_enter(kmutex_t *);
void mutex_spin_exit(kmutex_t *);
int mutex_tryenter(kmutex_t *);
int mutex_owned(kmutex_t *);
lwp_t *mutex_owner(kmutex_t *);
void mutex_obj_init(void);
kmutex_t *mutex_obj_alloc(kmutex_type_t, int);
void mutex_obj_hold(kmutex_t *);
bool mutex_obj_free(kmutex_t *);
#endif /* _KERNEL */
#endif /* _SYS_MUTEX_H_ */