xref: /NextBSD/sys/compat/cloudabi/cloudabi_futex.c (revision c21ffb8d6aca32c9584cfa072f309a5890a21aea)
1 /*-
2  * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include <sys/param.h>
30 #include <sys/kernel.h>
31 #include <sys/limits.h>
32 #include <sys/lock.h>
33 #include <sys/malloc.h>
34 #include <sys/mutex.h>
35 #include <sys/proc.h>
36 #include <sys/sx.h>
37 #include <sys/systm.h>
38 #include <sys/umtx.h>
39 
40 #include <compat/cloudabi/cloudabi_proto.h>
41 #include <compat/cloudabi/cloudabi_syscalldefs.h>
42 #include <compat/cloudabi/cloudabi_util.h>
43 
44 /*
45  * Futexes for CloudABI.
46  *
47  * On most systems, futexes are implemented as objects of a single type
48  * on which a set of operations can be performed. CloudABI makes a clear
49  * distinction between locks and condition variables. A lock may have
50  * zero or more associated condition variables. A condition variable is
51  * always associated with exactly one lock. There is a strict topology.
52  * This approach has two advantages:
53  *
54  * - This topology is guaranteed to be acyclic. Requeueing of threads
55  *   only happens in one direction (from condition variables to locks).
56  *   This eases locking.
57  * - It means that a futex object for a lock exists when it is unlocked,
58  *   but has threads waiting on associated condition variables. Threads
59  *   can be requeued to a lock even if the thread performing the wakeup
60  *   does not have the lock mapped in its address space.
61  *
62  * This futex implementation only implements a single lock type, namely
63  * a read-write lock. A regular mutex type would not be necessary, as
64  * the read-write lock is as efficient as a mutex if used as such.
65  * Userspace futex locks are 32 bits in size:
66  *
67  * - 1 bit: has threads waiting in kernel-space.
68  * - 1 bit: is write-locked.
69  * - 30 bits:
70  *   - if write-locked: thread ID of owner.
71  *   - if not write-locked: number of read locks held.
72  *
73  * Condition variables are also 32 bits in size. Its value is modified
74  * by kernel-space exclusively. Zero indicates that it has no waiting
75  * threads. Non-zero indicates the opposite.
76  *
77  * This implementation is optimal, in the sense that it only wakes up
78  * threads if they can actually continue execution. It does not suffer
79  * from the thundering herd problem. If multiple threads waiting on a
80  * condition variable need to be woken up, only a single thread is
81  * scheduled. All other threads are 'donated' to this thread. After the
82  * thread manages to reacquire the lock, it requeues its donated threads
83  * to the lock.
84  *
85  * TODO(ed): Integrate this functionality into kern_umtx.c instead.
86  * TODO(ed): Store futex objects in a hash table.
87  * TODO(ed): Add actual priority inheritance.
88  * TODO(ed): Let futex_queue also take priorities into account.
89  * TODO(ed): Make locking fine-grained.
90  * TODO(ed): Perform sleeps until an actual absolute point in time,
91  *           instead of converting the timestamp to a relative value.
92  */
93 
94 struct futex_address;
95 struct futex_condvar;
96 struct futex_lock;
97 struct futex_queue;
98 struct futex_waiter;
99 
100 /* Identifier of a location in memory. */
101 struct futex_address {
102 	struct umtx_key			fa_key;
103 };
104 
105 /* A set of waiting threads. */
106 struct futex_queue {
107 	STAILQ_HEAD(, futex_waiter)	fq_list;
108 	unsigned int			fq_count;
109 };
110 
111 /* Condition variables. */
112 struct futex_condvar {
113 	/* Address of the condition variable. */
114 	struct futex_address		fc_address;
115 
116 	/* The lock the waiters should be moved to when signalled. */
117 	struct futex_lock *		fc_lock;
118 
119 	/* Threads waiting on the condition variable. */
120 	struct futex_queue		fc_waiters;
121 	/*
122 	 * Number of threads blocked on this condition variable, or
123 	 * being blocked on the lock after being requeued.
124 	 */
125 	unsigned int			fc_waitcount;
126 
127 	/* Global list pointers. */
128 	LIST_ENTRY(futex_condvar)	fc_next;
129 };
130 
131 /* Read-write locks. */
132 struct futex_lock {
133 	/* Address of the lock. */
134 	struct futex_address		fl_address;
135 
136 	/*
137 	 * Current owner of the lock. LOCK_UNMANAGED if the lock is
138 	 * currently not owned by the kernel. LOCK_OWNER_UNKNOWN in case
139 	 * the owner is not known (e.g., when the lock is read-locked).
140 	 */
141 	cloudabi_tid_t			fl_owner;
142 #define LOCK_UNMANAGED 0x0
143 #define LOCK_OWNER_UNKNOWN 0x1
144 
145 	/* Writers blocked on the lock. */
146 	struct futex_queue		fl_writers;
147 	/* Readers blocked on the lock. */
148 	struct futex_queue		fl_readers;
149 	/* Number of threads blocked on this lock + condition variables. */
150 	unsigned int			fl_waitcount;
151 
152 	/* Global list pointers. */
153 	LIST_ENTRY(futex_lock)		fl_next;
154 };
155 
156 /* Information associated with a thread blocked on an object. */
157 struct futex_waiter {
158 	/* Thread ID. */
159 	cloudabi_tid_t			fw_tid;
160 	/* Condition variable used for waiting. */
161 	struct cv			fw_wait;
162 
163 	/* Queue this waiter is currently placed in. */
164 	struct futex_queue *		fw_queue;
165 	/* List pointers of fw_queue. */
166 	STAILQ_ENTRY(futex_waiter)	fw_next;
167 
168 	/* Lock has been acquired. */
169 	bool				fw_locked;
170 	/* If not locked, threads that should block after acquiring. */
171 	struct futex_queue		fw_donated;
172 };
173 
174 /* Global data structures. */
175 static MALLOC_DEFINE(M_FUTEX, "futex", "CloudABI futex");
176 
177 static struct sx futex_global_lock;
178 SX_SYSINIT(futex_global_lock, &futex_global_lock, "CloudABI futex global lock");
179 
180 static LIST_HEAD(, futex_lock) futex_lock_list =
181     LIST_HEAD_INITIALIZER(&futex_lock_list);
182 static LIST_HEAD(, futex_condvar) futex_condvar_list =
183     LIST_HEAD_INITIALIZER(&futex_condvar_list);
184 
185 /* Utility functions. */
186 static void futex_lock_assert(const struct futex_lock *);
187 static struct futex_lock *futex_lock_lookup_locked(struct futex_address *);
188 static void futex_lock_release(struct futex_lock *);
189 static int futex_lock_tryrdlock(struct futex_lock *, cloudabi_lock_t *);
190 static int futex_lock_unmanage(struct futex_lock *, cloudabi_lock_t *);
191 static int futex_lock_update_owner(struct futex_lock *, cloudabi_lock_t *);
192 static int futex_lock_wake_up_next(struct futex_lock *, cloudabi_lock_t *);
193 static unsigned int futex_queue_count(const struct futex_queue *);
194 static void futex_queue_init(struct futex_queue *);
195 static void futex_queue_requeue(struct futex_queue *, struct futex_queue *,
196     unsigned int);
197 static int futex_queue_sleep(struct futex_queue *, struct futex_lock *,
198     struct futex_waiter *, struct thread *, cloudabi_clockid_t,
199     cloudabi_timestamp_t, cloudabi_timestamp_t);
200 static cloudabi_tid_t futex_queue_tid_best(const struct futex_queue *);
201 static void futex_queue_wake_up_all(struct futex_queue *);
202 static void futex_queue_wake_up_best(struct futex_queue *);
203 static void futex_queue_wake_up_donate(struct futex_queue *, unsigned int);
204 static int futex_user_load(uint32_t *, uint32_t *);
205 static int futex_user_store(uint32_t *, uint32_t);
206 static int futex_user_cmpxchg(uint32_t *, uint32_t, uint32_t *, uint32_t);
207 
208 /*
209  * futex_address operations.
210  */
211 
212 static int
futex_address_create(struct futex_address * fa,struct thread * td,const void * object,cloudabi_mflags_t scope)213 futex_address_create(struct futex_address *fa, struct thread *td,
214     const void *object, cloudabi_mflags_t scope)
215 {
216 
217 	KASSERT(td == curthread,
218 	    ("Can only create umtx keys for the current thread"));
219 	switch (scope) {
220 	case CLOUDABI_MAP_PRIVATE:
221 		return (umtx_key_get(object, TYPE_FUTEX, THREAD_SHARE,
222 		    &fa->fa_key));
223 	case CLOUDABI_MAP_SHARED:
224 		return (umtx_key_get(object, TYPE_FUTEX, AUTO_SHARE,
225 		    &fa->fa_key));
226 	default:
227 		return (EINVAL);
228 	}
229 }
230 
231 static void
futex_address_free(struct futex_address * fa)232 futex_address_free(struct futex_address *fa)
233 {
234 
235 	umtx_key_release(&fa->fa_key);
236 }
237 
238 static bool
futex_address_match(const struct futex_address * fa1,const struct futex_address * fa2)239 futex_address_match(const struct futex_address *fa1,
240     const struct futex_address *fa2)
241 {
242 
243 	return (umtx_key_match(&fa1->fa_key, &fa2->fa_key));
244 }
245 
246 /*
247  * futex_condvar operations.
248  */
249 
250 static void
futex_condvar_assert(const struct futex_condvar * fc)251 futex_condvar_assert(const struct futex_condvar *fc)
252 {
253 
254 	KASSERT(fc->fc_waitcount >= futex_queue_count(&fc->fc_waiters),
255 	    ("Total number of waiters cannot be smaller than the wait queue"));
256 	futex_lock_assert(fc->fc_lock);
257 }
258 
259 static int
futex_condvar_lookup(struct thread * td,const cloudabi_condvar_t * address,cloudabi_mflags_t scope,struct futex_condvar ** fcret)260 futex_condvar_lookup(struct thread *td, const cloudabi_condvar_t *address,
261     cloudabi_mflags_t scope, struct futex_condvar **fcret)
262 {
263 	struct futex_address fa_condvar;
264 	struct futex_condvar *fc;
265 	int error;
266 
267 	error = futex_address_create(&fa_condvar, td, address, scope);
268 	if (error != 0)
269 		return (error);
270 
271 	sx_xlock(&futex_global_lock);
272 	LIST_FOREACH(fc, &futex_condvar_list, fc_next) {
273 		if (futex_address_match(&fc->fc_address, &fa_condvar)) {
274 			/* Found matching lock object. */
275 			futex_address_free(&fa_condvar);
276 			futex_condvar_assert(fc);
277 			*fcret = fc;
278 			return (0);
279 		}
280 	}
281 	sx_xunlock(&futex_global_lock);
282 	futex_address_free(&fa_condvar);
283 	return (ENOENT);
284 }
285 
286 static int
futex_condvar_lookup_or_create(struct thread * td,const cloudabi_condvar_t * condvar,cloudabi_mflags_t condvar_scope,const cloudabi_lock_t * lock,cloudabi_mflags_t lock_scope,struct futex_condvar ** fcret)287 futex_condvar_lookup_or_create(struct thread *td,
288     const cloudabi_condvar_t *condvar, cloudabi_mflags_t condvar_scope,
289     const cloudabi_lock_t *lock, cloudabi_mflags_t lock_scope,
290     struct futex_condvar **fcret)
291 {
292 	struct futex_address fa_condvar, fa_lock;
293 	struct futex_condvar *fc;
294 	struct futex_lock *fl;
295 	int error;
296 
297 	error = futex_address_create(&fa_condvar, td, condvar, condvar_scope);
298 	if (error != 0)
299 		return (error);
300 	error = futex_address_create(&fa_lock, td, lock, lock_scope);
301 	if (error != 0) {
302 		futex_address_free(&fa_condvar);
303 		return (error);
304 	}
305 
306 	sx_xlock(&futex_global_lock);
307 	LIST_FOREACH(fc, &futex_condvar_list, fc_next) {
308 		if (!futex_address_match(&fc->fc_address, &fa_condvar))
309 			continue;
310 		fl = fc->fc_lock;
311 		if (!futex_address_match(&fl->fl_address, &fa_lock)) {
312 			/* Condition variable is owned by a different lock. */
313 			futex_address_free(&fa_condvar);
314 			futex_address_free(&fa_lock);
315 			sx_xunlock(&futex_global_lock);
316 			return (EINVAL);
317 		}
318 
319 		/* Found fully matching condition variable. */
320 		futex_address_free(&fa_condvar);
321 		futex_address_free(&fa_lock);
322 		futex_condvar_assert(fc);
323 		*fcret = fc;
324 		return (0);
325 	}
326 
327 	/* None found. Create new condition variable object. */
328 	fc = malloc(sizeof(*fc), M_FUTEX, M_WAITOK);
329 	fc->fc_address = fa_condvar;
330 	fc->fc_lock = futex_lock_lookup_locked(&fa_lock);
331 	futex_queue_init(&fc->fc_waiters);
332 	fc->fc_waitcount = 0;
333 	LIST_INSERT_HEAD(&futex_condvar_list, fc, fc_next);
334 	*fcret = fc;
335 	return (0);
336 }
337 
338 static void
futex_condvar_release(struct futex_condvar * fc)339 futex_condvar_release(struct futex_condvar *fc)
340 {
341 	struct futex_lock *fl;
342 
343 	futex_condvar_assert(fc);
344 	fl = fc->fc_lock;
345 	if (fc->fc_waitcount == 0) {
346 		/* Condition variable has no waiters. Deallocate it. */
347 		futex_address_free(&fc->fc_address);
348 		LIST_REMOVE(fc, fc_next);
349 		free(fc, M_FUTEX);
350 	}
351 	futex_lock_release(fl);
352 }
353 
354 static int
futex_condvar_unmanage(struct futex_condvar * fc,cloudabi_condvar_t * condvar)355 futex_condvar_unmanage(struct futex_condvar *fc,
356     cloudabi_condvar_t *condvar)
357 {
358 
359 	if (futex_queue_count(&fc->fc_waiters) != 0)
360 		return (0);
361 	return (futex_user_store(condvar, CLOUDABI_CONDVAR_HAS_NO_WAITERS));
362 }
363 
364 /*
365  * futex_lock operations.
366  */
367 
368 static void
futex_lock_assert(const struct futex_lock * fl)369 futex_lock_assert(const struct futex_lock *fl)
370 {
371 
372 	/*
373 	 * A futex lock can only be kernel-managed if it has waiters.
374 	 * Vice versa: if a futex lock has waiters, it must be
375 	 * kernel-managed.
376 	 */
377 	KASSERT((fl->fl_owner == LOCK_UNMANAGED) ==
378 	    (futex_queue_count(&fl->fl_readers) == 0 &&
379 	    futex_queue_count(&fl->fl_writers) == 0),
380 	    ("Managed locks must have waiting threads"));
381 	KASSERT(fl->fl_waitcount != 0 || fl->fl_owner == LOCK_UNMANAGED,
382 	    ("Lock with no waiters must be unmanaged"));
383 }
384 
385 static int
futex_lock_lookup(struct thread * td,const cloudabi_lock_t * address,cloudabi_mflags_t scope,struct futex_lock ** flret)386 futex_lock_lookup(struct thread *td, const cloudabi_lock_t *address,
387     cloudabi_mflags_t scope, struct futex_lock **flret)
388 {
389 	struct futex_address fa;
390 	int error;
391 
392 	error = futex_address_create(&fa, td, address, scope);
393 	if (error != 0)
394 		return (error);
395 
396 	sx_xlock(&futex_global_lock);
397 	*flret = futex_lock_lookup_locked(&fa);
398 	return (0);
399 }
400 
401 static struct futex_lock *
futex_lock_lookup_locked(struct futex_address * fa)402 futex_lock_lookup_locked(struct futex_address *fa)
403 {
404 	struct futex_lock *fl;
405 
406 	LIST_FOREACH(fl, &futex_lock_list, fl_next) {
407 		if (futex_address_match(&fl->fl_address, fa)) {
408 			/* Found matching lock object. */
409 			futex_address_free(fa);
410 			futex_lock_assert(fl);
411 			return (fl);
412 		}
413 	}
414 
415 	/* None found. Create new lock object. */
416 	fl = malloc(sizeof(*fl), M_FUTEX, M_WAITOK);
417 	fl->fl_address = *fa;
418 	fl->fl_owner = LOCK_UNMANAGED;
419 	futex_queue_init(&fl->fl_readers);
420 	futex_queue_init(&fl->fl_writers);
421 	fl->fl_waitcount = 0;
422 	LIST_INSERT_HEAD(&futex_lock_list, fl, fl_next);
423 	return (fl);
424 }
425 
426 static int
futex_lock_rdlock(struct futex_lock * fl,struct thread * td,cloudabi_lock_t * lock,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision)427 futex_lock_rdlock(struct futex_lock *fl, struct thread *td,
428     cloudabi_lock_t *lock, cloudabi_clockid_t clock_id,
429     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
430 {
431 	struct futex_waiter fw;
432 	int error;
433 
434 	error = futex_lock_tryrdlock(fl, lock);
435 	if (error == EBUSY) {
436 		/* Suspend execution. */
437 		KASSERT(fl->fl_owner != LOCK_UNMANAGED,
438 		    ("Attempted to sleep on an unmanaged lock"));
439 		error = futex_queue_sleep(&fl->fl_readers, fl, &fw, td,
440 		    clock_id, timeout, precision);
441 		KASSERT((error == 0) == fw.fw_locked,
442 		    ("Should have locked write lock on success"));
443 		KASSERT(futex_queue_count(&fw.fw_donated) == 0,
444 		    ("Lock functions cannot receive threads"));
445 	}
446 	if (error != 0)
447 		futex_lock_unmanage(fl, lock);
448 	return (error);
449 }
450 
451 static void
futex_lock_release(struct futex_lock * fl)452 futex_lock_release(struct futex_lock *fl)
453 {
454 
455 	futex_lock_assert(fl);
456 	if (fl->fl_waitcount == 0) {
457 		/* Lock object is unreferenced. Deallocate it. */
458 		KASSERT(fl->fl_owner == LOCK_UNMANAGED,
459 		    ("Attempted to free a managed lock"));
460 		futex_address_free(&fl->fl_address);
461 		LIST_REMOVE(fl, fl_next);
462 		free(fl, M_FUTEX);
463 	}
464 	sx_xunlock(&futex_global_lock);
465 }
466 
467 static int
futex_lock_unmanage(struct futex_lock * fl,cloudabi_lock_t * lock)468 futex_lock_unmanage(struct futex_lock *fl, cloudabi_lock_t *lock)
469 {
470 	cloudabi_lock_t cmp, old;
471 	int error;
472 
473 	if (futex_queue_count(&fl->fl_readers) == 0 &&
474 	    futex_queue_count(&fl->fl_writers) == 0) {
475 		/* Lock should be unmanaged. */
476 		fl->fl_owner = LOCK_UNMANAGED;
477 
478 		/* Clear kernel-managed bit. */
479 		error = futex_user_load(lock, &old);
480 		if (error != 0)
481 			return (error);
482 		for (;;) {
483 			cmp = old;
484 			error = futex_user_cmpxchg(lock, cmp, &old,
485 			    cmp & ~CLOUDABI_LOCK_KERNEL_MANAGED);
486 			if (error != 0)
487 				return (error);
488 			if (old == cmp)
489 				break;
490 		}
491 	}
492 	return (0);
493 }
494 
495 /* Sets an owner of a lock, based on a userspace lock value. */
496 static void
futex_lock_set_owner(struct futex_lock * fl,cloudabi_lock_t lock)497 futex_lock_set_owner(struct futex_lock *fl, cloudabi_lock_t lock)
498 {
499 
500 	/* Lock has no explicit owner. */
501 	if ((lock & ~CLOUDABI_LOCK_WRLOCKED) == 0) {
502 		fl->fl_owner = LOCK_OWNER_UNKNOWN;
503 		return;
504 	}
505 	lock &= ~(CLOUDABI_LOCK_WRLOCKED | CLOUDABI_LOCK_KERNEL_MANAGED);
506 
507 	/* Don't allow userspace to silently unlock. */
508 	if (lock == LOCK_UNMANAGED) {
509 		fl->fl_owner = LOCK_OWNER_UNKNOWN;
510 		return;
511 	}
512 	fl->fl_owner = lock;
513 }
514 
515 static int
futex_lock_unlock(struct futex_lock * fl,struct thread * td,cloudabi_lock_t * lock)516 futex_lock_unlock(struct futex_lock *fl, struct thread *td,
517     cloudabi_lock_t *lock)
518 {
519 	int error;
520 
521 	/* Validate that this thread is allowed to unlock. */
522 	error = futex_lock_update_owner(fl, lock);
523 	if (error != 0)
524 		return (error);
525 	if (fl->fl_owner != LOCK_UNMANAGED && fl->fl_owner != td->td_tid)
526 		return (EPERM);
527 	return (futex_lock_wake_up_next(fl, lock));
528 }
529 
530 /* Syncs in the owner of the lock from userspace if needed. */
531 static int
futex_lock_update_owner(struct futex_lock * fl,cloudabi_lock_t * address)532 futex_lock_update_owner(struct futex_lock *fl, cloudabi_lock_t *address)
533 {
534 	cloudabi_lock_t lock;
535 	int error;
536 
537 	if (fl->fl_owner == LOCK_OWNER_UNKNOWN) {
538 		error = futex_user_load(address, &lock);
539 		if (error != 0)
540 			return (error);
541 		futex_lock_set_owner(fl, lock);
542 	}
543 	return (0);
544 }
545 
546 static int
futex_lock_tryrdlock(struct futex_lock * fl,cloudabi_lock_t * address)547 futex_lock_tryrdlock(struct futex_lock *fl, cloudabi_lock_t *address)
548 {
549 	cloudabi_lock_t old, cmp;
550 	int error;
551 
552 	if (fl->fl_owner != LOCK_UNMANAGED) {
553 		/* Lock is already acquired. */
554 		return (EBUSY);
555 	}
556 
557 	old = CLOUDABI_LOCK_UNLOCKED;
558 	for (;;) {
559 		if ((old & CLOUDABI_LOCK_KERNEL_MANAGED) != 0) {
560 			/*
561 			 * Userspace lock is kernel-managed, even though
562 			 * the kernel disagrees.
563 			 */
564 			return (EINVAL);
565 		}
566 
567 		if ((old & CLOUDABI_LOCK_WRLOCKED) == 0) {
568 			/*
569 			 * Lock is not write-locked. Attempt to acquire
570 			 * it by increasing the read count.
571 			 */
572 			cmp = old;
573 			error = futex_user_cmpxchg(address, cmp, &old, cmp + 1);
574 			if (error != 0)
575 				return (error);
576 			if (old == cmp) {
577 				/* Success. */
578 				return (0);
579 			}
580 		} else {
581 			/* Lock is write-locked. Make it kernel-managed. */
582 			cmp = old;
583 			error = futex_user_cmpxchg(address, cmp, &old,
584 			    cmp | CLOUDABI_LOCK_KERNEL_MANAGED);
585 			if (error != 0)
586 				return (error);
587 			if (old == cmp) {
588 				/* Success. */
589 				futex_lock_set_owner(fl, cmp);
590 				return (EBUSY);
591 			}
592 		}
593 	}
594 }
595 
596 static int
futex_lock_trywrlock(struct futex_lock * fl,cloudabi_lock_t * address,cloudabi_tid_t tid,bool force_kernel_managed)597 futex_lock_trywrlock(struct futex_lock *fl, cloudabi_lock_t *address,
598     cloudabi_tid_t tid, bool force_kernel_managed)
599 {
600 	cloudabi_lock_t old, new, cmp;
601 	int error;
602 
603 	if (fl->fl_owner == tid) {
604 		/* Attempted to acquire lock recursively. */
605 		return (EDEADLK);
606 	}
607 	if (fl->fl_owner != LOCK_UNMANAGED) {
608 		/* Lock is already acquired. */
609 		return (EBUSY);
610 	}
611 
612 	old = CLOUDABI_LOCK_UNLOCKED;
613 	for (;;) {
614 		if ((old & CLOUDABI_LOCK_KERNEL_MANAGED) != 0) {
615 			/*
616 			 * Userspace lock is kernel-managed, even though
617 			 * the kernel disagrees.
618 			 */
619 			return (EINVAL);
620 		}
621 		if (old == (tid | CLOUDABI_LOCK_WRLOCKED)) {
622 			/* Attempted to acquire lock recursively. */
623 			return (EDEADLK);
624 		}
625 
626 		if (old == CLOUDABI_LOCK_UNLOCKED) {
627 			/* Lock is unlocked. Attempt to acquire it. */
628 			new = tid | CLOUDABI_LOCK_WRLOCKED;
629 			if (force_kernel_managed)
630 				new |= CLOUDABI_LOCK_KERNEL_MANAGED;
631 			error = futex_user_cmpxchg(address,
632 			    CLOUDABI_LOCK_UNLOCKED, &old, new);
633 			if (error != 0)
634 				return (error);
635 			if (old == CLOUDABI_LOCK_UNLOCKED) {
636 				/* Success. */
637 				if (force_kernel_managed)
638 					fl->fl_owner = tid;
639 				return (0);
640 			}
641 		} else {
642 			/* Lock is still locked. Make it kernel-managed. */
643 			cmp = old;
644 			error = futex_user_cmpxchg(address, cmp, &old,
645 			    cmp | CLOUDABI_LOCK_KERNEL_MANAGED);
646 			if (error != 0)
647 				return (error);
648 			if (old == cmp) {
649 				/* Success. */
650 				futex_lock_set_owner(fl, cmp);
651 				return (EBUSY);
652 			}
653 		}
654 	}
655 }
656 
657 static int
futex_lock_wake_up_next(struct futex_lock * fl,cloudabi_lock_t * lock)658 futex_lock_wake_up_next(struct futex_lock *fl, cloudabi_lock_t *lock)
659 {
660 	cloudabi_tid_t tid;
661 	int error;
662 
663 	/*
664 	 * Determine which thread(s) to wake up. Prefer waking up
665 	 * writers over readers to prevent write starvation.
666 	 */
667 	if (futex_queue_count(&fl->fl_writers) > 0) {
668 		/* Transfer ownership to a single write-locker. */
669 		if (futex_queue_count(&fl->fl_writers) > 1 ||
670 		    futex_queue_count(&fl->fl_readers) > 0) {
671 			/* Lock should remain managed afterwards. */
672 			tid = futex_queue_tid_best(&fl->fl_writers);
673 			error = futex_user_store(lock,
674 			    tid | CLOUDABI_LOCK_WRLOCKED |
675 			    CLOUDABI_LOCK_KERNEL_MANAGED);
676 			if (error != 0)
677 				return (error);
678 
679 			futex_queue_wake_up_best(&fl->fl_writers);
680 			fl->fl_owner = tid;
681 		} else {
682 			/* Lock can become unmanaged afterwards. */
683 			error = futex_user_store(lock,
684 			    futex_queue_tid_best(&fl->fl_writers) |
685 			    CLOUDABI_LOCK_WRLOCKED);
686 			if (error != 0)
687 				return (error);
688 
689 			futex_queue_wake_up_best(&fl->fl_writers);
690 			fl->fl_owner = LOCK_UNMANAGED;
691 		}
692 	} else {
693 		/* Transfer ownership to all read-lockers (if any). */
694 		error = futex_user_store(lock,
695 		    futex_queue_count(&fl->fl_readers));
696 		if (error != 0)
697 			return (error);
698 
699 		/* Wake up all threads. */
700 		futex_queue_wake_up_all(&fl->fl_readers);
701 		fl->fl_owner = LOCK_UNMANAGED;
702 	}
703 	return (0);
704 }
705 
706 static int
futex_lock_wrlock(struct futex_lock * fl,struct thread * td,cloudabi_lock_t * lock,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision,struct futex_queue * donated)707 futex_lock_wrlock(struct futex_lock *fl, struct thread *td,
708     cloudabi_lock_t *lock, cloudabi_clockid_t clock_id,
709     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision,
710     struct futex_queue *donated)
711 {
712 	struct futex_waiter fw;
713 	int error;
714 
715 	error = futex_lock_trywrlock(fl, lock, td->td_tid,
716 	    futex_queue_count(donated) > 0);
717 
718 	if (error == 0 || error == EBUSY) {
719 		/* Put donated threads in queue before suspending. */
720 		KASSERT(futex_queue_count(donated) == 0 ||
721 		    fl->fl_owner != LOCK_UNMANAGED,
722 		    ("Lock should be managed if we are going to donate"));
723 		futex_queue_requeue(donated, &fl->fl_writers, UINT_MAX);
724 	} else {
725 		/*
726 		 * This thread cannot deal with the donated threads.
727 		 * Wake up the next thread and let it try it by itself.
728 		 */
729 		futex_queue_wake_up_donate(donated, UINT_MAX);
730 	}
731 
732 	if (error == EBUSY) {
733 		/* Suspend execution if the lock was busy. */
734 		KASSERT(fl->fl_owner != LOCK_UNMANAGED,
735 		    ("Attempted to sleep on an unmanaged lock"));
736 		error = futex_queue_sleep(&fl->fl_writers, fl, &fw, td,
737 		    clock_id, timeout, precision);
738 		KASSERT((error == 0) == fw.fw_locked,
739 		    ("Should have locked write lock on success"));
740 		KASSERT(futex_queue_count(&fw.fw_donated) == 0,
741 		    ("Lock functions cannot receive threads"));
742 	}
743 	if (error != 0)
744 		futex_lock_unmanage(fl, lock);
745 	return (error);
746 }
747 
748 /*
749  * futex_queue operations.
750  */
751 
752 static cloudabi_tid_t
futex_queue_tid_best(const struct futex_queue * fq)753 futex_queue_tid_best(const struct futex_queue *fq)
754 {
755 
756 	return (STAILQ_FIRST(&fq->fq_list)->fw_tid);
757 }
758 
759 static unsigned int
futex_queue_count(const struct futex_queue * fq)760 futex_queue_count(const struct futex_queue *fq)
761 {
762 
763 	return (fq->fq_count);
764 }
765 
766 static void
futex_queue_init(struct futex_queue * fq)767 futex_queue_init(struct futex_queue *fq)
768 {
769 
770 	STAILQ_INIT(&fq->fq_list);
771 	fq->fq_count = 0;
772 }
773 
774 /* Converts a relative timestamp to an sbintime. */
775 static sbintime_t
futex_queue_convert_timestamp_relative(cloudabi_timestamp_t ts)776 futex_queue_convert_timestamp_relative(cloudabi_timestamp_t ts)
777 {
778 	cloudabi_timestamp_t s, ns;
779 
780 	s = ts / 1000000000;
781 	ns = ts % 1000000000;
782 	if (s > INT32_MAX)
783 		return (INT64_MAX);
784 	return ((s << 32) + (ns << 32) / 1000000000);
785 }
786 
787 /* Converts an absolute timestamp and precision to a pair of sbintime values. */
788 static int
futex_queue_convert_timestamp(struct thread * td,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision,sbintime_t * sbttimeout,sbintime_t * sbtprecision)789 futex_queue_convert_timestamp(struct thread *td, cloudabi_clockid_t clock_id,
790     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision,
791     sbintime_t *sbttimeout, sbintime_t *sbtprecision)
792 {
793 	cloudabi_timestamp_t now;
794 	int error;
795 
796 	/* Make the time relative. */
797 	error = cloudabi_clock_time_get(td, clock_id, &now);
798 	if (error != 0)
799 		return (error);
800 	timeout = timeout < now ? 0 : timeout - now;
801 
802 	*sbttimeout = futex_queue_convert_timestamp_relative(timeout);
803 	*sbtprecision = futex_queue_convert_timestamp_relative(precision);
804 	return (0);
805 }
806 
807 static int
futex_queue_sleep(struct futex_queue * fq,struct futex_lock * fl,struct futex_waiter * fw,struct thread * td,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision)808 futex_queue_sleep(struct futex_queue *fq, struct futex_lock *fl,
809     struct futex_waiter *fw, struct thread *td, cloudabi_clockid_t clock_id,
810     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
811 {
812 	sbintime_t sbttimeout, sbtprecision;
813 	int error;
814 
815 	/* Initialize futex_waiter object. */
816 	fw->fw_tid = td->td_tid;
817 	fw->fw_locked = false;
818 	futex_queue_init(&fw->fw_donated);
819 
820 	if (timeout != UINT64_MAX) {
821 		/* Convert timeout duration. */
822 		error = futex_queue_convert_timestamp(td, clock_id, timeout,
823 		    precision, &sbttimeout, &sbtprecision);
824 		if (error != 0)
825 			return (error);
826 	}
827 
828 	/* Place object in the queue. */
829 	fw->fw_queue = fq;
830 	STAILQ_INSERT_TAIL(&fq->fq_list, fw, fw_next);
831 	++fq->fq_count;
832 
833 	cv_init(&fw->fw_wait, "futex");
834 	++fl->fl_waitcount;
835 
836 	futex_lock_assert(fl);
837 	if (timeout == UINT64_MAX) {
838 		/* Wait without a timeout. */
839 		error = cv_wait_sig(&fw->fw_wait, &futex_global_lock);
840 	} else {
841 		/* Wait respecting the timeout. */
842 		error = cv_timedwait_sig_sbt(&fw->fw_wait, &futex_global_lock,
843 		    sbttimeout, sbtprecision, 0);
844 		futex_lock_assert(fl);
845 		if (error == EWOULDBLOCK &&
846 		    fw->fw_queue != NULL && fw->fw_queue != fq) {
847 			/*
848 			 * We got signalled on a condition variable, but
849 			 * observed a timeout while waiting to reacquire
850 			 * the lock. In other words, we didn't actually
851 			 * time out. Go back to sleep and wait for the
852 			 * lock to be reacquired.
853 			 */
854 			error = cv_wait_sig(&fw->fw_wait, &futex_global_lock);
855 		}
856 	}
857 	futex_lock_assert(fl);
858 
859 	--fl->fl_waitcount;
860 	cv_destroy(&fw->fw_wait);
861 
862 	fq = fw->fw_queue;
863 	if (fq == NULL) {
864 		/* Thread got dequeued, so we've slept successfully. */
865 		return (0);
866 	}
867 
868 	/* Thread is still enqueued. Remove it. */
869 	KASSERT(error != 0, ("Woken up thread is still enqueued"));
870 	STAILQ_REMOVE(&fq->fq_list, fw, futex_waiter, fw_next);
871 	--fq->fq_count;
872 	return (error == EWOULDBLOCK ? ETIMEDOUT : error);
873 }
874 
875 /* Moves up to nwaiters waiters from one queue to another. */
876 static void
futex_queue_requeue(struct futex_queue * fqfrom,struct futex_queue * fqto,unsigned int nwaiters)877 futex_queue_requeue(struct futex_queue *fqfrom, struct futex_queue *fqto,
878     unsigned int nwaiters)
879 {
880 	struct futex_waiter *fw;
881 
882 	/* Move waiters to the target queue. */
883 	while (nwaiters-- > 0 && !STAILQ_EMPTY(&fqfrom->fq_list)) {
884 		fw = STAILQ_FIRST(&fqfrom->fq_list);
885 		STAILQ_REMOVE_HEAD(&fqfrom->fq_list, fw_next);
886 		--fqfrom->fq_count;
887 
888 		fw->fw_queue = fqto;
889 		STAILQ_INSERT_TAIL(&fqto->fq_list, fw, fw_next);
890 		++fqto->fq_count;
891 	}
892 }
893 
894 /* Wakes up all waiters in a queue. */
895 static void
futex_queue_wake_up_all(struct futex_queue * fq)896 futex_queue_wake_up_all(struct futex_queue *fq)
897 {
898 	struct futex_waiter *fw;
899 
900 	STAILQ_FOREACH(fw, &fq->fq_list, fw_next) {
901 		fw->fw_locked = true;
902 		fw->fw_queue = NULL;
903 		cv_signal(&fw->fw_wait);
904 	}
905 
906 	STAILQ_INIT(&fq->fq_list);
907 	fq->fq_count = 0;
908 }
909 
910 /*
911  * Wakes up the best waiter (i.e., the waiter having the highest
912  * priority) in a queue.
913  */
914 static void
futex_queue_wake_up_best(struct futex_queue * fq)915 futex_queue_wake_up_best(struct futex_queue *fq)
916 {
917 	struct futex_waiter *fw;
918 
919 	fw = STAILQ_FIRST(&fq->fq_list);
920 	fw->fw_locked = true;
921 	fw->fw_queue = NULL;
922 	cv_signal(&fw->fw_wait);
923 
924 	STAILQ_REMOVE_HEAD(&fq->fq_list, fw_next);
925 	--fq->fq_count;
926 }
927 
928 static void
futex_queue_wake_up_donate(struct futex_queue * fq,unsigned int nwaiters)929 futex_queue_wake_up_donate(struct futex_queue *fq, unsigned int nwaiters)
930 {
931 	struct futex_waiter *fw;
932 
933 	fw = STAILQ_FIRST(&fq->fq_list);
934 	if (fw == NULL)
935 		return;
936 	fw->fw_locked = false;
937 	fw->fw_queue = NULL;
938 	cv_signal(&fw->fw_wait);
939 
940 	STAILQ_REMOVE_HEAD(&fq->fq_list, fw_next);
941 	--fq->fq_count;
942 	futex_queue_requeue(fq, &fw->fw_donated, nwaiters);
943 }
944 
945 /*
946  * futex_user operations. Used to adjust values in userspace.
947  */
948 
949 static int
futex_user_load(uint32_t * obj,uint32_t * val)950 futex_user_load(uint32_t *obj, uint32_t *val)
951 {
952 
953 	return (fueword32(obj, val) != 0 ? EFAULT : 0);
954 }
955 
956 static int
futex_user_store(uint32_t * obj,uint32_t val)957 futex_user_store(uint32_t *obj, uint32_t val)
958 {
959 
960 	return (suword32(obj, val) != 0 ? EFAULT : 0);
961 }
962 
963 static int
futex_user_cmpxchg(uint32_t * obj,uint32_t cmp,uint32_t * old,uint32_t new)964 futex_user_cmpxchg(uint32_t *obj, uint32_t cmp, uint32_t *old, uint32_t new)
965 {
966 
967 	return (casueword32(obj, cmp, old, new) != 0 ? EFAULT : 0);
968 }
969 
970 /*
971  * Blocking calls: acquiring locks, waiting on condition variables.
972  */
973 
974 int
cloudabi_futex_condvar_wait(struct thread * td,cloudabi_condvar_t * condvar,cloudabi_mflags_t condvar_scope,cloudabi_lock_t * lock,cloudabi_mflags_t lock_scope,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision)975 cloudabi_futex_condvar_wait(struct thread *td, cloudabi_condvar_t *condvar,
976     cloudabi_mflags_t condvar_scope, cloudabi_lock_t *lock,
977     cloudabi_mflags_t lock_scope, cloudabi_clockid_t clock_id,
978     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
979 {
980 	struct futex_condvar *fc;
981 	struct futex_lock *fl;
982 	struct futex_waiter fw;
983 	int error, error2;
984 
985 	/* Lookup condition variable object. */
986 	error = futex_condvar_lookup_or_create(td, condvar, condvar_scope, lock,
987 	    lock_scope, &fc);
988 	if (error != 0)
989 		return (error);
990 	fl = fc->fc_lock;
991 
992 	/*
993 	 * Set the condition variable to something other than
994 	 * CLOUDABI_CONDVAR_HAS_NO_WAITERS to make userspace threads
995 	 * call into the kernel to perform wakeups.
996 	 */
997 	error = futex_user_store(condvar, ~CLOUDABI_CONDVAR_HAS_NO_WAITERS);
998 	if (error != 0) {
999 		futex_condvar_release(fc);
1000 		return (error);
1001 	}
1002 
1003 	/* Drop the lock. */
1004 	error = futex_lock_unlock(fl, td, lock);
1005 	if (error != 0) {
1006 		futex_condvar_unmanage(fc, condvar);
1007 		futex_condvar_release(fc);
1008 		return (error);
1009 	}
1010 
1011 	/* Go to sleep. */
1012 	++fc->fc_waitcount;
1013 	error = futex_queue_sleep(&fc->fc_waiters, fc->fc_lock, &fw, td,
1014 	    clock_id, timeout, precision);
1015 	if (fw.fw_locked) {
1016 		/* Waited and got the lock assigned to us. */
1017 		KASSERT(futex_queue_count(&fw.fw_donated) == 0,
1018 		    ("Received threads while being locked"));
1019 	} else if (error == 0 || error == ETIMEDOUT) {
1020 		if (error != 0)
1021 			futex_condvar_unmanage(fc, condvar);
1022 		/*
1023 		 * Got woken up without having the lock assigned to us.
1024 		 * This can happen in two cases:
1025 		 *
1026 		 * 1. We observed a timeout on a condition variable.
1027 		 * 2. We got signalled on a condition variable while the
1028 		 *    associated lock is unlocked. We are the first
1029 		 *    thread that gets woken up. This thread is
1030 		 *    responsible for reacquiring the userspace lock.
1031 		 */
1032 		error2 = futex_lock_wrlock(fl, td, lock,
1033 		    CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0, &fw.fw_donated);
1034 		if (error2 != 0)
1035 			error = error2;
1036 	} else {
1037 		KASSERT(futex_queue_count(&fw.fw_donated) == 0,
1038 		    ("Received threads on error"));
1039 		futex_condvar_unmanage(fc, condvar);
1040 		futex_lock_unmanage(fl, lock);
1041 	}
1042 	--fc->fc_waitcount;
1043 	futex_condvar_release(fc);
1044 	return (error);
1045 }
1046 
1047 int
cloudabi_futex_lock_rdlock(struct thread * td,cloudabi_lock_t * lock,cloudabi_mflags_t scope,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision)1048 cloudabi_futex_lock_rdlock(struct thread *td, cloudabi_lock_t *lock,
1049     cloudabi_mflags_t scope, cloudabi_clockid_t clock_id,
1050     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
1051 {
1052 	struct futex_lock *fl;
1053 	int error;
1054 
1055 	/* Look up lock object. */
1056 	error = futex_lock_lookup(td, lock, scope, &fl);
1057 	if (error != 0)
1058 		return (error);
1059 
1060 	error = futex_lock_rdlock(fl, td, lock, clock_id, timeout,
1061 	    precision);
1062 	futex_lock_release(fl);
1063 	return (error);
1064 }
1065 
1066 int
cloudabi_futex_lock_wrlock(struct thread * td,cloudabi_lock_t * lock,cloudabi_mflags_t scope,cloudabi_clockid_t clock_id,cloudabi_timestamp_t timeout,cloudabi_timestamp_t precision)1067 cloudabi_futex_lock_wrlock(struct thread *td, cloudabi_lock_t *lock,
1068     cloudabi_mflags_t scope, cloudabi_clockid_t clock_id,
1069     cloudabi_timestamp_t timeout, cloudabi_timestamp_t precision)
1070 {
1071 	struct futex_lock *fl;
1072 	struct futex_queue fq;
1073 	int error;
1074 
1075 	/* Look up lock object. */
1076 	error = futex_lock_lookup(td, lock, scope, &fl);
1077 	if (error != 0)
1078 		return (error);
1079 
1080 	futex_queue_init(&fq);
1081 	error = futex_lock_wrlock(fl, td, lock, clock_id, timeout,
1082 	    precision, &fq);
1083 	futex_lock_release(fl);
1084 	return (error);
1085 }
1086 
1087 /*
1088  * Non-blocking calls: releasing locks, signalling condition variables.
1089  */
1090 
1091 int
cloudabi_sys_condvar_signal(struct thread * td,struct cloudabi_sys_condvar_signal_args * uap)1092 cloudabi_sys_condvar_signal(struct thread *td,
1093     struct cloudabi_sys_condvar_signal_args *uap)
1094 {
1095 	struct futex_condvar *fc;
1096 	struct futex_lock *fl;
1097 	cloudabi_nthreads_t nwaiters;
1098 	int error;
1099 
1100 	nwaiters = uap->nwaiters;
1101 	if (nwaiters == 0) {
1102 		/* No threads to wake up. */
1103 		return (0);
1104 	}
1105 
1106 	/* Look up futex object. */
1107 	error = futex_condvar_lookup(td, uap->condvar, uap->scope, &fc);
1108 	if (error != 0) {
1109 		/* Race condition: condition variable with no waiters. */
1110 		return (error == ENOENT ? 0 : error);
1111 	}
1112 	fl = fc->fc_lock;
1113 
1114 	if (fl->fl_owner == LOCK_UNMANAGED) {
1115 		/*
1116 		 * The lock is currently not managed by the kernel,
1117 		 * meaning we must attempt to acquire the userspace lock
1118 		 * first. We cannot requeue threads to an unmanaged lock,
1119 		 * as these threads will then never be scheduled.
1120 		 *
1121 		 * Unfortunately, the memory address of the lock is
1122 		 * unknown from this context, meaning that we cannot
1123 		 * acquire the lock on behalf of the first thread to be
1124 		 * scheduled. The lock may even not be mapped within the
1125 		 * address space of the current thread.
1126 		 *
1127 		 * To solve this, wake up a single waiter that will
1128 		 * attempt to acquire the lock. Donate all of the other
1129 		 * waiters that need to be woken up to this waiter, so
1130 		 * it can requeue them after acquiring the lock.
1131 		 */
1132 		futex_queue_wake_up_donate(&fc->fc_waiters, nwaiters - 1);
1133 	} else {
1134 		/*
1135 		 * Lock is already managed by the kernel. This makes it
1136 		 * easy, as we can requeue the threads from the
1137 		 * condition variable directly to the associated lock.
1138 		 */
1139 		futex_queue_requeue(&fc->fc_waiters, &fl->fl_writers, nwaiters);
1140 	}
1141 
1142 	/* Clear userspace condition variable if all waiters are gone. */
1143 	error = futex_condvar_unmanage(fc, uap->condvar);
1144 	futex_condvar_release(fc);
1145 	return (error);
1146 }
1147 
1148 int
cloudabi_sys_lock_unlock(struct thread * td,struct cloudabi_sys_lock_unlock_args * uap)1149 cloudabi_sys_lock_unlock(struct thread *td,
1150     struct cloudabi_sys_lock_unlock_args *uap)
1151 {
1152 	struct futex_lock *fl;
1153 	int error;
1154 
1155 	error = futex_lock_lookup(td, uap->lock, uap->scope, &fl);
1156 	if (error != 0)
1157 		return (error);
1158 	error = futex_lock_unlock(fl, td, uap->lock);
1159 	futex_lock_release(fl);
1160 	return (error);
1161 }
1162