2 * Copyright (c) 2004, David Xu <davidxu@freebsd.org>
3 * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/limits.h>
35 #include <sys/malloc.h>
36 #include <sys/mutex.h>
38 #include <sys/sysent.h>
39 #include <sys/systm.h>
40 #include <sys/sysproto.h>
41 #include <sys/eventhandler.h>
46 #include <vm/vm_param.h>
48 #include <vm/vm_map.h>
49 #include <vm/vm_object.h>
51 #define UMTX_PRIVATE 0
73 LIST_ENTRY(umtx_q) uq_next; /* Linked list for the hash. */
74 struct umtx_key uq_key; /* Umtx key. */
75 int uq_flags; /* Umtx flags. */
76 #define UQF_UMTXQ 0x0001
77 struct thread *uq_thread; /* The thread waits on. */
78 vm_offset_t uq_addr; /* Umtx's virtual address. */
81 LIST_HEAD(umtx_head, umtx_q);
83 struct mtx uc_lock; /* Lock for this chain. */
84 struct umtx_head uc_queue; /* List of sleep queues. */
90 #define GOLDEN_RATIO_PRIME 2654404609U
91 #define UMTX_CHAINS 128
92 #define UMTX_SHIFTS (__WORD_BIT - 7)
94 static struct umtxq_chain umtxq_chains[UMTX_CHAINS];
95 static MALLOC_DEFINE(M_UMTX, "umtx", "UMTX queue memory");
97 static void umtxq_init_chains(void *);
98 static int umtxq_hash(struct umtx_key *key);
99 static struct mtx *umtxq_mtx(int chain);
100 static void umtxq_lock(struct umtx_key *key);
101 static void umtxq_unlock(struct umtx_key *key);
102 static void umtxq_busy(struct umtx_key *key);
103 static void umtxq_unbusy(struct umtx_key *key);
104 static void umtxq_insert(struct umtx_q *uq);
105 static void umtxq_remove(struct umtx_q *uq);
106 static int umtxq_sleep(struct thread *td, struct umtx_key *key,
107 int prio, const char *wmesg, int timo);
108 static int umtxq_count(struct umtx_key *key);
109 static int umtxq_signal(struct umtx_key *key, int nr_wakeup);
110 static int umtx_key_match(const struct umtx_key *k1, const struct umtx_key *k2);
111 static int umtx_key_get(struct thread *td, struct umtx *umtx,
112 struct umtx_key *key);
113 static void umtx_key_release(struct umtx_key *key);
115 SYSINIT(umtx, SI_SUB_EVENTHANDLER+1, SI_ORDER_MIDDLE, umtxq_init_chains, NULL);
120 return (malloc(sizeof(struct umtx_q), M_UMTX, M_WAITOK|M_ZERO));
124 umtxq_free(struct umtx_q *uq)
130 umtxq_init_chains(void *arg __unused)
134 for (i = 0; i < UMTX_CHAINS; ++i) {
135 mtx_init(&umtxq_chains[i].uc_lock, "umtxq_lock", NULL,
136 MTX_DEF | MTX_DUPOK);
137 LIST_INIT(&umtxq_chains[i].uc_queue);
138 umtxq_chains[i].uc_flags = 0;
139 umtxq_chains[i].uc_waiters = 0;
144 umtxq_hash(struct umtx_key *key)
146 unsigned n = (uintptr_t)key->info.both.ptr + key->info.both.word;
147 return (((n * GOLDEN_RATIO_PRIME) >> UMTX_SHIFTS) % UMTX_CHAINS);
151 umtx_key_match(const struct umtx_key *k1, const struct umtx_key *k2)
153 return (k1->type == k2->type &&
154 k1->info.both.ptr == k2->info.both.ptr &&
155 k1->info.both.word == k2->info.both.word);
158 static inline struct mtx *
161 return (&umtxq_chains[chain].uc_lock);
165 umtxq_busy(struct umtx_key *key)
167 int chain = umtxq_hash(key);
169 mtx_assert(umtxq_mtx(chain), MA_OWNED);
170 while (umtxq_chains[chain].uc_flags & UCF_BUSY) {
171 umtxq_chains[chain].uc_waiters++;
172 msleep(&umtxq_chains[chain], umtxq_mtx(chain),
174 umtxq_chains[chain].uc_waiters--;
176 umtxq_chains[chain].uc_flags |= UCF_BUSY;
180 umtxq_unbusy(struct umtx_key *key)
182 int chain = umtxq_hash(key);
184 mtx_assert(umtxq_mtx(chain), MA_OWNED);
185 KASSERT(umtxq_chains[chain].uc_flags & UCF_BUSY, ("not busy"));
186 umtxq_chains[chain].uc_flags &= ~UCF_BUSY;
187 if (umtxq_chains[chain].uc_waiters)
188 wakeup_one(&umtxq_chains[chain]);
192 umtxq_lock(struct umtx_key *key)
194 int chain = umtxq_hash(key);
195 mtx_lock(umtxq_mtx(chain));
199 umtxq_unlock(struct umtx_key *key)
201 int chain = umtxq_hash(key);
202 mtx_unlock(umtxq_mtx(chain));
206 * Insert a thread onto the umtx queue.
209 umtxq_insert(struct umtx_q *uq)
211 struct umtx_head *head;
212 int chain = umtxq_hash(&uq->uq_key);
214 mtx_assert(umtxq_mtx(chain), MA_OWNED);
215 head = &umtxq_chains[chain].uc_queue;
216 LIST_INSERT_HEAD(head, uq, uq_next);
217 uq->uq_flags |= UQF_UMTXQ;
221 * Remove thread from the umtx queue.
224 umtxq_remove(struct umtx_q *uq)
226 mtx_assert(umtxq_mtx(umtxq_hash(&uq->uq_key)), MA_OWNED);
227 if (uq->uq_flags & UQF_UMTXQ) {
228 LIST_REMOVE(uq, uq_next);
229 /* turning off UQF_UMTXQ should be the last thing. */
230 uq->uq_flags &= ~UQF_UMTXQ;
235 umtxq_count(struct umtx_key *key)
238 struct umtx_head *head;
239 int chain, count = 0;
241 chain = umtxq_hash(key);
242 mtx_assert(umtxq_mtx(chain), MA_OWNED);
243 head = &umtxq_chains[chain].uc_queue;
244 LIST_FOREACH(uq, head, uq_next) {
245 if (umtx_key_match(&uq->uq_key, key)) {
254 umtxq_signal(struct umtx_key *key, int n_wake)
256 struct umtx_q *uq, *next;
257 struct umtx_head *head;
258 struct thread *blocked = NULL;
262 chain = umtxq_hash(key);
263 mtx_assert(umtxq_mtx(chain), MA_OWNED);
264 head = &umtxq_chains[chain].uc_queue;
265 for (uq = LIST_FIRST(head); uq; uq = next) {
266 next = LIST_NEXT(uq, uq_next);
267 if (umtx_key_match(&uq->uq_key, key)) {
268 blocked = uq->uq_thread;
279 umtxq_sleep(struct thread *td, struct umtx_key *key, int priority,
280 const char *wmesg, int timo)
282 int chain = umtxq_hash(key);
283 int error = msleep(td, umtxq_mtx(chain), priority, wmesg, timo);
284 if (error == EWOULDBLOCK)
290 umtx_key_get(struct thread *td, struct umtx *umtx, struct umtx_key *key)
293 vm_map_entry_t entry;
298 map = &td->td_proc->p_vmspace->vm_map;
299 if (vm_map_lookup(&map, (vm_offset_t)umtx, VM_PROT_WRITE,
300 &entry, &key->info.shared.object, &pindex, &prot,
301 &wired) != KERN_SUCCESS) {
305 if (VM_INHERIT_SHARE == entry->inheritance) {
306 key->type = UMTX_SHARED;
307 key->info.shared.offset = entry->offset + entry->start -
309 vm_object_reference(key->info.shared.object);
311 key->type = UMTX_PRIVATE;
312 key->info.private.umtx = umtx;
313 key->info.private.pid = td->td_proc->p_pid;
315 vm_map_lookup_done(map, entry);
320 umtx_key_release(struct umtx_key *key)
322 if (key->type == UMTX_SHARED)
323 vm_object_deallocate(key->info.shared.object);
327 umtxq_queue_me(struct thread *td, struct umtx *umtx, struct umtx_q *uq)
331 if ((error = umtx_key_get(td, umtx, &uq->uq_key)) != 0)
334 uq->uq_addr = (vm_offset_t)umtx;
336 umtxq_lock(&uq->uq_key);
337 /* hmm, for condition variable, we don't need busy flag. */
338 umtxq_busy(&uq->uq_key);
340 umtxq_unbusy(&uq->uq_key);
341 umtxq_unlock(&uq->uq_key);
346 _do_lock(struct thread *td, struct umtx *umtx, long id, int timo)
355 * Care must be exercised when dealing with umtx structure. It
356 * can fault on any access.
361 * Try the uncontested case. This should be done in userland.
363 owner = casuptr((intptr_t *)&umtx->u_owner,
366 /* The acquire succeeded. */
367 if (owner == UMTX_UNOWNED)
370 /* The address was invalid. */
374 /* If no one owns it but it is contested try to acquire it. */
375 if (owner == UMTX_CONTESTED) {
376 owner = casuptr((intptr_t *)&umtx->u_owner,
377 UMTX_CONTESTED, id | UMTX_CONTESTED);
379 if (owner == UMTX_CONTESTED)
382 /* The address was invalid. */
386 /* If this failed the lock has changed, restart. */
391 * If we caught a signal, we have retried and now
394 if (error || (error = umtxq_queue_me(td, umtx, uq)) != 0)
398 * Set the contested bit so that a release in user space
399 * knows to use the system call for unlock. If this fails
400 * either some one else has acquired the lock or it has been
403 old = casuptr((intptr_t *)&umtx->u_owner, owner,
404 owner | UMTX_CONTESTED);
406 /* The address was invalid. */
408 umtxq_lock(&uq->uq_key);
409 umtxq_busy(&uq->uq_key);
411 umtxq_unbusy(&uq->uq_key);
412 umtxq_unlock(&uq->uq_key);
413 umtx_key_release(&uq->uq_key);
418 * We set the contested bit, sleep. Otherwise the lock changed
419 * and we need to retry or we lost a race to the thread
420 * unlocking the umtx.
422 umtxq_lock(&uq->uq_key);
423 if (old == owner && (uq->uq_flags & UQF_UMTXQ)) {
424 error = umtxq_sleep(td, &uq->uq_key, PCATCH,
427 umtxq_busy(&uq->uq_key);
429 umtxq_unbusy(&uq->uq_key);
430 umtxq_unlock(&uq->uq_key);
431 umtx_key_release(&uq->uq_key);
438 do_lock(struct thread *td, struct umtx *umtx, long id,
439 struct timespec *timeout)
441 struct timespec ts, ts2, ts3;
445 if (timeout == NULL) {
446 error = _do_lock(td, umtx, id, 0);
449 timespecadd(&ts, timeout);
450 TIMESPEC_TO_TIMEVAL(&tv, timeout);
452 error = _do_lock(td, umtx, id, tvtohz(&tv));
453 if (error != ETIMEDOUT)
456 if (timespeccmp(&ts2, &ts, >=)) {
461 timespecsub(&ts3, &ts2);
462 TIMESPEC_TO_TIMEVAL(&tv, &ts3);
466 * This lets userland back off critical region if needed.
468 if (error == ERESTART)
474 do_unlock(struct thread *td, struct umtx *umtx, long id)
483 * Make sure we own this mtx.
485 * XXX Need a {fu,su}ptr this is not correct on arch where
486 * sizeof(intptr_t) != sizeof(long).
488 if ((owner = fuword(&umtx->u_owner)) == -1)
491 if ((owner & ~UMTX_CONTESTED) != id)
494 /* We should only ever be in here for contested locks */
495 if ((owner & UMTX_CONTESTED) == 0)
498 if ((error = umtx_key_get(td, umtx, &key)) != 0)
503 count = umtxq_count(&key);
507 * When unlocking the umtx, it must be marked as unowned if
508 * there is zero or one thread only waiting for it.
509 * Otherwise, it must be marked as contested.
511 old = casuptr((intptr_t *)&umtx->u_owner, owner,
512 count <= 1 ? UMTX_UNOWNED : UMTX_CONTESTED);
514 umtxq_signal(&key, 0);
517 umtx_key_release(&key);
526 do_wait(struct thread *td, struct umtx *umtx, long id, struct timespec *timeout)
529 struct timespec ts, ts2, ts3;
535 if ((error = umtxq_queue_me(td, umtx, uq)) != 0)
537 tmp = fuword(&umtx->u_owner);
539 umtxq_lock(&uq->uq_key);
541 umtxq_unlock(&uq->uq_key);
542 } else if (timeout == NULL) {
543 umtxq_lock(&uq->uq_key);
544 if (uq->uq_flags & UQF_UMTXQ)
545 error = umtxq_sleep(td, &uq->uq_key,
547 if (!(uq->uq_flags & UQF_UMTXQ))
551 umtxq_unlock(&uq->uq_key);
554 timespecadd(&ts, timeout);
555 TIMESPEC_TO_TIMEVAL(&tv, timeout);
557 umtxq_lock(&uq->uq_key);
558 if (uq->uq_flags & UQF_UMTXQ) {
559 error = umtxq_sleep(td, &uq->uq_key, PCATCH,
560 "ucond", tvtohz(&tv));
562 if (!(uq->uq_flags & UQF_UMTXQ)) {
563 umtxq_unlock(&uq->uq_key);
566 umtxq_unlock(&uq->uq_key);
567 if (error != ETIMEDOUT)
570 if (timespeccmp(&ts2, &ts, >=)) {
575 timespecsub(&ts3, &ts2);
576 TIMESPEC_TO_TIMEVAL(&tv, &ts3);
578 umtxq_lock(&uq->uq_key);
580 umtxq_unlock(&uq->uq_key);
583 umtx_key_release(&uq->uq_key);
584 if (error == ERESTART)
590 kern_umtx_wake(struct thread *td, void *uaddr, int n_wake)
595 if ((ret = umtx_key_get(td, uaddr, &key)) != 0)
598 ret = umtxq_signal(&key, n_wake);
600 umtx_key_release(&key);
605 _umtx_lock(struct thread *td, struct _umtx_lock_args *uap)
606 /* struct umtx *umtx */
608 return _do_lock(td, uap->umtx, td->td_tid, 0);
612 _umtx_unlock(struct thread *td, struct _umtx_unlock_args *uap)
613 /* struct umtx *umtx */
615 return do_unlock(td, uap->umtx, td->td_tid);
619 _umtx_op(struct thread *td, struct _umtx_op_args *uap)
621 struct timespec timeout;
627 /* Allow a null timespec (wait forever). */
628 if (uap->uaddr2 == NULL)
631 error = copyin(uap->uaddr2, &timeout, sizeof(timeout));
634 if (timeout.tv_nsec >= 1000000000 ||
635 timeout.tv_nsec < 0) {
641 error = do_lock(td, uap->umtx, uap->id, ts);
644 error = do_unlock(td, uap->umtx, uap->id);
647 /* Allow a null timespec (wait forever). */
648 if (uap->uaddr2 == NULL)
651 error = copyin(uap->uaddr2, &timeout, sizeof(timeout));
654 if (timeout.tv_nsec >= 1000000000 ||
655 timeout.tv_nsec < 0) {
661 error = do_wait(td, uap->umtx, uap->id, ts);
664 error = kern_umtx_wake(td, uap->umtx, uap->id);