xref: /freebsd/sys/sys/umtxvar.h (revision bcaa0b4c)
1af29f399SDmitry Chagin /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3af29f399SDmitry Chagin  *
4af29f399SDmitry Chagin  * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
5af29f399SDmitry Chagin  * All rights reserved.
6af29f399SDmitry Chagin  *
7af29f399SDmitry Chagin  * Redistribution and use in source and binary forms, with or without
8af29f399SDmitry Chagin  * modification, are permitted provided that the following conditions
9af29f399SDmitry Chagin  * are met:
10af29f399SDmitry Chagin  * 1. Redistributions of source code must retain the above copyright
11af29f399SDmitry Chagin  *    notice unmodified, this list of conditions, and the following
12af29f399SDmitry Chagin  *    disclaimer.
13af29f399SDmitry Chagin  * 2. Redistributions in binary form must reproduce the above copyright
14af29f399SDmitry Chagin  *    notice, this list of conditions and the following disclaimer in the
15af29f399SDmitry Chagin  *    documentation and/or other materials provided with the distribution.
16af29f399SDmitry Chagin  *
17af29f399SDmitry Chagin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18af29f399SDmitry Chagin  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19af29f399SDmitry Chagin  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20af29f399SDmitry Chagin  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21af29f399SDmitry Chagin  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22af29f399SDmitry Chagin  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23af29f399SDmitry Chagin  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24af29f399SDmitry Chagin  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25af29f399SDmitry Chagin  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26af29f399SDmitry Chagin  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27af29f399SDmitry Chagin  *
28af29f399SDmitry Chagin  */
29af29f399SDmitry Chagin 
30af29f399SDmitry Chagin #ifndef _SYS_UMTXVAR_H_
31af29f399SDmitry Chagin #define	_SYS_UMTXVAR_H_
32af29f399SDmitry Chagin 
33af29f399SDmitry Chagin #ifdef _KERNEL
34af29f399SDmitry Chagin 
35bcaa0b4cSOlivier Certner #include <sys/_timespec.h>
36bcaa0b4cSOlivier Certner 
37af29f399SDmitry Chagin /*
38af29f399SDmitry Chagin  * The umtx_key structure is used by both the Linux futex code and the
39af29f399SDmitry Chagin  * umtx implementation to map userland addresses to unique keys.
40af29f399SDmitry Chagin  */
41af29f399SDmitry Chagin enum {
42af29f399SDmitry Chagin 	TYPE_SIMPLE_WAIT,
43af29f399SDmitry Chagin 	TYPE_CV,
44af29f399SDmitry Chagin 	TYPE_SEM,
45af29f399SDmitry Chagin 	TYPE_SIMPLE_LOCK,
46af29f399SDmitry Chagin 	TYPE_NORMAL_UMUTEX,
47af29f399SDmitry Chagin 	TYPE_PI_UMUTEX,
48af29f399SDmitry Chagin 	TYPE_PP_UMUTEX,
49af29f399SDmitry Chagin 	TYPE_RWLOCK,
50af29f399SDmitry Chagin 	TYPE_FUTEX,
51af29f399SDmitry Chagin 	TYPE_SHM,
52af29f399SDmitry Chagin 	TYPE_PI_ROBUST_UMUTEX,
53af29f399SDmitry Chagin 	TYPE_PP_ROBUST_UMUTEX,
5420979f38SDmitry Chagin 	TYPE_PI_FUTEX,
55af29f399SDmitry Chagin };
56af29f399SDmitry Chagin 
57af29f399SDmitry Chagin /* Key to represent a unique userland synchronous object */
58af29f399SDmitry Chagin struct umtx_key {
59af29f399SDmitry Chagin 	int	hash;
60af29f399SDmitry Chagin 	int	type;
61af29f399SDmitry Chagin 	int	shared;
62af29f399SDmitry Chagin 	union {
63af29f399SDmitry Chagin 		struct {
64af29f399SDmitry Chagin 			struct vm_object *object;
65af29f399SDmitry Chagin 			uintptr_t	offset;
66af29f399SDmitry Chagin 		} shared;
67af29f399SDmitry Chagin 		struct {
68af29f399SDmitry Chagin 			struct vmspace	*vs;
69af29f399SDmitry Chagin 			uintptr_t	addr;
70af29f399SDmitry Chagin 		} private;
71af29f399SDmitry Chagin 		struct {
72af29f399SDmitry Chagin 			void		*a;
73af29f399SDmitry Chagin 			uintptr_t	b;
74af29f399SDmitry Chagin 		} both;
75af29f399SDmitry Chagin 	} info;
76af29f399SDmitry Chagin };
77af29f399SDmitry Chagin 
78af29f399SDmitry Chagin #define THREAD_SHARE		0
79af29f399SDmitry Chagin #define PROCESS_SHARE		1
80af29f399SDmitry Chagin #define AUTO_SHARE		2
81af29f399SDmitry Chagin 
82307a3dd3SDmitry Chagin struct umtx_abs_timeout {
83307a3dd3SDmitry Chagin 	int clockid;
84307a3dd3SDmitry Chagin 	bool is_abs_real;	/* TIMER_ABSTIME && CLOCK_REALTIME* */
85307a3dd3SDmitry Chagin 	struct timespec cur;
86307a3dd3SDmitry Chagin 	struct timespec end;
87307a3dd3SDmitry Chagin };
88307a3dd3SDmitry Chagin 
89af29f399SDmitry Chagin struct thread;
90af29f399SDmitry Chagin 
911fdcc87cSDmitry Chagin /* Priority inheritance mutex info. */
921fdcc87cSDmitry Chagin struct umtx_pi {
931fdcc87cSDmitry Chagin 	/* Owner thread */
941fdcc87cSDmitry Chagin 	struct thread		*pi_owner;
951fdcc87cSDmitry Chagin 
961fdcc87cSDmitry Chagin 	/* Reference count */
971fdcc87cSDmitry Chagin 	int			pi_refcount;
981fdcc87cSDmitry Chagin 
991fdcc87cSDmitry Chagin 	/* List entry to link umtx holding by thread */
1001fdcc87cSDmitry Chagin 	TAILQ_ENTRY(umtx_pi)	pi_link;
1011fdcc87cSDmitry Chagin 
1021fdcc87cSDmitry Chagin 	/* List entry in hash */
1031fdcc87cSDmitry Chagin 	TAILQ_ENTRY(umtx_pi)	pi_hashlink;
1041fdcc87cSDmitry Chagin 
1051fdcc87cSDmitry Chagin 	/* List for waiters */
1061fdcc87cSDmitry Chagin 	TAILQ_HEAD(,umtx_q)	pi_blocked;
1071fdcc87cSDmitry Chagin 
1081fdcc87cSDmitry Chagin 	/* Identify a userland lock object */
1091fdcc87cSDmitry Chagin 	struct umtx_key		pi_key;
1101fdcc87cSDmitry Chagin };
1111fdcc87cSDmitry Chagin 
1121fdcc87cSDmitry Chagin /* A userland synchronous object user. */
1131fdcc87cSDmitry Chagin struct umtx_q {
1141fdcc87cSDmitry Chagin 	/* Linked list for the hash. */
1151fdcc87cSDmitry Chagin 	TAILQ_ENTRY(umtx_q)	uq_link;
1161fdcc87cSDmitry Chagin 
1171fdcc87cSDmitry Chagin 	/* Umtx key. */
1181fdcc87cSDmitry Chagin 	struct umtx_key		uq_key;
1191fdcc87cSDmitry Chagin 
1201fdcc87cSDmitry Chagin 	/* Umtx flags. */
1211fdcc87cSDmitry Chagin 	int			uq_flags;
1221fdcc87cSDmitry Chagin #define UQF_UMTXQ	0x0001
1231fdcc87cSDmitry Chagin 
1247caa2911SDmitry Chagin 	/* Futex bitset mask */
1257caa2911SDmitry Chagin 	u_int			uq_bitset;
1267caa2911SDmitry Chagin 
1271fdcc87cSDmitry Chagin 	/* The thread waits on. */
1281fdcc87cSDmitry Chagin 	struct thread		*uq_thread;
1291fdcc87cSDmitry Chagin 
1301fdcc87cSDmitry Chagin 	/*
1311fdcc87cSDmitry Chagin 	 * Blocked on PI mutex. read can use chain lock
1321fdcc87cSDmitry Chagin 	 * or umtx_lock, write must have both chain lock and
1331fdcc87cSDmitry Chagin 	 * umtx_lock being hold.
1341fdcc87cSDmitry Chagin 	 */
1351fdcc87cSDmitry Chagin 	struct umtx_pi		*uq_pi_blocked;
1361fdcc87cSDmitry Chagin 
1371fdcc87cSDmitry Chagin 	/* On blocked list */
1381fdcc87cSDmitry Chagin 	TAILQ_ENTRY(umtx_q)	uq_lockq;
1391fdcc87cSDmitry Chagin 
1401fdcc87cSDmitry Chagin 	/* Thread contending with us */
1411fdcc87cSDmitry Chagin 	TAILQ_HEAD(,umtx_pi)	uq_pi_contested;
1421fdcc87cSDmitry Chagin 
1431fdcc87cSDmitry Chagin 	/* Inherited priority from PP mutex */
1441fdcc87cSDmitry Chagin 	u_char			uq_inherited_pri;
1451fdcc87cSDmitry Chagin 
1461fdcc87cSDmitry Chagin 	/* Spare queue ready to be reused */
1471fdcc87cSDmitry Chagin 	struct umtxq_queue	*uq_spare_queue;
1481fdcc87cSDmitry Chagin 
1491fdcc87cSDmitry Chagin 	/* The queue we on */
1501fdcc87cSDmitry Chagin 	struct umtxq_queue	*uq_cur_queue;
1511fdcc87cSDmitry Chagin };
1521fdcc87cSDmitry Chagin 
1531fdcc87cSDmitry Chagin TAILQ_HEAD(umtxq_head, umtx_q);
1541fdcc87cSDmitry Chagin 
1551fdcc87cSDmitry Chagin /* Per-key wait-queue */
1561fdcc87cSDmitry Chagin struct umtxq_queue {
1571fdcc87cSDmitry Chagin 	struct umtxq_head	head;
1581fdcc87cSDmitry Chagin 	struct umtx_key		key;
1591fdcc87cSDmitry Chagin 	LIST_ENTRY(umtxq_queue)	link;
1601fdcc87cSDmitry Chagin 	int			length;
1611fdcc87cSDmitry Chagin };
1621fdcc87cSDmitry Chagin 
1631fdcc87cSDmitry Chagin LIST_HEAD(umtxq_list, umtxq_queue);
1641fdcc87cSDmitry Chagin 
1651fdcc87cSDmitry Chagin /* Userland lock object's wait-queue chain */
1661fdcc87cSDmitry Chagin struct umtxq_chain {
1671fdcc87cSDmitry Chagin 	/* Lock for this chain. */
1681fdcc87cSDmitry Chagin 	struct mtx		uc_lock;
1691fdcc87cSDmitry Chagin 
1701fdcc87cSDmitry Chagin 	/* List of sleep queues. */
1711fdcc87cSDmitry Chagin 	struct umtxq_list	uc_queue[2];
1721fdcc87cSDmitry Chagin #define UMTX_SHARED_QUEUE	0
1731fdcc87cSDmitry Chagin #define UMTX_EXCLUSIVE_QUEUE	1
1741fdcc87cSDmitry Chagin 
1751fdcc87cSDmitry Chagin 	LIST_HEAD(, umtxq_queue) uc_spare_queue;
1761fdcc87cSDmitry Chagin 
1771fdcc87cSDmitry Chagin 	/* Busy flag */
1781fdcc87cSDmitry Chagin 	char			uc_busy;
1791fdcc87cSDmitry Chagin 
1801fdcc87cSDmitry Chagin 	/* Chain lock waiters */
1811fdcc87cSDmitry Chagin 	int			uc_waiters;
1821fdcc87cSDmitry Chagin 
1831fdcc87cSDmitry Chagin 	/* All PI in the list */
1841fdcc87cSDmitry Chagin 	TAILQ_HEAD(,umtx_pi)	uc_pi_list;
1851fdcc87cSDmitry Chagin 
1861fdcc87cSDmitry Chagin #ifdef UMTX_PROFILING
1871fdcc87cSDmitry Chagin 	u_int			length;
1881fdcc87cSDmitry Chagin 	u_int			max_length;
1891fdcc87cSDmitry Chagin #endif
1901fdcc87cSDmitry Chagin };
1911fdcc87cSDmitry Chagin 
192af29f399SDmitry Chagin static inline int
umtx_key_match(const struct umtx_key * k1,const struct umtx_key * k2)193af29f399SDmitry Chagin umtx_key_match(const struct umtx_key *k1, const struct umtx_key *k2)
194af29f399SDmitry Chagin {
195af29f399SDmitry Chagin 
196af29f399SDmitry Chagin 	return (k1->type == k2->type &&
197af29f399SDmitry Chagin 	    k1->info.both.a == k2->info.both.a &&
198af29f399SDmitry Chagin 	    k1->info.both.b == k2->info.both.b);
199af29f399SDmitry Chagin }
200af29f399SDmitry Chagin 
201307a3dd3SDmitry Chagin void umtx_abs_timeout_init(struct umtx_abs_timeout *, int, int,
202307a3dd3SDmitry Chagin     const struct timespec *);
203af29f399SDmitry Chagin int umtx_copyin_timeout(const void *, struct timespec *);
204af29f399SDmitry Chagin void umtx_exec(struct proc *p);
205af29f399SDmitry Chagin int umtx_key_get(const void *, int, int, struct umtx_key *);
206af29f399SDmitry Chagin void umtx_key_release(struct umtx_key *);
207af29f399SDmitry Chagin struct umtx_q *umtxq_alloc(void);
2081fdcc87cSDmitry Chagin void umtxq_busy(struct umtx_key *);
2091fdcc87cSDmitry Chagin int umtxq_count(struct umtx_key *);
210af29f399SDmitry Chagin void umtxq_free(struct umtx_q *);
2111fdcc87cSDmitry Chagin struct umtxq_chain *umtxq_getchain(struct umtx_key *);
2121fdcc87cSDmitry Chagin void umtxq_insert_queue(struct umtx_q *, int);
2131fdcc87cSDmitry Chagin void umtxq_remove_queue(struct umtx_q *, int);
2148e4d22c0SDmitry Chagin int umtxq_requeue(struct umtx_key *, int, struct umtx_key *, int);
2157caa2911SDmitry Chagin int umtxq_signal_mask(struct umtx_key *, int, u_int);
2161fdcc87cSDmitry Chagin int umtxq_sleep(struct umtx_q *, const char *,
2171fdcc87cSDmitry Chagin     struct umtx_abs_timeout *);
21809f55e60SDmitry Chagin int umtxq_sleep_pi(struct umtx_q *, struct umtx_pi *, uint32_t,
21909f55e60SDmitry Chagin     const char *, struct umtx_abs_timeout *, bool);
2201fdcc87cSDmitry Chagin void umtxq_unbusy(struct umtx_key *);
22109f55e60SDmitry Chagin void umtxq_unbusy_unlocked(struct umtx_key *);
222af29f399SDmitry Chagin int kern_umtx_wake(struct thread *, void *, int, int);
223af29f399SDmitry Chagin void umtx_pi_adjust(struct thread *, u_char);
22409f55e60SDmitry Chagin struct umtx_pi *umtx_pi_alloc(int);
22509f55e60SDmitry Chagin int umtx_pi_claim(struct umtx_pi *, struct thread *);
2269e32efa7SDmitry Chagin int umtx_pi_drop(struct thread *, struct umtx_key *, bool, int *);
22709f55e60SDmitry Chagin void umtx_pi_free(struct umtx_pi *);
22809f55e60SDmitry Chagin void umtx_pi_insert(struct umtx_pi *);
22909f55e60SDmitry Chagin struct umtx_pi *umtx_pi_lookup(struct umtx_key *);
23009f55e60SDmitry Chagin void umtx_pi_ref(struct umtx_pi *);
23109f55e60SDmitry Chagin void umtx_pi_unref(struct umtx_pi *);
232af29f399SDmitry Chagin void umtx_thread_init(struct thread *);
233af29f399SDmitry Chagin void umtx_thread_fini(struct thread *);
234af29f399SDmitry Chagin void umtx_thread_alloc(struct thread *);
235af29f399SDmitry Chagin void umtx_thread_exit(struct thread *);
236af29f399SDmitry Chagin 
2371fdcc87cSDmitry Chagin #define umtxq_insert(uq)	umtxq_insert_queue((uq), UMTX_SHARED_QUEUE)
2381fdcc87cSDmitry Chagin #define umtxq_remove(uq)	umtxq_remove_queue((uq), UMTX_SHARED_QUEUE)
2391fdcc87cSDmitry Chagin 
2401fdcc87cSDmitry Chagin /*
2411fdcc87cSDmitry Chagin  * Lock a chain.
2421fdcc87cSDmitry Chagin  *
2431fdcc87cSDmitry Chagin  * The code is a macro so that file/line information is taken from the caller.
2441fdcc87cSDmitry Chagin  */
2451fdcc87cSDmitry Chagin #define umtxq_lock(key) do {		\
2461fdcc87cSDmitry Chagin 	struct umtx_key *_key = (key);	\
2471fdcc87cSDmitry Chagin 	struct umtxq_chain *_uc;	\
2481fdcc87cSDmitry Chagin 					\
2491fdcc87cSDmitry Chagin 	_uc = umtxq_getchain(_key);	\
2501fdcc87cSDmitry Chagin 	mtx_lock(&_uc->uc_lock);	\
2511fdcc87cSDmitry Chagin } while (0)
2521fdcc87cSDmitry Chagin 
2531fdcc87cSDmitry Chagin /*
2541fdcc87cSDmitry Chagin  * Unlock a chain.
2551fdcc87cSDmitry Chagin  */
2561fdcc87cSDmitry Chagin static inline void
umtxq_unlock(struct umtx_key * key)2571fdcc87cSDmitry Chagin umtxq_unlock(struct umtx_key *key)
2581fdcc87cSDmitry Chagin {
2591fdcc87cSDmitry Chagin 	struct umtxq_chain *uc;
2601fdcc87cSDmitry Chagin 
2611fdcc87cSDmitry Chagin 	uc = umtxq_getchain(key);
2621fdcc87cSDmitry Chagin 	mtx_unlock(&uc->uc_lock);
2631fdcc87cSDmitry Chagin }
2641fdcc87cSDmitry Chagin 
265af29f399SDmitry Chagin #endif /* _KERNEL */
266af29f399SDmitry Chagin #endif /* !_SYS_UMTXVAR_H_ */
267