LinuxThreads replacement
Mike Makonnen
mtm at identd.net
Wed Jul 9 16:52:25 PDT 2003
On Wed, Jul 09, 2003 at 06:49:25PM +0200, Kai Mosebach wrote:
>
> Would you more likely use libthr or libkse,
> as kse is not complete yet, isnt it ?
>
Either one should work just as well. There is currently a race
in the kernel code for libthr that can lead to deadlocks. I have
a fix for this and I am waiting for jeff to review it before I
commit it. In the mean time you can get the patch here:
http://people.freebsd.org/~mtm/patches/libthr.kern.diff
(also attached)
Cheers.
--
Mike Makonnen | GPG-KEY: http://www.identd.net/~mtm/mtm.asc
mtm at identd.net | D228 1A6F C64E 120A A1C9 A3AA DAE1 E2AF DBCC 68B9
mtm at FreeBSD.Org| FreeBSD - Unleash the Daemon!
-------------- next part --------------
Index: sys/kern/kern_umtx.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_umtx.c,v
retrieving revision 1.7
diff -u -r1.7 kern_umtx.c
--- sys/kern/kern_umtx.c 4 Jul 2003 23:28:42 -0000 1.7
+++ sys/kern/kern_umtx.c 5 Jul 2003 05:53:02 -0000
@@ -181,7 +181,7 @@
return (EFAULT);
if (owner == UMTX_CONTESTED)
- return (0);
+ goto out;
/* If this failed the lock has changed, restart. */
continue;
@@ -190,7 +190,6 @@
UMTX_LOCK();
uq = umtx_insert(td, umtx);
- UMTX_UNLOCK();
/*
* Set the contested bit so that a release in user space
@@ -203,7 +202,6 @@
/* The address was invalid. */
if (old == -1) {
- UMTX_LOCK();
umtx_remove(uq, td);
UMTX_UNLOCK();
return (EFAULT);
@@ -213,7 +211,6 @@
* We set the contested bit, sleep. Otherwise the lock changed
* and we need to retry.
*/
- UMTX_LOCK();
if (old == owner)
error = msleep(td, &umtx_lock,
td->td_priority | PCATCH, "umtx", 0);
@@ -230,8 +227,37 @@
if (error)
return (error);
}
-
- return (0);
+out:
+ /*
+ * We reach here only if we just acquired a contested umtx.
+ *
+ * If there are no other threads on this umtx's queue
+ * clear the contested bit. However, we cannot hold
+ * a lock across casuptr(). So after we unset it we
+ * have to recheck, and set it again if another thread has
+ * put itself on the queue in the mean time.
+ */
+ error = 0;
+ UMTX_LOCK();
+ uq = umtx_lookup(td, umtx);
+ UMTX_UNLOCK();
+ if (uq == NULL)
+ old = casuptr((intptr_t *)&umtx->u_owner,
+ ((intptr_t)td | UMTX_CONTESTED), (intptr_t)td);
+ if (uq == NULL && old == ((intptr_t)td | UMTX_CONTESTED)) {
+ UMTX_LOCK();
+ uq = umtx_lookup(td, umtx);
+ UMTX_UNLOCK();
+ if (uq != NULL) {
+ old = casuptr((intptr_t *)&umtx->u_owner,
+ (intptr_t)td, ((intptr_t)td | UMTX_CONTESTED));
+ if (old == -1)
+ error = EFAULT;
+ else if (old != (intptr_t)td)
+ error = EINVAL;
+ }
+ }
+ return (error);
}
int
@@ -257,25 +283,9 @@
if ((struct thread *)(owner & ~UMTX_CONTESTED) != td)
return (EPERM);
- /*
- * If we own it but it isn't contested then we can just release and
- * return.
- */
- if ((owner & UMTX_CONTESTED) == 0) {
- owner = casuptr((intptr_t *)&umtx->u_owner,
- (intptr_t)td, UMTX_UNOWNED);
- if (owner == -1)
- return (EFAULT);
- /*
- * If this failed someone modified the memory without going
- * through this api.
- */
- if (owner != (intptr_t)td)
- return (EINVAL);
-
- return (0);
- }
+ /* We should only ever be in here for contested locks */
+ KASSERT((owner & UMTX_CONTESTED) != 0, ("contested umtx is not."));
old = casuptr((intptr_t *)&umtx->u_owner, owner, UMTX_CONTESTED);
@@ -296,6 +306,7 @@
uq = umtx_lookup(td, umtx);
if (uq != NULL) {
blocked = TAILQ_FIRST(&uq->uq_tdq);
+ KASSERT(blocked != NULL, ("umtx_q with no waiting threads."));
wakeup(blocked);
}
More information about the freebsd-threads
mailing list