xref: /dragonfly/lib/libc/sys/umtx.2 (revision 3b41d66a)
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.In unistd.h
46.Ft int
47.Fn umtx_sleep "const int *ptr" "int value" "int timeout"
48.Ft int
49.Fn umtx_wakeup "const int *ptr" "int count"
50.Sh DESCRIPTION
51The
52.Fn umtx_sleep
53system call will put the calling process to sleep for
54.Fa timeout
55microseconds if the contents of the specified pointer matches
56the specified value.
57Specifying a timeout of 0 indicates an indefinite timeout.
58The comparison is not atomic with the sleep but is properly
59interlocked against another process calling
60.Fn umtx_wakeup .
61In particular, while it is possible for two userland threads to race, one
62going to sleep simultaneously with another releasing the mutex, this condition
63is caught when the second userland thread calls
64.Fn umtx_wakeup
65after releasing the contended mutex.
66.Pp
67The
68.Fa timeout
69has no specific limitation other than what fits in the signed integer.
70A negative timeout will return
71.Er EINVAL .
72.Pp
73The
74.Fn umtx_wakeup
75system call will wakeup the specified number of processes sleeping
76in
77.Fn umtx_sleep
78on the specified user address.  A count of 0 will wake up all sleeping
79processes.  This function may wake up more processes then the specified
80count but will never wake up fewer processes (unless there are simply not
81that many currently sleeping on the address).  The current
82.Dx
83implementation optimized the count = 1 case but otherwise just wakes up
84all processes sleeping on the address.
85.Pp
86Kernel support for userland mutexes is based on the physical memory backing
87the user address.  Two userland programs may use this facility through
88.Fn mmap ,
89.Fn sysv ,
90.Fn rfork ,
91or light weight process-based shared memory.
92It is important to note that the kernel does not
93take responsibility for adjusting the contents of the mutex or for the
94userland implementation of the mutex.
95.Pp
96.Fn umtx_sleep
97does not restart in case of a signal, even if the signal specifies
98that system calls should restart.
99.Pp
100Various operating system events can cause
101.Fn umtx_sleep
102to return prematurely, with the contents of the mutex unchanged relative
103to the compare value.  Callers must be able to deal with such returns.
104.Sh RETURN VALUES
105.Fn umtx_sleep
106will return 0 if it successfully slept and was then woken up.  Otherwise
107it will return -1 and set
108.Va errno
109as shown below.
110.Pp
111.Fn umtx_wakeup
112will generally return 0 unless the address is bad.
113.Sh EXAMPLE
114.Bd -literal -compact
115
116void
117userland_get_mutex(struct umtx *mtx)
118{
119    int v;
120
121    for (;;) {
122	v = mtx->lock;
123	if ((v & MTX_LOCKED) == 0) {
124	    /*
125	     * not locked, attempt to lock.
126	     */
127	    if (cmp_and_exg(&mtx->lock, v, v | MTX_LOCKED) == 0)
128		return;
129	} else {
130	    /*
131	     * Locked, bump the contested count and obtain the contested
132	     * mutex.
133	     */
134	    if (cmp_and_exg(&mtx->lock, v, v + 1) == 0) {
135		userland_get_mutex_contested(mtx);
136		return;
137	    }
138	}
139    }
140}
141
142static void
143userland_get_mutex_contested(struct umtx *mtx)
144{
145    int v;
146
147    for (;;) {
148	v = mtx->lock;
149	assert(v & ~MTX_LOCKED);	/* our contesting count still there */
150	if ((v & MTX_LOCKED) == 0) {
151	    /*
152	     * not locked, attempt to remove our contested count and
153	     * lock at the same time.
154	     */
155	    if (cmp_and_exg(&mtx->lock, v, (v - 1) | MTX_LOCKED) == 0)
156		return;
157	} else {
158	    /*
159	     * Still locked, sleep and try again.
160	     */
161	    umtx_sleep(&mtx->lock, v, 0);
162	    /*
163	     * XXX note: if we are woken up here but do not proceed to
164	     * attempt to obtain the mutex, we should chain the
165	     * umtx_wakeup() along.
166	     */
167	}
168    }
169}
170
171void
172userland_rel_mutex(struct umtx *mtx)
173{
174    int v;
175
176    for (;;) {
177	v = mtx->lock;
178	assert(v & MTX_LOCKED);	/* we still have it locked */
179	if (v == MTX_LOCKED) {
180	    /*
181	     * We hold an uncontested lock, try to set to an unlocked
182	     * state.
183	     */
184	    if (cmp_and_exg(&mtx->lock, MTX_LOCKED, 0) == 0)
185		return;
186	} else {
187	    /*
188	     * We hold a contested lock, unlock and wakeup exactly
189	     * one sleeper.  It is possible for this to race a new
190	     * thread obtaining a lock, in which case any contested
191	     * sleeper we wake up will simply go back to sleep.
192	     */
193	    if (cmp_and_exg(&mtx->lock, v, v & ~MTX_LOCKED) == 0) {
194		umtx_wakeup(&mtx->lock, 1);
195		return;
196	    }
197	}
198    }
199}
200.Ed
201.Sh ERRORS
202.Bl -tag -width Er
203.It Bq Er EBUSY
204The contents of
205.Fa *ptr
206did not match
207.Fa value
208.It Bq Er EWOULDBLOCK
209The specified timeout occurred.
210.It Bq Er EINTR
211The
212.Fn umtx_sleep
213call was interrupted by a signal.
214.It Bq Er EINVAL
215An invalid parameter (typically an invalid timeout) was specified.
216.El
217.Sh SEE ALSO
218.Xr tls 2
219.Sh HISTORY
220The
221.Fn umtx_sleep ,
222and
223.Fn umtx_wakeup
224function calls first appeared in
225.Dx 1.1 .
226