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