Swapped out procs not brought in immediately after child exits

From: Sam Lawrance <boris_at_brooknet.com.au>
Date: Sun, 6 Mar 2005 12:21:46 +1100 (EST)
>Submitter-Id:  current-users
>Originator:    Sam Lawrance
>Confidential:  no 
>Synopsis:      Swapped out procs not brought in immediately after child exits
>Severity:      non-critical
>Priority:      medium
>Category:      kern
>Class:         sw-bug
>Release:       FreeBSD 5.4-PRERELEASE i386
>Environment:
System: FreeBSD dirk.no.domain 5.4-PRERELEASE FreeBSD 5.4-PRERELEASE #10: Sun Ma
r 6 10:45:13 EST 2005 root_at_dirk.no.domain:/usr/testbuild/src5/sys/i386/compile/G
ENERIC i386


>Description:

I run -stable on my lonely box, but AFAICS this affects current.

This problem is similar in flavour to one that I reported a while ago,
since fixed.

Here's an example. Below we have a login, shell and su which have
swapped out, and a shell which is active:

root 4291  0.0  0.0  1664     0  v3  IWs  -         0:00.00 login [pam] (login)
sam  4298  0.0  0.0  2260     0  v3  IW   -         0:00.00 -bash (bash)
root 4299  0.0  0.0  1644     0  v3  IW   -         0:00.00 su
root 4300  0.0  0.4  2952  1132  v3  S+    3:23PM   0:00.66 su (bash)

When 4300 exits, it will sit in the zombie state for a long
time, waiting for 4299 to be swapped in.  Same for 4299 and 4298.

The kernel call stack for 4300 would be something like

	exit1
	  kern_exit
	    wakeup (parent process as wait channel)
	      sleepq_broadcast
	        sleepq_resume_thread (on parent process)
	          setrunnable

In setrunnable, curthread->td_pflags is flagged with TDP_WAKEPROC0 to
indicate the vm scheduler should be awoken to do its thing.

David Xu's original change was to check for TDP_WAKEPROC0 in
critical_exit() and wakeup(&proc0) from there. Things were arranged
this way in order to prevent an LOR between sched_lock and sleepqueue
locks.

That scheme doesn't take into account that exit1() does a
critical_enter() that has no corresponding critical_exit() in that
thread (because the exiting thread grabs sched_lock which is held across
cpu_throw).

So the wakeup is not done, and we just have to wait for the vm's tsleep
on proc0 to time out. The same thing might occur across other exit
points, but I don't know what they are.

>How-To-Repeat:

Run a shell somewhere (first). Su or run another shell or similar (second).
Wait until the first shell has swapped out (might require running some other
memory hogs). Exit the second shell. Notice that the second shell takes a
long time to exit.

>Fix:

A possible solution might be to wakeup(&proc0) after waking the parent
and before grabbing sched_lock:

Index: kern_exit.c
===================================================================
RCS file: /home/ncvs/FreeBSD/src/sys/kern/kern_exit.c,v
retrieving revision 1.256
diff -u -r1.256 kern_exit.c
--- kern_exit.c	29 Jan 2005 14:03:41 -0000	1.256
+++ kern_exit.c	6 Mar 2005 01:17:35 -0000
_at__at_ -503,6 +503,7 _at__at_
 	mtx_unlock_spin(&sched_lock);
 	wakeup(p->p_pptr);
 	PROC_UNLOCK(p->p_pptr);
+	wakeup(&proc0);
 	mtx_lock_spin(&sched_lock);
 	critical_exit();
 
Received on Sun Mar 06 2005 - 00:20:41 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:38:29 UTC