diff options
author | jeff <jeff@FreeBSD.org> | 2008-03-19 07:13:24 +0000 |
---|---|---|
committer | jeff <jeff@FreeBSD.org> | 2008-03-19 07:13:24 +0000 |
commit | 4cd4553bb53da6eff2e16385db01ba95bd7d7266 (patch) | |
tree | c6e3b7daf968664cd89e965811151abeab9c38fa | |
parent | e846a1612b584a4d896189eb9ece9b3fa61d3878 (diff) | |
download | FreeBSD-src-4cd4553bb53da6eff2e16385db01ba95bd7d7266.zip FreeBSD-src-4cd4553bb53da6eff2e16385db01ba95bd7d7266.tar.gz |
- Fix the last of the threading bugs that were introduced as far back as
1.38 in 2001. Break out of the FOREACH_THREAD_IN_PROC loop when we've
discovered a new proc in the chain.
- Increment i and check for maxlockdepth once per matching process not
once per thread. This didn't properly terminate the loop before.
- Fix a bug which has existed potentially since rev 1.1. waitblock->lf_next
can be NULL when a thread has been woken-up but not yet scheduled. Check
for this condition rather than blindly dereferencing.
Found by: libMicro
-rw-r--r-- | sys/kern/kern_lockf.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/sys/kern/kern_lockf.c b/sys/kern/kern_lockf.c index 6cce5aa..95ac99d 100644 --- a/sys/kern/kern_lockf.c +++ b/sys/kern/kern_lockf.c @@ -286,28 +286,34 @@ restart: PROC_LOCK(wproc); FOREACH_THREAD_IN_PROC(wproc, td) { thread_lock(td); - while (td->td_wchan && - (td->td_wmesg == lockstr) && - (i++ < maxlockdepth)) { + for (;;) { + if (!TD_ON_SLEEPQ(td) || + td->td_wmesg != lockstr) + break; waitblock = (struct lockf *)td->td_wchan; /* Get the owner of the blocking lock */ + if (waitblock->lf_next == NULL) + break; waitblock = waitblock->lf_next; if ((waitblock->lf_flags & F_POSIX) == 0) break; - nproc = (struct proc *)waitblock->lf_id; - if (nproc == (struct proc *)lock->lf_id) { + if (waitblock->lf_id == lock->lf_id) { thread_unlock(td); PROC_UNLOCK(wproc); lock->lf_next = *clean; *clean = lock; return (EDEADLK); } + nproc = (struct proc *)waitblock->lf_id; + break; } thread_unlock(td); + if (nproc) + break; } PROC_UNLOCK(wproc); wproc = nproc; - if (wproc) + if (++i < maxlockdepth && wproc) goto restart; } /* |