summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stapelberg <stapelberg@debian.org>2014-03-03 17:40:28 +0100
committerMichael Stapelberg <stapelberg@debian.org>2014-03-03 17:40:28 +0100
commit9c01ffca14473c5eb84b73e9cafdfcae46505aea (patch)
tree8e1ff9eed085f6d05f6a538fcb927e3f57bdcfb7
parentf3bac4df22adcdd6ff99eaf351605cf7872c7319 (diff)
parentc8bf49ef8a92e2337b69c14b9b88396efe498600 (diff)
downloadgolang-9c01ffca14473c5eb84b73e9cafdfcae46505aea.tar.gz
Merge tag 'upstream/1.2.1' into debian-sid
Upstream version 1.2.1
-rw-r--r--VERSION2
-rw-r--r--doc/devel/release.html6
-rw-r--r--doc/install.html2
-rw-r--r--src/pkg/database/sql/sql.go4
-rw-r--r--src/pkg/database/sql/sql_test.go23
-rw-r--r--src/pkg/net/fd_windows.go48
-rw-r--r--src/pkg/net/net_windows_test.go146
-rw-r--r--src/pkg/runtime/mgc0.c5
-rw-r--r--src/pkg/runtime/mprof.goc4
-rw-r--r--src/pkg/runtime/proc.c4
-rw-r--r--src/pkg/runtime/sys_x86.c13
-rw-r--r--src/pkg/runtime/traceback_arm.c12
-rw-r--r--src/pkg/runtime/traceback_x86.c10
-rw-r--r--src/pkg/syscall/ztypes_windows.go2
14 files changed, 264 insertions, 17 deletions
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).
</p>
+<h3 id="go1.2.minor">Minor revisions</h3>
+
+<p>
+go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
+See the <a href="https://code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
+</p>
<h3 id="r58.minor">Minor revisions</h3>
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 <code>/usr/local</code>, creating a Go tree in
</p>
<pre>
-tar -C /usr/local -xzf go1.1.linux-amd64.tar.gz
+tar -C /usr/local -xzf go1.2.1.linux-amd64.tar.gz
</pre>
<p>
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 (