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