aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/netpoll.go47
-rw-r--r--src/runtime/proc.go21
-rw-r--r--src/runtime/signal_unix.go22
3 files changed, 76 insertions, 14 deletions
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 34ea82a7fa..77eb3aa4c6 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -79,16 +79,17 @@ type pollDesc struct {
lock mutex // protects the following fields
fd uintptr
closing bool
- everr bool // marks event scanning error happened
- user uint32 // user settable cookie
- rseq uintptr // protects from stale read timers
- rg uintptr // pdReady, pdWait, G waiting for read or nil
- rt timer // read deadline timer (set if rt.f != nil)
- rd int64 // read deadline
- wseq uintptr // protects from stale write timers
- wg uintptr // pdReady, pdWait, G waiting for write or nil
- wt timer // write deadline timer
- wd int64 // write deadline
+ everr bool // marks event scanning error happened
+ user uint32 // user settable cookie
+ rseq uintptr // protects from stale read timers
+ rg uintptr // pdReady, pdWait, G waiting for read or nil
+ rt timer // read deadline timer (set if rt.f != nil)
+ rd int64 // read deadline
+ wseq uintptr // protects from stale write timers
+ wg uintptr // pdReady, pdWait, G waiting for write or nil
+ wt timer // write deadline timer
+ wd int64 // write deadline
+ self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
}
type pollCache struct {
@@ -157,6 +158,7 @@ func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
pd.wseq++
pd.wg = 0
pd.wd = 0
+ pd.self = pd
unlock(&pd.lock)
var errno int32
@@ -271,14 +273,14 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
// Copy current seq into the timer arg.
// Timer func will check the seq against current descriptor seq,
// if they differ the descriptor was reused or timers were reset.
- pd.rt.arg = pd
+ pd.rt.arg = pd.makeArg()
pd.rt.seq = pd.rseq
resettimer(&pd.rt, pd.rd)
}
} else if pd.rd != rd0 || combo != combo0 {
pd.rseq++ // invalidate current timers
if pd.rd > 0 {
- modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq)
+ modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq)
} else {
deltimer(&pd.rt)
pd.rt.f = nil
@@ -287,14 +289,14 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
if pd.wt.f == nil {
if pd.wd > 0 && !combo {
pd.wt.f = netpollWriteDeadline
- pd.wt.arg = pd
+ pd.wt.arg = pd.makeArg()
pd.wt.seq = pd.wseq
resettimer(&pd.wt, pd.wd)
}
} else if pd.wd != wd0 || combo != combo0 {
pd.wseq++ // invalidate current timers
if pd.wd > 0 && !combo {
- modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq)
+ modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq)
} else {
deltimer(&pd.wt)
pd.wt.f = nil
@@ -547,3 +549,20 @@ func (c *pollCache) alloc() *pollDesc {
unlock(&c.lock)
return pd
}
+
+// makeArg converts pd to an interface{}.
+// makeArg does not do any allocation. Normally, such
+// a conversion requires an allocation because pointers to
+// go:notinheap types (which pollDesc is) must be stored
+// in interfaces indirectly. See issue 42076.
+func (pd *pollDesc) makeArg() (i interface{}) {
+ x := (*eface)(unsafe.Pointer(&i))
+ x._type = pdType
+ x.data = unsafe.Pointer(&pd.self)
+ return
+}
+
+var (
+ pdEface interface{} = (*pollDesc)(nil)
+ pdType *_type = efaceOf(&pdEface)._type
+)
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 035822216d..2f1272d310 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1281,6 +1281,14 @@ found:
checkdead()
unlock(&sched.lock)
+ if GOOS == "darwin" {
+ // Make sure pendingPreemptSignals is correct when an M exits.
+ // For #41702.
+ if atomic.Load(&m.signalPending) != 0 {
+ atomic.Xadd(&pendingPreemptSignals, -1)
+ }
+ }
+
if osStack {
// Return from mstart and let the system thread
// library free the g0 stack and terminate the thread.
@@ -3475,11 +3483,24 @@ func syscall_runtime_AfterForkInChild() {
inForkedChild = false
}
+// pendingPreemptSignals is the number of preemption signals
+// that have been sent but not received. This is only used on Darwin.
+// For #41702.
+var pendingPreemptSignals uint32
+
// Called from syscall package before Exec.
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
func syscall_runtime_BeforeExec() {
// Prevent thread creation during exec.
execLock.lock()
+
+ // On Darwin, wait for all pending preemption signals to
+ // be received. See issue #41702.
+ if GOOS == "darwin" {
+ for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
+ osyield()
+ }
+ }
}
// Called from syscall package after Exec.
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index dd6d79f8ec..80fd2d6604 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -336,6 +336,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt) {
// Acknowledge the preemption.
atomic.Xadd(&gp.m.preemptGen, 1)
atomic.Store(&gp.m.signalPending, 0)
+
+ if GOOS == "darwin" {
+ atomic.Xadd(&pendingPreemptSignals, -1)
+ }
}
const preemptMSupported = true
@@ -357,7 +361,18 @@ func preemptM(mp *m) {
// required).
return
}
+
+ // On Darwin, don't try to preempt threads during exec.
+ // Issue #41702.
+ if GOOS == "darwin" {
+ execLock.rlock()
+ }
+
if atomic.Cas(&mp.signalPending, 0, 1) {
+ if GOOS == "darwin" {
+ atomic.Xadd(&pendingPreemptSignals, 1)
+ }
+
// If multiple threads are preempting the same M, it may send many
// signals to the same M such that it hardly make progress, causing
// live-lock problem. Apparently this could happen on darwin. See
@@ -365,6 +380,10 @@ func preemptM(mp *m) {
// Only send a signal if there isn't already one pending.
signalM(mp, sigPreempt)
}
+
+ if GOOS == "darwin" {
+ execLock.runlock()
+ }
}
// sigFetchG fetches the value of G safely when running in a signal handler.
@@ -425,6 +444,9 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
// no non-Go signal handler for sigPreempt.
// The default behavior for sigPreempt is to ignore
// the signal, so badsignal will be a no-op anyway.
+ if GOOS == "darwin" {
+ atomic.Xadd(&pendingPreemptSignals, -1)
+ }
return
}
c.fixsigcode(sig)