From c8bf49ef8a92e2337b69c14b9b88396efe498600 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 3 Mar 2014 17:40:19 +0100 Subject: Imported Upstream version 1.2.1 --- VERSION | 2 +- doc/devel/release.html | 6 ++ doc/install.html | 2 +- src/pkg/database/sql/sql.go | 4 +- src/pkg/database/sql/sql_test.go | 23 ++++++ src/pkg/net/fd_windows.go | 48 ++++++++++--- src/pkg/net/net_windows_test.go | 146 ++++++++++++++++++++++++++++++++++++++ src/pkg/runtime/mgc0.c | 5 +- src/pkg/runtime/mprof.goc | 4 +- src/pkg/runtime/proc.c | 4 +- src/pkg/runtime/sys_x86.c | 13 ++++ src/pkg/runtime/traceback_arm.c | 12 ++++ src/pkg/runtime/traceback_x86.c | 10 +++ src/pkg/syscall/ztypes_windows.go | 2 + 14 files changed, 264 insertions(+), 17 deletions(-) create mode 100644 src/pkg/net/net_windows_test.go diff --git a/VERSION b/VERSION index 7e7b355f7..39dbf6463 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -go1.2 \ No newline at end of file +go1.2.1 \ No newline at end of file diff --git a/doc/devel/release.html b/doc/devel/release.html index d31f79359..5511db71b 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -363,6 +363,12 @@ variable to build and install your own code and external libraries outside of the Go tree (and avoid writing Makefiles).

+

Minor revisions

+ +

+go1.2.1 (released 2014/03/02) includes bug fixes to the runtime, net, and database/sql packages. +See the change history for details. +

Minor revisions

diff --git a/doc/install.html b/doc/install.html index f08c7665f..af4c8f3d1 100644 --- a/doc/install.html +++ b/doc/install.html @@ -76,7 +76,7 @@ and extract it into /usr/local, creating a Go tree in

-tar -C /usr/local -xzf go1.1.linux-amd64.tar.gz
+tar -C /usr/local -xzf go1.2.1.linux-amd64.tar.gz
 

diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go index dddf5a3f2..84a096513 100644 --- a/src/pkg/database/sql/sql.go +++ b/src/pkg/database/sql/sql.go @@ -620,8 +620,8 @@ func (db *DB) conn() (*driverConn, error) { } // If db.maxOpen > 0 and the number of open connections is over the limit - // or there are no free connection, then make a request and wait. - if db.maxOpen > 0 && (db.numOpen >= db.maxOpen || db.freeConn.Len() == 0) { + // and there are no free connection, make a request and wait. + if db.maxOpen > 0 && db.numOpen >= db.maxOpen && db.freeConn.Len() == 0 { // Make the connRequest channel. It's buffered so that the // connectionOpener doesn't block while waiting for the req to be read. ch := make(chan interface{}, 1) diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go index 093c0d64c..787a5c9f7 100644 --- a/src/pkg/database/sql/sql_test.go +++ b/src/pkg/database/sql/sql_test.go @@ -1005,6 +1005,29 @@ func TestMaxOpenConns(t *testing.T) { } } +func TestSingleOpenConn(t *testing.T) { + db := newTestDB(t, "people") + defer closeDB(t, db) + + db.SetMaxOpenConns(1) + + rows, err := db.Query("SELECT|people|name|") + if err != nil { + t.Fatal(err) + } + if err = rows.Close(); err != nil { + t.Fatal(err) + } + // shouldn't deadlock + rows, err = db.Query("SELECT|people|name|") + if err != nil { + t.Fatal(err) + } + if err = rows.Close(); err != nil { + t.Fatal(err) + } +} + // golang.org/issue/5323 func TestStmtCloseDeps(t *testing.T) { if testing.Short() { diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go index 64d56c73e..630fc5e6f 100644 --- a/src/pkg/net/fd_windows.go +++ b/src/pkg/net/fd_windows.go @@ -513,12 +513,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) { }) } -func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) { - if err := fd.readLock(); err != nil { - return nil, err - } - defer fd.readUnlock() - +func (fd *netFD) acceptOne(toAddr func(syscall.Sockaddr) Addr, rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) { // Get new socket. s, err := sysSocket(fd.family, fd.sotype, 0) if err != nil { @@ -537,9 +532,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) { } // Submit accept request. - o := &fd.rop o.handle = s - var rawsa [2]syscall.RawSockaddrAny o.rsan = int32(unsafe.Sizeof(rawsa[0])) _, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error { return syscall.AcceptEx(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o) @@ -556,6 +549,45 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) { return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err} } + return netfd, nil +} + +func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) { + if err := fd.readLock(); err != nil { + return nil, err + } + defer fd.readUnlock() + + o := &fd.rop + var netfd *netFD + var err error + var rawsa [2]syscall.RawSockaddrAny + for { + netfd, err = fd.acceptOne(toAddr, rawsa[:], o) + if err == nil { + break + } + // Sometimes we see WSAECONNRESET and ERROR_NETNAME_DELETED is + // returned here. These happen if connection reset is received + // before AcceptEx could complete. These errors relate to new + // connection, not to AcceptEx, so ignore broken connection and + // try AcceptEx again for more connections. + operr, ok := err.(*OpError) + if !ok { + return nil, err + } + errno, ok := operr.Err.(syscall.Errno) + if !ok { + return nil, err + } + switch errno { + case syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET: + // ignore these and try again + default: + return nil, err + } + } + // Get local and peer addr out of AcceptEx buffer. var lrsa, rrsa *syscall.RawSockaddrAny var llen, rlen int32 diff --git a/src/pkg/net/net_windows_test.go b/src/pkg/net/net_windows_test.go new file mode 100644 index 000000000..8b1c9cdc5 --- /dev/null +++ b/src/pkg/net/net_windows_test.go @@ -0,0 +1,146 @@ +// Copyright 2014 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. + +package net + +import ( + "bufio" + "fmt" + "io" + "os" + "os/exec" + "syscall" + "testing" + "time" +) + +func TestAcceptIgnoreSomeErrors(t *testing.T) { + recv := func(ln Listener) (string, error) { + c, err := ln.Accept() + if err != nil { + // Display windows errno in error message. + operr, ok := err.(*OpError) + if !ok { + return "", err + } + errno, ok := operr.Err.(syscall.Errno) + if !ok { + return "", err + } + return "", fmt.Errorf("%v (windows errno=%d)", err, errno) + } + defer c.Close() + + b := make([]byte, 100) + n, err := c.Read(b) + if err != nil && err != io.EOF { + return "", err + } + return string(b[:n]), nil + } + + send := func(addr string, data string) error { + c, err := Dial("tcp", addr) + if err != nil { + return err + } + defer c.Close() + + b := []byte(data) + n, err := c.Write(b) + if err != nil { + return err + } + if n != len(b) { + return fmt.Errorf(`Only %d chars of string "%s" sent`, n, data) + } + return nil + } + + if envaddr := os.Getenv("GOTEST_DIAL_ADDR"); envaddr != "" { + // In child process. + c, err := Dial("tcp", envaddr) + if err != nil { + t.Fatalf("Dial failed: %v", err) + } + fmt.Printf("sleeping\n") + time.Sleep(time.Minute) // process will be killed here + c.Close() + } + + ln, err := Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("Listen failed: %v", err) + } + defer ln.Close() + + // Start child process that connects to our listener. + cmd := exec.Command(os.Args[0], "-test.run=TestAcceptIgnoreSomeErrors") + cmd.Env = append(os.Environ(), "GOTEST_DIAL_ADDR="+ln.Addr().String()) + stdout, err := cmd.StdoutPipe() + if err != nil { + t.Fatalf("cmd.StdoutPipe failed: %v", err) + } + err = cmd.Start() + if err != nil { + t.Fatalf("cmd.Start failed: %v\n%s\n", err) + } + outReader := bufio.NewReader(stdout) + for { + s, err := outReader.ReadString('\n') + if err != nil { + t.Fatalf("reading stdout failed: %v", err) + } + if s == "sleeping\n" { + break + } + } + defer cmd.Wait() // ignore error - we know it is getting killed + + const alittle = 100 * time.Millisecond + time.Sleep(alittle) + cmd.Process.Kill() // the only way to trigger the errors + time.Sleep(alittle) + + // Send second connection data (with delay in a separate goroutine). + result := make(chan error) + go func() { + time.Sleep(alittle) + err = send(ln.Addr().String(), "abc") + if err != nil { + result <- err + } + result <- nil + }() + defer func() { + err := <-result + if err != nil { + t.Fatalf("send failed: %v", err) + } + }() + + // Receive first or second connection. + s, err := recv(ln) + if err != nil { + t.Fatalf("recv failed: %v", err) + } + switch s { + case "": + // First connection data is received, lets get second connection data. + case "abc": + // First connection is lost forever, but that is ok. + return + default: + t.Fatalf(`"%s" received from recv, but "" or "abc" expected`, s) + } + + // Get second connection data. + s, err = recv(ln) + if err != nil { + t.Fatalf("recv failed: %v", err) + } + if s != "abc" { + t.Fatalf(`"%s" received from recv, but "abc" expected`, s) + } +} diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c index 4b2108ba7..761f128a8 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -1798,6 +1798,8 @@ runtime·memorydump(void) void runtime·gchelper(void) { + int32 nproc; + gchelperstart(); // parallel mark for over gc roots @@ -1814,7 +1816,8 @@ runtime·gchelper(void) runtime·parfordo(work.sweepfor); bufferList[m->helpgc].busy = 0; - if(runtime·xadd(&work.ndone, +1) == work.nproc-1) + nproc = work.nproc; // work.nproc can change right after we increment work.ndone + if(runtime·xadd(&work.ndone, +1) == nproc-1) runtime·notewakeup(&work.alldone); } diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc index 5b92cec95..4ae74f0c2 100644 --- a/src/pkg/runtime/mprof.goc +++ b/src/pkg/runtime/mprof.goc @@ -477,7 +477,7 @@ saveg(uintptr pc, uintptr sp, G *gp, TRecord *r) { int32 n; - n = runtime·gentraceback((uintptr)pc, (uintptr)sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil, false); + n = runtime·gentraceback(pc, sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil, false); if(n < nelem(r->stk)) r->stk[n] = 0; } @@ -505,7 +505,7 @@ func GoroutineProfile(b Slice) (n int, ok bool) { for(gp = runtime·allg; gp != nil; gp = gp->alllink) { if(gp == g || gp->status == Gdead) continue; - saveg(gp->sched.pc, gp->sched.sp, gp, r++); + saveg(~(uintptr)0, ~(uintptr)0, gp, r++); } } diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index de26c72d3..ed3e1e73e 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -276,7 +276,7 @@ runtime·tracebackothers(G *me) if((gp = m->curg) != nil && gp != me) { runtime·printf("\n"); runtime·goroutineheader(gp); - runtime·traceback(gp->sched.pc, gp->sched.sp, gp->sched.lr, gp); + runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp); } for(gp = runtime·allg; gp != nil; gp = gp->alllink) { @@ -290,7 +290,7 @@ runtime·tracebackothers(G *me) runtime·printf("\tgoroutine running on other thread; stack unavailable\n"); runtime·printcreatedby(gp); } else - runtime·traceback(gp->sched.pc, gp->sched.sp, gp->sched.lr, gp); + runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp); } } diff --git a/src/pkg/runtime/sys_x86.c b/src/pkg/runtime/sys_x86.c index e68ff514a..0df6dfbbd 100644 --- a/src/pkg/runtime/sys_x86.c +++ b/src/pkg/runtime/sys_x86.c @@ -37,6 +37,19 @@ runtime·rewindmorestack(Gobuf *gobuf) gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1); return; } + if(pc[0] == 0xcc) { + // This is a breakpoint inserted by gdb. We could use + // runtime·findfunc to find the function. But if we + // do that, then we will continue execution at the + // function entry point, and we will not hit the gdb + // breakpoint. So for this case we don't change + // gobuf->pc, so that when we return we will execute + // the jump instruction and carry on. This means that + // stack unwinding may not work entirely correctly + // (http://golang.org/issue/5723) but the user is + // running under gdb anyhow. + return; + } runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]); runtime·throw("runtime: misuse of rewindmorestack"); } diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c index 341aa2058..8a3685e76 100644 --- a/src/pkg/runtime/traceback_arm.c +++ b/src/pkg/runtime/traceback_arm.c @@ -20,6 +20,18 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, Stktop *stk; String file; + if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp. + if(gp->syscallstack != (uintptr)nil) { + pc0 = gp->syscallpc; + sp0 = gp->syscallsp; + lr0 = 0; + } else { + pc0 = gp->sched.pc; + sp0 = gp->sched.sp; + lr0 = gp->sched.lr; + } + } + nprint = 0; runtime·memclr((byte*)&frame, sizeof frame); frame.pc = pc0; diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c index d658e8f11..8e3063f43 100644 --- a/src/pkg/runtime/traceback_x86.c +++ b/src/pkg/runtime/traceback_x86.c @@ -30,6 +30,16 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip, String file; USED(lr0); + + if(pc0 == ~(uintptr)0 && sp0 == ~(uintptr)0) { // Signal to fetch saved values from gp. + if(gp->syscallstack != (uintptr)nil) { + pc0 = gp->syscallpc; + sp0 = gp->syscallsp; + } else { + pc0 = gp->sched.pc; + sp0 = gp->sched.sp; + } + } nprint = 0; runtime·memclr((byte*)&frame, sizeof frame); diff --git a/src/pkg/syscall/ztypes_windows.go b/src/pkg/syscall/ztypes_windows.go index bdc15ce3b..a5681d700 100644 --- a/src/pkg/syscall/ztypes_windows.go +++ b/src/pkg/syscall/ztypes_windows.go @@ -11,6 +11,7 @@ const ( ERROR_ACCESS_DENIED Errno = 5 ERROR_NO_MORE_FILES Errno = 18 ERROR_HANDLE_EOF Errno = 38 + ERROR_NETNAME_DELETED Errno = 64 ERROR_FILE_EXISTS Errno = 80 ERROR_BROKEN_PIPE Errno = 109 ERROR_BUFFER_OVERFLOW Errno = 111 @@ -23,6 +24,7 @@ const ( ERROR_IO_PENDING Errno = 997 ERROR_NOT_FOUND Errno = 1168 WSAEACCES Errno = 10013 + WSAECONNRESET Errno = 10054 ) const ( -- cgit v1.2.3