runtime: don't clear lockedExt on locked M when G exits

When a locked M has its G exit without calling UnlockOSThread, then
lockedExt on it was getting cleared. Unfortunately, this meant that
during P handoff, if a new M was started, it might get forked (on
most OSs besides Windows) from the locked M, which could have kernel
state attached to it.

To solve this, just don't clear lockedExt. At the point where the
locked M has its G exit, it will also exit in accordance with the
LockOSThread API. So, we can safely assume that it's lockedExt state
will no longer be used. For the case of the main thread where it just
gets wedged instead of exiting, it's probably better for it to keep
the locked marker since it more accurately represents its state.

Fixed #28979.

Change-Id: I7d3d71dd65bcb873e9758086d2cbcb9a06429b0f
Reviewed-on: https://go-review.googlesource.com/c/153078
Run-TryBot: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
Michael Anthony Knyszek 2018-12-07 00:07:43 +00:00 committed by Michael Knyszek
parent 6fcab648af
commit d0f8a7517a
6 changed files with 175 additions and 30 deletions

View file

@ -885,6 +885,12 @@ func TestLockOSThreadNesting(t *testing.T) {
func TestLockOSThreadExit(t *testing.T) {
testLockOSThreadExit(t, "testprog")
want := "OK\n"
output := runTestProg(t, "testprog", "LockOSThreadAvoidsStatePropagation", "GOMAXPROCS=1")
if output != want {
t.Errorf("want %s, got %s\n", want, output)
}
}
func testLockOSThreadExit(t *testing.T, prog string) {