umtx.h revision 139427
1163712Simp/*
2163712Simp * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
3163712Simp * All rights reserved.
4163712Simp *
5163712Simp * Redistribution and use in source and binary forms, with or without
6163712Simp * modification, are permitted provided that the following conditions
7163712Simp * are met:
8163712Simp * 1. Redistributions of source code must retain the above copyright
9163712Simp *    notice unmodified, this list of conditions, and the following
10163712Simp *    disclaimer.
11163712Simp * 2. Redistributions in binary form must reproduce the above copyright
12163712Simp *    notice, this list of conditions and the following disclaimer in the
13163712Simp *    documentation and/or other materials provided with the distribution.
14163712Simp *
15163712Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16163712Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17163712Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18163712Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19163712Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20163712Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21163712Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22163712Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23163712Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24163712Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25163712Simp *
26163712Simp * $FreeBSD: head/sys/sys/umtx.h 139427 2004-12-30 02:56:17Z davidxu $
27163712Simp *
28163712Simp */
29163712Simp
30163712Simp#ifndef _SYS_UMTX_H_
31163712Simp#define	_SYS_UMTX_H_
32163712Simp
33163712Simp#include <sys/limits.h>
34163712Simp
35163712Simp/*
36163712Simp * See pthread_*
37163712Simp */
38163712Simp
39163712Simp#define	UMTX_UNOWNED	0x0
40163712Simp#define	UMTX_CONTESTED	LONG_MIN
41163712Simp
42163712Simpstruct umtx {
43163712Simp	void	*u_owner;	/* Owner of the mutex. */
44163712Simp};
45163712Simp
46163712Simp/* op code for _umtx_op */
47163712Simp#define UMTX_OP_LOCK		0
48163712Simp#define UMTX_OP_UNLOCK		1
49163712Simp#define UMTX_OP_WAIT		2
50163712Simp#define UMTX_OP_WAKE		3
51163712Simp
52163712Simp#ifndef _KERNEL
53163712Simp
54163712Simp/*
55185996Ssbruno * System calls for acquiring and releasing contested mutexes.
56163712Simp */
57163712Simp/* deprecated becaues it can only use thread id */
58185996Ssbrunoint _umtx_lock(struct umtx *mtx);
59185996Ssbruno/* deprecated becaues it can only use thread id */
60185996Ssbrunoint _umtx_unlock(struct umtx *mtx);
61185996Ssbrunoint _umtx_op(struct umtx *umtx, int op, long id, void *uaddr, void *uaddr2);
62185996Ssbruno
63185996Ssbruno/*
64163712Simp * Standard api.  Try uncontested acquire/release and asks the
65185996Ssbruno * kernel to resolve failures.
66163712Simp */
67163712Simpstatic __inline void
68163712Simpumtx_init(struct umtx *umtx)
69163712Simp{
70163712Simp	umtx->u_owner = UMTX_UNOWNED;
71163712Simp}
72163712Simp
73163712Simpstatic __inline long
74163712Simpumtx_owner(struct umtx *umtx)
75163712Simp{
76163712Simp	return ((long)umtx->u_owner & ~LONG_MIN);
77163712Simp}
78163712Simp
79163712Simpstatic __inline int
80163712Simpumtx_lock(struct umtx *umtx, long id)
81163712Simp{
82163712Simp	if (atomic_cmpset_acq_ptr(&umtx->u_owner, (void *)UMTX_UNOWNED,
83163712Simp	    (void *)id) == 0)
84163712Simp		if (_umtx_op(umtx, UMTX_OP_LOCK, id, 0, 0) == -1)
85163712Simp			return (errno);
86163712Simp	return (0);
87163712Simp}
88163712Simp
89163712Simpstatic __inline int
90163712Simpumtx_trylock(struct umtx *umtx, long id)
91163712Simp{
92163712Simp	if (atomic_cmpset_acq_ptr(&umtx->u_owner, (void *)UMTX_UNOWNED,
93163712Simp	    (void *)id) == 0)
94163712Simp		return (EBUSY);
95163712Simp	return (0);
96163712Simp}
97228990Suqs
98163712Simpstatic __inline int
99163712Simpumtx_timedlock(struct umtx *umtx, long id, const struct timespec *abstime)
100163712Simp{
101163712Simp	if (atomic_cmpset_acq_ptr(&umtx->u_owner, (void *)UMTX_UNOWNED,
102163712Simp	    (void *)id) == 0)
103163712Simp		if (_umtx_op(umtx, UMTX_OP_LOCK, id, 0, (void *)abstime) == -1)
104163712Simp			return (errno);
105163712Simp	return (0);
106163712Simp}
107163712Simp
108163712Simpstatic __inline int
109163712Simpumtx_unlock(struct umtx *umtx, long id)
110163712Simp{
111163712Simp	if (atomic_cmpset_rel_ptr(&umtx->u_owner, (void *)id,
112163712Simp	    (void *)UMTX_UNOWNED) == 0)
113163712Simp		if (_umtx_op(umtx, UMTX_OP_UNLOCK, id, 0, 0) == -1)
114163712Simp			return (errno);
115163712Simp	return (0);
116163712Simp}
117163712Simp
118163712Simp/* Unlock umtx and wait on a user address. */
119163712Simp
120163712Simpstatic __inline int
121163712Simpumtx_wait(struct umtx *umtx, long id)
122293290Sbdrewery{
123163712Simp	if (_umtx_op(umtx, UMTX_OP_WAIT, id, 0, 0) == -1)
124163712Simp		return (errno);
125163712Simp	return (0);
126163712Simp}
127163712Simp
128163712Simpstatic __inline int
129163712Simpumtx_timedwait(struct umtx *umtx, long id, const struct timespec *abstime)
130163712Simp{
131163712Simp	if (_umtx_op(umtx, UMTX_OP_WAIT, id, 0, (void *)abstime) == -1)
132163712Simp		return (errno);
133163712Simp	return (0);
134163712Simp}
135163712Simp
136163712Simp/* Wake threads waiting on a user address. */
137163712Simpstatic __inline int
138163712Simpumtx_wake(struct umtx *umtx, int nr_wakeup)
139163712Simp{
140163712Simp	/* return how many threads were woke up, -1 if error */
141163712Simp	return _umtx_op(umtx, UMTX_OP_WAKE, nr_wakeup, 0, 0);
142163712Simp}
143163712Simp
144163712Simp#endif /* !_KERNEL */
145163712Simp#endif /* !_SYS_UMTX_H_ */
146163712Simp