libgo: update to 1.15.6 release
authorIan Lance Taylor <iant@golang.org>
Tue, 8 Dec 2020 18:57:05 +0000 (10:57 -0800)
committerIan Lance Taylor <iant@golang.org>
Tue, 8 Dec 2020 22:01:04 +0000 (14:01 -0800)
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/276153

gcc/go/gofrontend/MERGE
libgo/MERGE
libgo/VERSION
libgo/go/cmd/go/internal/work/exec.go
libgo/go/internal/poll/copy_file_range_linux.go
libgo/go/runtime/crash_cgo_test.go
libgo/go/runtime/os_js.go
libgo/go/runtime/proc.go
libgo/go/runtime/signal_unix.go
libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go [new file with mode: 0644]
libgo/runtime/proc.c

index 619f1c001f08cf9448e63ab7b154b5efbe55f096..dc2682d95d1d655acd97984508bb544f4b1eae73 100644 (file)
@@ -1,4 +1,4 @@
-f4069d94a25893afc9f2fcf641359366f3ede017
+0d0b423739b2fee9788cb6cb8af9ced29375e545
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index b753907837de58d06c0e6ebf587cda0cc2c4e2b6..e95c59a132d769f473bef8851009b5a1ed07641f 100644 (file)
@@ -1,4 +1,4 @@
-c53315d6cf1b4bfea6ff356b4a1524778c683bb9
+9b955d2d3fcff6a5bc8bce7bafdc4c634a28e95b
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index 701454707cddcddde010fc9d213ee80374d855b9..7b6d7469626d9e6696f5a51394f5ca288ab98c8f 100644 (file)
@@ -1 +1 @@
-go1.15.5
+go1.15.6
index 4f689438d1d428b59156b5b50134f132d5621897..3898b2047c3a746e6cd611712a02fd758bca3c77 100644 (file)
@@ -2778,6 +2778,21 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
                                idx = bytes.Index(src, []byte(cgoLdflag))
                        }
                }
+
+               // We expect to find the contents of cgoLDFLAGS in flags.
+               if len(cgoLDFLAGS) > 0 {
+               outer:
+                       for i := range flags {
+                               for j, f := range cgoLDFLAGS {
+                                       if f != flags[i+j] {
+                                               continue outer
+                                       }
+                               }
+                               flags = append(flags[:i], flags[i+len(cgoLDFLAGS):]...)
+                               break
+                       }
+               }
+
                if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil {
                        return nil, nil, err
                }
index 09de299ff71781f09e173acc72dc60705e2f1b37..fc34aef4cba0e4320bba3e51f1be3677ab590870 100644 (file)
@@ -10,15 +10,61 @@ import (
        "syscall"
 )
 
-var copyFileRangeSupported int32 = 1 // accessed atomically
+var copyFileRangeSupported int32 = -1 // accessed atomically
 
 const maxCopyFileRangeRound = 1 << 30
 
+func kernelVersion() (major int, minor int) {
+       var uname syscall.Utsname
+       if err := syscall.Uname(&uname); err != nil {
+               return
+       }
+
+       rl := uname.Release
+       var values [2]int
+       vi := 0
+       value := 0
+       for _, c := range rl {
+               if '0' <= c && c <= '9' {
+                       value = (value * 10) + int(c-'0')
+               } else {
+                       // Note that we're assuming N.N.N here.  If we see anything else we are likely to
+                       // mis-parse it.
+                       values[vi] = value
+                       vi++
+                       if vi >= len(values) {
+                               break
+                       }
+                       value = 0
+               }
+       }
+       switch vi {
+       case 0:
+               return 0, 0
+       case 1:
+               return values[0], 0
+       case 2:
+               return values[0], values[1]
+       }
+       return
+}
+
 // CopyFileRange copies at most remain bytes of data from src to dst, using
 // the copy_file_range system call. dst and src must refer to regular files.
 func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) {
-       if atomic.LoadInt32(&copyFileRangeSupported) == 0 {
+       if supported := atomic.LoadInt32(&copyFileRangeSupported); supported == 0 {
                return 0, false, nil
+       } else if supported == -1 {
+               major, minor := kernelVersion()
+               if major > 5 || (major == 5 && minor >= 3) {
+                       atomic.StoreInt32(&copyFileRangeSupported, 1)
+               } else {
+                       // copy_file_range(2) is broken in various ways on kernels older than 5.3,
+                       // see issue #42400 and
+                       // https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS
+                       atomic.StoreInt32(&copyFileRangeSupported, 0)
+                       return 0, false, nil
+               }
        }
        for remain > 0 {
                max := remain
@@ -41,7 +87,7 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err
                        // use copy_file_range(2) again.
                        atomic.StoreInt32(&copyFileRangeSupported, 0)
                        return 0, false, nil
-               case syscall.EXDEV, syscall.EINVAL, syscall.EOPNOTSUPP, syscall.EPERM:
+               case syscall.EXDEV, syscall.EINVAL, syscall.EIO, syscall.EOPNOTSUPP, syscall.EPERM:
                        // Prior to Linux 5.3, it was not possible to
                        // copy_file_range across file systems. Similarly to
                        // the ENOSYS case above, if we see EXDEV, we have
@@ -53,6 +99,9 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err
                        // file. This is another case where no data has been
                        // transfered, so we consider it unhandled.
                        //
+                       // If src and dst are on CIFS, we can see EIO.
+                       // See issue #42334.
+                       //
                        // If the file is on NFS, we can see EOPNOTSUPP.
                        // See issue #40731.
                        //
index 7c10213b868db7d54babab36ece9e7ce95a2123b..64a7c088585cdee9f7d0ce3f59a421a0b68e3912 100644 (file)
@@ -612,3 +612,16 @@ func TestEINTR(t *testing.T) {
                t.Fatalf("want %s, got %s\n", want, output)
        }
 }
+
+// Issue #42207.
+func TestNeedmDeadlock(t *testing.T) {
+       switch runtime.GOOS {
+       case "plan9", "windows":
+               t.Skipf("no signals on %s", runtime.GOOS)
+       }
+       output := runTestProg(t, "testprogcgo", "NeedmDeadlock")
+       want := "OK\n"
+       if output != want {
+               t.Fatalf("want %s, got %s\n", want, output)
+       }
+}
index ff0ee3aa6be8dfd4ae3adfbb82c9eaeaa4f18031..94983b358d4abdc604a84fcb488e3628bc81e397 100644 (file)
@@ -59,7 +59,7 @@ func mpreinit(mp *m) {
 }
 
 //go:nosplit
-func msigsave(mp *m) {
+func sigsave(p *sigset) {
 }
 
 //go:nosplit
index 6c720503c44471e28a79cacf49dde149fe971818..e0b4b50456e3942f4abe262ae00695e85e7a5c17 100644 (file)
@@ -571,7 +571,7 @@ func schedinit() {
        cpuinit() // must run before alginit
        alginit() // maps must not be used before this call
 
-       msigsave(_g_.m)
+       sigsave(&_g_.m.sigmask)
        initSigmask = _g_.m.sigmask
 
        goargs()
@@ -1496,6 +1496,18 @@ func needm(x byte) {
                exit(1)
        }
 
+       // Save and block signals before getting an M.
+       // The signal handler may call needm itself,
+       // and we must avoid a deadlock. Also, once g is installed,
+       // any incoming signals will try to execute,
+       // but we won't have the sigaltstack settings and other data
+       // set up appropriately until the end of minit, which will
+       // unblock the signals. This is the same dance as when
+       // starting a new m to run Go code via newosproc.
+       var sigmask sigset
+       sigsave(&sigmask)
+       sigblock()
+
        // Lock extra list, take head, unlock popped list.
        // nilokay=false is safe here because of the invariant above,
        // that the extra list always contains or will soon contain
@@ -1513,14 +1525,8 @@ func needm(x byte) {
        extraMCount--
        unlockextra(mp.schedlink.ptr())
 
-       // Save and block signals before installing g.
-       // Once g is installed, any incoming signals will try to execute,
-       // but we won't have the sigaltstack settings and other data
-       // set up appropriately until the end of minit, which will
-       // unblock the signals. This is the same dance as when
-       // starting a new m to run Go code via newosproc.
-       msigsave(mp)
-       sigblock()
+       // Store the original signal mask for use by minit.
+       mp.sigmask = sigmask
 
        // Install g (= m->curg).
        setg(mp.curg)
@@ -3300,7 +3306,7 @@ func beforefork() {
        // a signal handler before exec if a signal is sent to the process
        // group. See issue #18600.
        gp.m.locks++
-       msigsave(gp.m)
+       sigsave(&gp.m.sigmask)
        sigblock()
 }
 
index 6b69dcf06d258c1d819bad3ac8b5d93327dd08ca..ec7c6471b5d8a97c794400c1c6ab946e65ab15ca 100644 (file)
@@ -956,15 +956,15 @@ func sigfwdgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) bool {
        return true
 }
 
-// msigsave saves the current thread's signal mask into mp.sigmask.
+// sigsave saves the current thread's signal mask into *p.
 // This is used to preserve the non-Go signal mask when a non-Go
 // thread calls a Go function.
 // This is nosplit and nowritebarrierrec because it is called by needm
 // which may be called on a non-Go thread with no g available.
 //go:nosplit
 //go:nowritebarrierrec
-func msigsave(mp *m) {
-       sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+func sigsave(p *sigset) {
+       sigprocmask(_SIG_SETMASK, nil, p)
 }
 
 // msigrestore sets the current thread's signal mask to sigmask.
@@ -1038,7 +1038,7 @@ func minitSignalStack() {
 // thread's signal mask. When this is called all signals have been
 // blocked for the thread.  This starts with m.sigmask, which was set
 // either from initSigmask for a newly created thread or by calling
-// msigsave if this is a non-Go thread calling a Go function. It
+// sigsave if this is a non-Go thread calling a Go function. It
 // removes all essential signals from the mask, thus causing those
 // signals to not be blocked. Then it sets the thread's signal mask.
 // After this is called the thread can receive signals.
diff --git a/libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go b/libgo/go/runtime/testdata/testprogcgo/needmdeadlock.go
new file mode 100644 (file)
index 0000000..5a9c359
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!windows
+
+package main
+
+// This is for issue #42207.
+// During a call to needm we could get a SIGCHLD signal
+// which would itself call needm, causing a deadlock.
+
+/*
+#include <signal.h>
+#include <pthread.h>
+#include <sched.h>
+#include <unistd.h>
+
+extern void GoNeedM();
+
+#define SIGNALERS 10
+
+static void* needmSignalThread(void* p) {
+       pthread_t* pt = (pthread_t*)(p);
+       int i;
+
+       for (i = 0; i < 100; i++) {
+               if (pthread_kill(*pt, SIGCHLD) < 0) {
+                       return NULL;
+               }
+               usleep(1);
+       }
+       return NULL;
+}
+
+// We don't need many calls, as the deadlock is only likely
+// to occur the first couple of times that needm is called.
+// After that there will likely be an extra M available.
+#define CALLS 10
+
+static void* needmCallbackThread(void* p) {
+       int i;
+
+       for (i = 0; i < SIGNALERS; i++) {
+               sched_yield(); // Help the signal threads get started.
+       }
+       for (i = 0; i < CALLS; i++) {
+               GoNeedM();
+       }
+       return NULL;
+}
+
+static void runNeedmSignalThread() {
+       int i;
+       pthread_t caller;
+       pthread_t s[SIGNALERS];
+
+       pthread_create(&caller, NULL, needmCallbackThread, NULL);
+       for (i = 0; i < SIGNALERS; i++) {
+               pthread_create(&s[i], NULL, needmSignalThread, &caller);
+       }
+       for (i = 0; i < SIGNALERS; i++) {
+               pthread_join(s[i], NULL);
+       }
+       pthread_join(caller, NULL);
+}
+*/
+import "C"
+
+import (
+       "fmt"
+       "os"
+       "time"
+)
+
+func init() {
+       register("NeedmDeadlock", NeedmDeadlock)
+}
+
+//export GoNeedM
+func GoNeedM() {
+}
+
+func NeedmDeadlock() {
+       // The failure symptom is that the program hangs because of a
+       // deadlock in needm, so set an alarm.
+       go func() {
+               time.Sleep(5 * time.Second)
+               fmt.Println("Hung for 5 seconds")
+               os.Exit(1)
+       }()
+
+       C.runNeedmSignalThread()
+       fmt.Println("OK")
+}
index 274ce01c0bf1d5b99c0c4641ba2354dcf41dbf22..c037df645b9accc100908b3b4df194b24e753ace 100644 (file)
@@ -222,6 +222,9 @@ runtime_m(void)
 }
 
 // Set g.
+
+void runtime_setg(G*) __attribute__ ((no_split_stack));
+
 void
 runtime_setg(G* gp)
 {