xref: /dragonfly/lib/libc/sys/umtx.2 (revision 82730a9c)
1.\" Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
2.\"
3.\" This code is derived from software contributed to The DragonFly Project
4.\" by Matthew Dillon <dillon@backplane.com>
5.\"
6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions
8.\" are met:
9.\"
10.\" 1. Redistributions of source code must retain the above copyright
11.\"    notice, this list of conditions and the following disclaimer.
12.\" 2. Redistributions in binary form must reproduce the above copyright
13.\"    notice, this list of conditions and the following disclaimer in
14.\"    the documentation and/or other materials provided with the
15.\"    distribution.
16.\" 3. Neither the name of The DragonFly Project nor the names of its
17.\"    contributors may be used to endorse or promote products derived
18.\"    from this software without specific, prior written permission.
19.\"
20.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31.\" SUCH DAMAGE.
32.\"
33.\" $DragonFly: src/lib/libc/sys/umtx.2,v 1.12 2008/04/14 20:17:41 dillon Exp $
34.\"
35.Dd February 21, 2005
36.Dt UMTX 2
37.Os
38.Sh NAME
39.Nm umtx_sleep ,
40.Nm umtx_wakeup
41.Nd kernel support for userland mutexes
42.Sh LIBRARY
43.Lb libc
44.Sh SYNOPSIS
45.Ft int
46.Fn umtx_sleep "const int *ptr" "int value" "int timeout"
47.Ft int
48.Fn umtx_wakeup "const int *ptr" "int count"
49.Sh DESCRIPTION
50The
51.Fn umtx_sleep
52system call will put the calling process to sleep for
53.Fa timeout
54microseconds if the contents of the specified pointer matches
55the specified value.
56Specifying a timeout of 0 indicates an indefinite timeout.
57The comparison is not atomic with the sleep but is properly
58interlocked against another process calling
59.Fn umtx_wakeup .
60In particular, while it is possible for two userland threads to race, one
61going to sleep simultaneously with another releasing the mutex, this condition
62is caught when the second userland thread calls
63.Fn umtx_wakeup
64after releasing the contended mutex.
65.Pp
66The
67.Fa timeout
68has no specific limitation other than what fits in the signed integer.
69A negative timeout will return
70.Er EINVAL .
71.Pp
72The
73.Fn umtx_wakeup
74system call will wakeup the specified number of processes sleeping
75in
76.Fn umtx_sleep
77on the specified user address.  A count of 0 will wake up all sleeping
78processes.  This function may wake up more processes then the specified
79count but will never wake up fewer processes (unless there are simply not
80that many currently sleeping on the address).  The current
81.Dx
82implementation optimized the count = 1 case but otherwise just wakes up
83all processes sleeping on the address.
84.Pp
85Kernel support for userland mutexes is based on the physical memory backing
86the user address.  Two userland programs may use this facility through
87.Fn mmap ,
88.Fn sysv ,
89.Fn rfork ,
90or light weight process-based shared memory.
91It is important to note that the kernel does not
92take responsibility for adjusting the contents of the mutex or for the
93userland implementation of the mutex.
94.Pp
95.Fn umtx_sleep
96does not restart in case of a signal, even if the signal specifies
97that system calls should restart.
98.Pp
99Various operating system events can cause
100.Fn umtx_sleep
101to return prematurely, with the contents of the mutex unchanged relative
102to the compare value.  Callers must be able to deal with such returns.
103.Sh RETURN VALUES
104.Fn umtx_sleep
105will return 0 if it successfully slept and was then woken up.  Otherwise
106it will return -1 and set
107.Va errno
108as shown below.
109.Pp
110.Fn umtx_wakeup
111will generally return 0 unless the address is bad.
112.Sh EXAMPLE
113.Bd -literal -compact
114
115void
116userland_get_mutex(struct umtx *mtx)
117{
118    int v;
119
120    for (;;) {
121	v = mtx->lock;
122	if ((v & MTX_LOCKED) == 0) {
123	    /*
124	     * not locked, attempt to lock.
125	     */
126	    if (cmp_and_exg(&mtx->lock, v, v | MTX_LOCKED) == 0)
127		return;
128	} else {
129	    /*
130	     * Locked, bump the contested count and obtain the contested
131	     * mutex.
132	     */
133	    if (cmp_and_exg(&mtx->lock, v, v + 1) == 0) {
134		userland_get_mutex_contested(mtx);
135		return;
136	    }
137	}
138    }
139}
140
141static void
142userland_get_mutex_contested(struct umtx *mtx)
143{
144    int v;
145
146    for (;;) {
147	v = mtx->lock;
148	assert(v & ~MTX_LOCKED);	/* our contesting count still there */
149	if ((v & MTX_LOCKED) == 0) {
150	    /*
151	     * not locked, attempt to remove our contested count and
152	     * lock at the same time.
153	     */
154	    if (cmp_and_exg(&mtx->lock, v, (v - 1) | MTX_LOCKED) == 0)
155		return;
156	} else {
157	    /*
158	     * Still locked, sleep and try again.
159	     */
160	    umtx_sleep(&mtx->lock, v, 0);
161	    /*
162	     * XXX note: if we are woken up here but do not proceed to
163	     * attempt to obtain the mutex, we should chain the
164	     * umtx_wakeup() along.
165	     */
166	}
167    }
168}
169
170void
171userland_rel_mutex(struct umtx *mtx)
172{
173    int v;
174
175    for (;;) {
176	v = mtx->lock;
177	assert(v & MTX_LOCKED);	/* we still have it locked */
178	if (v == MTX_LOCKED) {
179	    /*
180	     * We hold an uncontested lock, try to set to an unlocked
181	     * state.
182	     */
183	    if (cmp_and_exg(&mtx->lock, MTX_LOCKED, 0) == 0)
184		return;
185	} else {
186	    /*
187	     * We hold a contested lock, unlock and wakeup exactly
188	     * one sleeper.  It is possible for this to race a new
189	     * thread obtaining a lock, in which case any contested
190	     * sleeper we wake up will simply go back to sleep.
191	     */
192	    if (cmp_and_exg(&mtx->lock, v, v & ~MTX_LOCKED) == 0) {
193		umtx_wakeup(&mtx->lock, 1);
194		return;
195	    }
196	}
197    }
198}
199.Ed
200.Sh ERRORS
201.Bl -tag -width Er
202.It Bq Er EBUSY
203The contents of
204.Fa *ptr
205did not match
206.Fa value
207.It Bq Er EWOULDBLOCK
208The specified timeout occurred.
209.It Bq Er EINTR
210The
211.Fn umtx_sleep
212call was interrupted by a signal.
213.It Bq Er EINVAL
214An invalid parameter (typically an invalid timeout) was specified.
215.El
216.Sh SEE ALSO
217.Xr tls 2
218.Sh HISTORY
219The
220.Fn umtx_sleep ,
221and
222.Fn umtx_wakeup
223function calls first appeared in
224.Dx 1.1 .
225