File tree 7 files changed +53
-11
lines changed 7 files changed +53
-11
lines changed Original file line number Diff line number Diff line change @@ -72,7 +72,7 @@ func clearSignalHandlers() {
72
72
}
73
73
74
74
//go:nosplit
75
- func sigblock () {
75
+ func sigblock (exiting bool ) {
76
76
}
77
77
78
78
// Called to initialize a new m (including the bootstrap m).
Original file line number Diff line number Diff line change @@ -301,6 +301,24 @@ func getHugePageSize() uintptr {
301
301
func osinit () {
302
302
ncpu = getproccount ()
303
303
physHugePageSize = getHugePageSize ()
304
+ if iscgo {
305
+ // #42494 glibc and musl reserve some signals for
306
+ // internal use and require they not be blocked by
307
+ // the rest of a normal C runtime. When the go runtime
308
+ // blocks...unblocks signals, temporarily, the blocked
309
+ // interval of time is generally very short. As such,
310
+ // these expectations of *libc code are mostly met by
311
+ // the combined go+cgo system of threads. However,
312
+ // when go causes a thread to exit, via a return from
313
+ // mstart(), the combined runtime can deadlock if
314
+ // these signals are blocked. Thus, don't block these
315
+ // signals when exiting threads.
316
+ // - glibc: SIGCANCEL (32), SIGSETXID (33)
317
+ // - musl: SIGTIMER (32), SIGCANCEL (33), SIGSYNCCALL (34)
318
+ sigdelset (& sigsetAllExiting , 32 )
319
+ sigdelset (& sigsetAllExiting , 33 )
320
+ sigdelset (& sigsetAllExiting , 34 )
321
+ }
304
322
osArchInit ()
305
323
}
306
324
Original file line number Diff line number Diff line change @@ -195,7 +195,7 @@ func msigrestore(sigmask sigset) {
195
195
func clearSignalHandlers () {
196
196
}
197
197
198
- func sigblock () {
198
+ func sigblock (exiting bool ) {
199
199
}
200
200
201
201
// Called to initialize a new m (including the bootstrap m).
Original file line number Diff line number Diff line change @@ -886,7 +886,7 @@ func clearSignalHandlers() {
886
886
}
887
887
888
888
//go:nosplit
889
- func sigblock () {
889
+ func sigblock (exiting bool ) {
890
890
}
891
891
892
892
// Called to initialize a new m (including the bootstrap m).
Original file line number Diff line number Diff line change @@ -1313,7 +1313,7 @@ func mexit(osStack bool) {
1313
1313
throw ("locked m0 woke up" )
1314
1314
}
1315
1315
1316
- sigblock ()
1316
+ sigblock (true )
1317
1317
unminit ()
1318
1318
1319
1319
// Free the gsignal stack.
@@ -1754,7 +1754,7 @@ func needm() {
1754
1754
// starting a new m to run Go code via newosproc.
1755
1755
var sigmask sigset
1756
1756
sigsave (& sigmask )
1757
- sigblock ()
1757
+ sigblock (false )
1758
1758
1759
1759
// Lock extra list, take head, unlock popped list.
1760
1760
// nilokay=false is safe here because of the invariant above,
@@ -1903,7 +1903,7 @@ func dropm() {
1903
1903
// Setg(nil) clears g, which is the signal handler's cue not to run Go handlers.
1904
1904
// It's important not to try to handle a signal between those two steps.
1905
1905
sigmask := mp .sigmask
1906
- sigblock ()
1906
+ sigblock (false )
1907
1907
unminit ()
1908
1908
1909
1909
mnext := lockextra (true )
@@ -3776,7 +3776,7 @@ func beforefork() {
3776
3776
// group. See issue #18600.
3777
3777
gp .m .locks ++
3778
3778
sigsave (& gp .m .sigmask )
3779
- sigblock ()
3779
+ sigblock (false )
3780
3780
3781
3781
// This function is called before fork in syscall package.
3782
3782
// Code between fork and exec must not allocate memory nor even try to grow stack.
Original file line number Diff line number Diff line change @@ -1042,15 +1042,26 @@ func msigrestore(sigmask sigset) {
1042
1042
sigprocmask (_SIG_SETMASK , & sigmask , nil )
1043
1043
}
1044
1044
1045
- // sigblock blocks all signals in the current thread's signal mask.
1045
+ // sigsetAllExiting is used by sigblock(true) when a thread is
1046
+ // exiting. sigset_all is defined in OS specific code, and per GOOS
1047
+ // behavior may override this default for sigsetAllExiting: see
1048
+ // osinit().
1049
+ var sigsetAllExiting = sigset_all
1050
+
1051
+ // sigblock blocks signals in the current thread's signal mask.
1046
1052
// This is used to block signals while setting up and tearing down g
1047
- // when a non-Go thread calls a Go function.
1048
- // The OS-specific code is expected to define sigset_all.
1053
+ // when a non-Go thread calls a Go function. When a thread is exiting
1054
+ // we use the sigsetAllExiting value, otherwise the OS specific
1055
+ // definition of sigset_all is used.
1049
1056
// This is nosplit and nowritebarrierrec because it is called by needm
1050
1057
// which may be called on a non-Go thread with no g available.
1051
1058
//go:nosplit
1052
1059
//go:nowritebarrierrec
1053
- func sigblock () {
1060
+ func sigblock (exiting bool ) {
1061
+ if exiting {
1062
+ sigprocmask (_SIG_SETMASK , & sigsetAllExiting , nil )
1063
+ return
1064
+ }
1054
1065
sigprocmask (_SIG_SETMASK , & sigset_all , nil )
1055
1066
}
1056
1067
Original file line number Diff line number Diff line change @@ -597,6 +597,14 @@ func compareStatus(filter, expect string) error {
597
597
return nil
598
598
}
599
599
600
+ // killAThread locks the goroutine to an OS thread and exits; this
601
+ // causes an OS thread to terminate.
602
+ func killAThread (c <- chan struct {}) {
603
+ runtime .LockOSThread ()
604
+ <- c
605
+ return
606
+ }
607
+
600
608
// TestSetuidEtc performs tests on all of the wrapped system calls
601
609
// that mirror to the 9 glibc syscalls with POSIX semantics. The test
602
610
// here is considered authoritative and should compile and run
@@ -647,6 +655,11 @@ func TestSetuidEtc(t *testing.T) {
647
655
}
648
656
649
657
for i , v := range vs {
658
+ // Generate some thread churn as we execute the tests.
659
+ c := make (chan struct {})
660
+ go killAThread (c )
661
+ close (c )
662
+
650
663
if err := v .fn (); err != nil {
651
664
t .Errorf ("[%d] %q failed: %v" , i , v .call , err )
652
665
continue
You can’t perform that action at this time.
0 commit comments