Commit 9745e88b authored by Austin Clements's avatar Austin Clements

runtime: use rwmutex for execLock

Currently the execLock is a mutex, which has the unfortunate
side-effect of serializing all thread creation. This replaces it with
an rwmutex so threads can be created in parallel, but exec still
blocks thread creation.

Fixes #20738.

Change-Id: Ia8f30a92053c3d28af460b0da71176abe5fd074b
Reviewed-on: https://go-review.googlesource.com/47072
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 80832974
...@@ -1617,9 +1617,7 @@ func unlockextra(mp *m) { ...@@ -1617,9 +1617,7 @@ func unlockextra(mp *m) {
// execLock serializes exec and clone to avoid bugs or unspecified behaviour // execLock serializes exec and clone to avoid bugs or unspecified behaviour
// around exec'ing while creating/destroying threads. See issue #19546. // around exec'ing while creating/destroying threads. See issue #19546.
// var execLock rwmutex
// TODO: look into using a rwmutex, to avoid serializing thread creation.
var execLock mutex
// Create a new m. It will start off with a call to fn, or else the scheduler. // Create a new m. It will start off with a call to fn, or else the scheduler.
// fn needs to be static and not a heap allocated closure. // fn needs to be static and not a heap allocated closure.
...@@ -1640,14 +1638,14 @@ func newm(fn func(), _p_ *p) { ...@@ -1640,14 +1638,14 @@ func newm(fn func(), _p_ *p) {
if msanenabled { if msanenabled {
msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts)) msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
} }
lock(&execLock) execLock.rlock() // Prevent process clone.
asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts)) asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
unlock(&execLock) execLock.runlock()
return return
} }
lock(&execLock) execLock.rlock() // Prevent process clone.
newosproc(mp, unsafe.Pointer(mp.g0.stack.hi)) newosproc(mp, unsafe.Pointer(mp.g0.stack.hi))
unlock(&execLock) execLock.runlock()
} }
// Stops execution of the current m until new work is available. // Stops execution of the current m until new work is available.
...@@ -2870,13 +2868,14 @@ func syscall_runtime_AfterForkInChild() { ...@@ -2870,13 +2868,14 @@ func syscall_runtime_AfterForkInChild() {
// Called from syscall package before Exec. // Called from syscall package before Exec.
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec //go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
func syscall_runtime_BeforeExec() { func syscall_runtime_BeforeExec() {
lock(&execLock) // Prevent thread creation during exec.
execLock.lock()
} }
// Called from syscall package after Exec. // Called from syscall package after Exec.
//go:linkname syscall_runtime_AfterExec syscall.runtime_AfterExec //go:linkname syscall_runtime_AfterExec syscall.runtime_AfterExec
func syscall_runtime_AfterExec() { func syscall_runtime_AfterExec() {
unlock(&execLock) execLock.unlock()
} }
// Allocate a new g, with a stack big enough for stacksize bytes. // Allocate a new g, with a stack big enough for stacksize bytes.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment