1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.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 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30#ifndef _SYS_UMTXVAR_H_
31#define	_SYS_UMTXVAR_H_
32
33#ifdef _KERNEL
34
35#include <sys/_timespec.h>
36
37/*
38 * The umtx_key structure is used by both the Linux futex code and the
39 * umtx implementation to map userland addresses to unique keys.
40 */
41enum {
42	TYPE_SIMPLE_WAIT,
43	TYPE_CV,
44	TYPE_SEM,
45	TYPE_SIMPLE_LOCK,
46	TYPE_NORMAL_UMUTEX,
47	TYPE_PI_UMUTEX,
48	TYPE_PP_UMUTEX,
49	TYPE_RWLOCK,
50	TYPE_FUTEX,
51	TYPE_SHM,
52	TYPE_PI_ROBUST_UMUTEX,
53	TYPE_PP_ROBUST_UMUTEX,
54	TYPE_PI_FUTEX,
55};
56
57/* Key to represent a unique userland synchronous object */
58struct umtx_key {
59	int	hash;
60	int	type;
61	int	shared;
62	union {
63		struct {
64			struct vm_object *object;
65			uintptr_t	offset;
66		} shared;
67		struct {
68			struct vmspace	*vs;
69			uintptr_t	addr;
70		} private;
71		struct {
72			void		*a;
73			uintptr_t	b;
74		} both;
75	} info;
76};
77
78#define THREAD_SHARE		0
79#define PROCESS_SHARE		1
80#define AUTO_SHARE		2
81
82struct umtx_abs_timeout {
83	int clockid;
84	bool is_abs_real;	/* TIMER_ABSTIME && CLOCK_REALTIME* */
85	struct timespec cur;
86	struct timespec end;
87};
88
89struct thread;
90
91/* Priority inheritance mutex info. */
92struct umtx_pi {
93	/* Owner thread */
94	struct thread		*pi_owner;
95
96	/* Reference count */
97	int			pi_refcount;
98
99	/* List entry to link umtx holding by thread */
100	TAILQ_ENTRY(umtx_pi)	pi_link;
101
102	/* List entry in hash */
103	TAILQ_ENTRY(umtx_pi)	pi_hashlink;
104
105	/* List for waiters */
106	TAILQ_HEAD(,umtx_q)	pi_blocked;
107
108	/* Identify a userland lock object */
109	struct umtx_key		pi_key;
110};
111
112/* A userland synchronous object user. */
113struct umtx_q {
114	/* Linked list for the hash. */
115	TAILQ_ENTRY(umtx_q)	uq_link;
116
117	/* Umtx key. */
118	struct umtx_key		uq_key;
119
120	/* Umtx flags. */
121	int			uq_flags;
122#define UQF_UMTXQ	0x0001
123
124	/* Futex bitset mask */
125	u_int			uq_bitset;
126
127	/* The thread waits on. */
128	struct thread		*uq_thread;
129
130	/*
131	 * Blocked on PI mutex. read can use chain lock
132	 * or umtx_lock, write must have both chain lock and
133	 * umtx_lock being hold.
134	 */
135	struct umtx_pi		*uq_pi_blocked;
136
137	/* On blocked list */
138	TAILQ_ENTRY(umtx_q)	uq_lockq;
139
140	/* Thread contending with us */
141	TAILQ_HEAD(,umtx_pi)	uq_pi_contested;
142
143	/* Inherited priority from PP mutex */
144	u_char			uq_inherited_pri;
145
146	/* Spare queue ready to be reused */
147	struct umtxq_queue	*uq_spare_queue;
148
149	/* The queue we on */
150	struct umtxq_queue	*uq_cur_queue;
151};
152
153TAILQ_HEAD(umtxq_head, umtx_q);
154
155/* Per-key wait-queue */
156struct umtxq_queue {
157	struct umtxq_head	head;
158	struct umtx_key		key;
159	LIST_ENTRY(umtxq_queue)	link;
160	int			length;
161};
162
163LIST_HEAD(umtxq_list, umtxq_queue);
164
165/* Userland lock object's wait-queue chain */
166struct umtxq_chain {
167	/* Lock for this chain. */
168	struct mtx		uc_lock;
169
170	/* List of sleep queues. */
171	struct umtxq_list	uc_queue[2];
172#define UMTX_SHARED_QUEUE	0
173#define UMTX_EXCLUSIVE_QUEUE	1
174
175	LIST_HEAD(, umtxq_queue) uc_spare_queue;
176
177	/* Busy flag */
178	char			uc_busy;
179
180	/* Chain lock waiters */
181	int			uc_waiters;
182
183	/* All PI in the list */
184	TAILQ_HEAD(,umtx_pi)	uc_pi_list;
185
186#ifdef UMTX_PROFILING
187	u_int			length;
188	u_int			max_length;
189#endif
190};
191
192static inline int
193umtx_key_match(const struct umtx_key *k1, const struct umtx_key *k2)
194{
195
196	return (k1->type == k2->type &&
197	    k1->info.both.a == k2->info.both.a &&
198	    k1->info.both.b == k2->info.both.b);
199}
200
201void umtx_abs_timeout_init(struct umtx_abs_timeout *, int, int,
202    const struct timespec *);
203int umtx_copyin_timeout(const void *, struct timespec *);
204void umtx_exec(struct proc *p);
205int umtx_key_get(const void *, int, int, struct umtx_key *);
206void umtx_key_release(struct umtx_key *);
207struct umtx_q *umtxq_alloc(void);
208void umtxq_busy(struct umtx_key *);
209int umtxq_count(struct umtx_key *);
210void umtxq_free(struct umtx_q *);
211struct umtxq_chain *umtxq_getchain(struct umtx_key *);
212void umtxq_insert_queue(struct umtx_q *, int);
213void umtxq_remove_queue(struct umtx_q *, int);
214int umtxq_requeue(struct umtx_key *, int, struct umtx_key *, int);
215int umtxq_signal_mask(struct umtx_key *, int, u_int);
216int umtxq_sleep(struct umtx_q *, const char *,
217    struct umtx_abs_timeout *);
218int umtxq_sleep_pi(struct umtx_q *, struct umtx_pi *, uint32_t,
219    const char *, struct umtx_abs_timeout *, bool);
220void umtxq_unbusy(struct umtx_key *);
221void umtxq_unbusy_unlocked(struct umtx_key *);
222int kern_umtx_wake(struct thread *, void *, int, int);
223void umtx_pi_adjust(struct thread *, u_char);
224struct umtx_pi *umtx_pi_alloc(int);
225int umtx_pi_claim(struct umtx_pi *, struct thread *);
226int umtx_pi_drop(struct thread *, struct umtx_key *, bool, int *);
227void umtx_pi_free(struct umtx_pi *);
228void umtx_pi_insert(struct umtx_pi *);
229struct umtx_pi *umtx_pi_lookup(struct umtx_key *);
230void umtx_pi_ref(struct umtx_pi *);
231void umtx_pi_unref(struct umtx_pi *);
232void umtx_thread_init(struct thread *);
233void umtx_thread_fini(struct thread *);
234void umtx_thread_alloc(struct thread *);
235void umtx_thread_exit(struct thread *);
236
237#define umtxq_insert(uq)	umtxq_insert_queue((uq), UMTX_SHARED_QUEUE)
238#define umtxq_remove(uq)	umtxq_remove_queue((uq), UMTX_SHARED_QUEUE)
239
240/*
241 * Lock a chain.
242 *
243 * The code is a macro so that file/line information is taken from the caller.
244 */
245#define umtxq_lock(key) do {		\
246	struct umtx_key *_key = (key);	\
247	struct umtxq_chain *_uc;	\
248					\
249	_uc = umtxq_getchain(_key);	\
250	mtx_lock(&_uc->uc_lock);	\
251} while (0)
252
253/*
254 * Unlock a chain.
255 */
256static inline void
257umtxq_unlock(struct umtx_key *key)
258{
259	struct umtxq_chain *uc;
260
261	uc = umtxq_getchain(key);
262	mtx_unlock(&uc->uc_lock);
263}
264
265#endif /* _KERNEL */
266#endif /* !_SYS_UMTXVAR_H_ */
267