- 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
This commit is contained in:
Jeff Roberson 2008-03-19 07:13:24 +00:00
parent 86a06c6000
commit fbd762f197
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=177371

View File

@ -286,28 +286,34 @@ lf_setlock(lock, vp, clean)
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;
}
/*