Skip to content

Commit

Permalink
runtime: free Windows event handles after last lock is dropped
Browse files Browse the repository at this point in the history
Calls to lock may need to use global members of mOS that also need to be
cleaned up before the thread exits. Before this commit, these resources
would leak. Moving them to be cleaned up in unminit, however, would race
with gstack on unix. So this creates a new helper, mdestroy, to release
resources that must be destroyed only after locks are no longer
required. We also move highResTimer lifetime to the same semantics,
since it doesn't help to constantly acquire and release the timer object
during dropm.

Updates #43720.

Change-Id: Ib3f598f3fda1b2bbcb608099616fa4f85bc1c289
Reviewed-on: https://go-review.googlesource.com/c/go/+/284137
Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Alex Brainman <alex.brainman@gmail.com>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
  • Loading branch information
zx2c4 committed Jan 18, 2021
1 parent 5a8fbb0 commit dbab079
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 12 deletions.
5 changes: 5 additions & 0 deletions src/runtime/os3_solaris.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

func sigtramp()

//go:nosplit
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_aix.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

// tstart is a function descriptor to _tstart defined in assembly.
var tstart funcDescriptor

Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ func unminit() {
}
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

//go:nosplit
func osyield() {
usleep(1)
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_dragonfly.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

func sigtramp()

type sigactiont struct {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

func sigtramp()

type sigactiont struct {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ func minit() {
func unminit() {
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

func osinit() {
ncpu = 1
getg().m.procid = 2
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

//#ifdef GOARCH_386
//#define sa_handler k_sa_handler
//#endif
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_netbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

func sigtramp()

type sigactiont struct {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ func unminit() {
unminitSignals()
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

func sigtramp()

type sigactiont struct {
Expand Down
5 changes: 5 additions & 0 deletions src/runtime/os_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ func minit() {
func unminit() {
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
func mdestroy(mp *m) {
}

var sysstat = []byte("/dev/sysstat\x00")

func getproccount() int32 {
Expand Down
38 changes: 26 additions & 12 deletions src/runtime/os_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -898,20 +898,18 @@ func minit() {
throw("runtime.minit: duplicatehandle failed")
}

mp := getg().m
lock(&mp.threadLock)
mp.thread = thandle

// Configure usleep timer, if possible.
var timer uintptr
if haveHighResTimer {
timer = createHighResTimer()
if timer == 0 {
if mp.highResTimer == 0 && haveHighResTimer {
mp.highResTimer = createHighResTimer()
if mp.highResTimer == 0 {
print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n")
throw("CreateWaitableTimerEx when creating timer failed")
}
}

mp := getg().m
lock(&mp.threadLock)
mp.thread = thandle
mp.highResTimer = timer
unlock(&mp.threadLock)

// Query the true stack base from the OS. Currently we're
Expand Down Expand Up @@ -947,13 +945,29 @@ func minit() {
func unminit() {
mp := getg().m
lock(&mp.threadLock)
stdcall1(_CloseHandle, mp.thread)
mp.thread = 0
if mp.thread != 0 {
stdcall1(_CloseHandle, mp.thread)
mp.thread = 0
}
unlock(&mp.threadLock)
}

// Called from exitm, but not from drop, to undo the effect of thread-owned
// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
//go:nosplit
func mdestroy(mp *m) {
if mp.highResTimer != 0 {
stdcall1(_CloseHandle, mp.highResTimer)
mp.highResTimer = 0
}
unlock(&mp.threadLock)
if mp.waitsema != 0 {
stdcall1(_CloseHandle, mp.waitsema)
mp.waitsema = 0
}
if mp.resumesema != 0 {
stdcall1(_CloseHandle, mp.resumesema)
mp.resumesema = 0
}
}

// Calling stdcall on os stack.
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/proc.go
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,10 @@ found:
}
}

// Destroy all allocated resources. After this is called, we may no
// longer take any locks.
mdestroy(m)

if osStack {
// Return from mstart and let the system thread
// library free the g0 stack and terminate the thread.
Expand Down

0 comments on commit dbab079

Please sign in to comment.