aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Broadfoot <cbro@golang.org>2016-08-08 11:28:55 -0700
committerChris Broadfoot <cbro@golang.org>2016-08-08 11:30:51 -0700
commit78d024a5880a3a1b6e779a6585344b6c20a200ec (patch)
tree3f988c90d5a622c30347ab8e50b33880fc69bad5
parent09fc3cc5df6b37b62a219bd4cacd8898a2328b76 (diff)
parent7a622740655bb5fcbd160eb96887032314842e6e (diff)
downloadgo-78d024a5880a3a1b6e779a6585344b6c20a200ec.tar.gz
go-78d024a5880a3a1b6e779a6585344b6c20a200ec.zip
all: merge master into release-branch.go1.7
7a62274 net/http: make Transport use new connection if over HTTP/2 concurrency limit 219ca60 doc: fix required OS X version inconsistency for binary downloads 26015b9 runtime: make stack 16-byte aligned for external code in _rt0_amd64_linux_lib 9fde86b runtime, syscall: fix kernel gettimeofday ABI change on iOS 10 3a03e87 os: check for waitid returning ENOSYS 1031675 net/http: update bundled http2 for flow control window adjustment fix da070be syscall: fix Gettimeofday on macOS Sierra f135c32 runtime: initialize hash algs before typemap Change-Id: Ie176f3db1e253d75ae8e56b16d3fd9900b37dde3
-rw-r--r--doc/install.html4
-rw-r--r--src/net/http/h2_bundle.go112
-rw-r--r--src/net/http/transport.go9
-rw-r--r--src/os/wait_waitid.go6
-rw-r--r--src/runtime/alg.go2
-rw-r--r--src/runtime/proc.go3
-rw-r--r--src/runtime/rt0_linux_amd64.s8
-rw-r--r--src/runtime/sys_darwin_arm.s15
-rw-r--r--src/runtime/sys_darwin_arm64.s14
-rw-r--r--src/syscall/syscall_darwin_386.go21
-rw-r--r--src/syscall/syscall_darwin_amd64.go21
-rw-r--r--src/syscall/syscall_darwin_arm.go13
-rw-r--r--src/syscall/syscall_darwin_arm64.go13
-rw-r--r--src/syscall/syscall_darwin_test.go23
14 files changed, 198 insertions, 66 deletions
diff --git a/doc/install.html b/doc/install.html
index 0e6b86fdaf..cfe3e67a64 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -17,7 +17,7 @@
<p>
<a href="https://golang.org/dl/" target="_blank">Official binary
distributions</a> are available for the FreeBSD (release 8-STABLE and above),
-Linux, Mac OS X (10.7 and above), and Windows operating systems and
+Linux, Mac OS X (10.8 and above), and Windows operating systems and
the 32-bit (<code>386</code>) and 64-bit (<code>amd64</code>) x86 processor
architectures.
</p>
@@ -49,7 +49,7 @@ If your OS or architecture is not on the list, you may be able to
<tr><td colspan="3"><hr></td></tr>
<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported</td></tr>
-<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup></td></tr>
+<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup> for <code>cgo</code> support</td></tr>
<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>&#8224;</sup>. No need for cygwin or msys.</td></tr>
</table>
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index cd66c0960e..ffe15f0605 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -28,6 +28,7 @@ import (
"io"
"io/ioutil"
"log"
+ "math"
"net"
"net/http/httptrace"
"net/textproto"
@@ -403,9 +404,17 @@ func (e http2ConnectionError) Error() string {
type http2StreamError struct {
StreamID uint32
Code http2ErrCode
+ Cause error // optional additional detail
+}
+
+func http2streamError(id uint32, code http2ErrCode) http2StreamError {
+ return http2StreamError{StreamID: id, Code: code}
}
func (e http2StreamError) Error() string {
+ if e.Cause != nil {
+ return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
+ }
return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
}
@@ -1366,7 +1375,7 @@ func http2parseWindowUpdateFrame(fh http2FrameHeader, p []byte) (http2Frame, err
if fh.StreamID == 0 {
return nil, http2ConnectionError(http2ErrCodeProtocol)
}
- return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol}
+ return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
}
return &http2WindowUpdateFrame{
http2FrameHeader: fh,
@@ -1444,7 +1453,7 @@ func http2parseHeadersFrame(fh http2FrameHeader, p []byte) (_ http2Frame, err er
}
}
if len(p)-int(padLength) <= 0 {
- return nil, http2StreamError{fh.StreamID, http2ErrCodeProtocol}
+ return nil, http2streamError(fh.StreamID, http2ErrCodeProtocol)
}
hf.headerFragBuf = p[:len(p)-int(padLength)]
return hf, nil
@@ -1911,6 +1920,9 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
hdec.SetEmitEnabled(true)
hdec.SetMaxStringLength(fr.maxHeaderStringLen())
hdec.SetEmitFunc(func(hf hpack.HeaderField) {
+ if http2VerboseLogs && http2logFrameReads {
+ log.Printf("http2: decoded hpack field %+v", hf)
+ }
if !httplex.ValidHeaderFieldValue(hf.Value) {
invalid = http2headerFieldValueError(hf.Value)
}
@@ -1969,11 +1981,17 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr
}
if invalid != nil {
fr.errDetail = invalid
- return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol}
+ if http2VerboseLogs {
+ log.Printf("http2: invalid header: %v", invalid)
+ }
+ return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, invalid}
}
if err := mh.checkPseudos(); err != nil {
fr.errDetail = err
- return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol}
+ if http2VerboseLogs {
+ log.Printf("http2: invalid pseudo headers: %v", err)
+ }
+ return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol, err}
}
return mh, nil
}
@@ -3604,7 +3622,7 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
case http2stateOpen:
st.state = http2stateHalfClosedLocal
- errCancel := http2StreamError{st.id, http2ErrCodeCancel}
+ errCancel := http2streamError(st.id, http2ErrCodeCancel)
sc.resetStream(errCancel)
case http2stateHalfClosedRemote:
sc.closeStream(st, http2errHandlerComplete)
@@ -3797,7 +3815,7 @@ func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error
return nil
}
if !st.flow.add(int32(f.Increment)) {
- return http2StreamError{f.StreamID, http2ErrCodeFlowControl}
+ return http2streamError(f.StreamID, http2ErrCodeFlowControl)
}
default:
if !sc.flow.add(int32(f.Increment)) {
@@ -3819,7 +3837,7 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
if st != nil {
st.gotReset = true
st.cancelCtx()
- sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode})
+ sc.closeStream(st, http2streamError(f.StreamID, f.ErrCode))
}
return nil
}
@@ -3922,13 +3940,13 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
if !ok || st.state != http2stateOpen || st.gotTrailerHeader {
if sc.inflow.available() < int32(f.Length) {
- return http2StreamError{id, http2ErrCodeFlowControl}
+ return http2streamError(id, http2ErrCodeFlowControl)
}
sc.inflow.take(int32(f.Length))
sc.sendWindowUpdate(nil, int(f.Length))
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ return http2streamError(id, http2ErrCodeStreamClosed)
}
if st.body == nil {
panic("internal error: should have a body in this state")
@@ -3936,19 +3954,19 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ return http2streamError(id, http2ErrCodeStreamClosed)
}
if f.Length > 0 {
if st.inflow.available() < int32(f.Length) {
- return http2StreamError{id, http2ErrCodeFlowControl}
+ return http2streamError(id, http2ErrCodeFlowControl)
}
st.inflow.take(int32(f.Length))
if len(data) > 0 {
wrote, err := st.body.Write(data)
if err != nil {
- return http2StreamError{id, http2ErrCodeStreamClosed}
+ return http2streamError(id, http2ErrCodeStreamClosed)
}
if wrote != len(data) {
panic("internal error: bad Writer")
@@ -4046,10 +4064,10 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
if sc.unackedSettings == 0 {
- return http2StreamError{st.id, http2ErrCodeProtocol}
+ return http2streamError(st.id, http2ErrCodeProtocol)
}
- return http2StreamError{st.id, http2ErrCodeRefusedStream}
+ return http2streamError(st.id, http2ErrCodeRefusedStream)
}
rw, req, err := sc.newWriterAndRequest(st, f)
@@ -4083,18 +4101,18 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
}
st.gotTrailerHeader = true
if !f.StreamEnded() {
- return http2StreamError{st.id, http2ErrCodeProtocol}
+ return http2streamError(st.id, http2ErrCodeProtocol)
}
if len(f.PseudoFields()) > 0 {
- return http2StreamError{st.id, http2ErrCodeProtocol}
+ return http2streamError(st.id, http2ErrCodeProtocol)
}
if st.trailer != nil {
for _, hf := range f.RegularFields() {
key := sc.canonicalHeader(hf.Name)
if !http2ValidTrailerHeader(key) {
- return http2StreamError{st.id, http2ErrCodeProtocol}
+ return http2streamError(st.id, http2ErrCodeProtocol)
}
st.trailer[key] = append(st.trailer[key], hf.Value)
}
@@ -4148,18 +4166,18 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
isConnect := method == "CONNECT"
if isConnect {
if path != "" || scheme != "" || authority == "" {
- return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
} else if method == "" || path == "" ||
(scheme != "https" && scheme != "http") {
- return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
bodyOpen := !f.StreamEnded()
if method == "HEAD" && bodyOpen {
- return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
var tlsState *tls.ConnectionState // nil if not scheme https
@@ -4216,7 +4234,7 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
var err error
url_, err = url.ParseRequestURI(path)
if err != nil {
- return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
+ return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
requestURI = path
}
@@ -4993,14 +5011,14 @@ type http2ClientConn struct {
br *bufio.Reader
fr *http2Framer
lastActive time.Time
-
- // Settings from peer:
+ // Settings from peer: (also guarded by mu)
maxFrameSize uint32
maxConcurrentStreams uint32
initialWindowSize uint32
- hbuf bytes.Buffer // HPACK encoder writes into this
- henc *hpack.Encoder
- freeBuf [][]byte
+
+ hbuf bytes.Buffer // HPACK encoder writes into this
+ henc *hpack.Encoder
+ freeBuf [][]byte
wmu sync.Mutex // held while writing; acquire AFTER mu if holding both
werr error // first write error that has occurred
@@ -5244,10 +5262,6 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
}
func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2ClientConn, error) {
- if http2VerboseLogs {
- t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
- }
-
cc := &http2ClientConn{
t: t,
tconn: c,
@@ -5260,6 +5274,10 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
singleUse: singleUse,
wantSettingsAck: true,
}
+ if http2VerboseLogs {
+ t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
+ }
+
cc.cond = sync.NewCond(&cc.mu)
cc.flow.add(int32(http2initialWindowSize))
@@ -5324,7 +5342,7 @@ func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
}
return cc.goAway == nil && !cc.closed &&
int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
- cc.nextStreamID < 2147483647
+ cc.nextStreamID < math.MaxInt32
}
func (cc *http2ClientConn) closeIfIdle() {
@@ -5334,9 +5352,13 @@ func (cc *http2ClientConn) closeIfIdle() {
return
}
cc.closed = true
+ nextID := cc.nextStreamID
cc.mu.Unlock()
+ if http2VerboseLogs {
+ cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)
+ }
cc.tconn.Close()
}
@@ -5986,11 +6008,15 @@ func (rl *http2clientConnReadLoop) run() error {
for {
f, err := cc.fr.ReadFrame()
if err != nil {
- cc.vlogf("Transport readFrame error: (%T) %v", err, err)
+ cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err)
}
if se, ok := err.(http2StreamError); ok {
if cs := cc.streamByID(se.StreamID, true); cs != nil {
- rl.endStreamError(cs, cc.fr.errDetail)
+ cs.cc.writeStreamReset(cs.ID, se.Code, err)
+ if se.Cause == nil {
+ se.Cause = cc.fr.errDetail
+ }
+ rl.endStreamError(cs, se)
}
continue
} else if err != nil {
@@ -6034,6 +6060,9 @@ func (rl *http2clientConnReadLoop) run() error {
cc.logf("Transport: unhandled response frame type %T", f)
}
if err != nil {
+ if http2VerboseLogs {
+ cc.vlogf("http2: Transport conn %p received error from processing frame %v: %v", cc, http2summarizeFrame(f), err)
+ }
return err
}
if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
@@ -6381,6 +6410,11 @@ func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err err
if http2isConnectionCloseRequest(cs.req) {
rl.closeWhenIdle = true
}
+
+ select {
+ case cs.resc <- http2resAndError{err: err}:
+ default:
+ }
}
func (cs *http2clientStream) copyTrailers() {
@@ -6425,6 +6459,16 @@ func (rl *http2clientConnReadLoop) processSettings(f *http2SettingsFrame) error
cc.maxConcurrentStreams = s.Val
case http2SettingInitialWindowSize:
+ if s.Val > math.MaxInt32 {
+ return http2ConnectionError(http2ErrCodeFlowControl)
+ }
+
+ delta := int32(s.Val) - int32(cc.initialWindowSize)
+ for _, cs := range cc.streams {
+ cs.flow.add(delta)
+ }
+ cc.cond.Broadcast()
+
cc.initialWindowSize = s.Val
default:
@@ -6475,7 +6519,7 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er
case <-cs.peerReset:
default:
- err := http2StreamError{cs.ID, f.ErrCode}
+ err := http2streamError(cs.ID, f.ErrCode)
cs.resetErr = err
close(cs.peerReset)
cs.bufPipe.CloseWithError(err)
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 009f3c5b6a..3046de5a8e 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -398,6 +398,15 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
// HTTP request on a new connection. The non-nil input error is the
// error from roundTrip.
func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
+ if err == http2ErrNoCachedConn {
+ // Issue 16582: if the user started a bunch of
+ // requests at once, they can all pick the same conn
+ // and violate the server's max concurrent streams.
+ // Instead, match the HTTP/1 behavior for now and dial
+ // again to get a new TCP connection, rather than failing
+ // this request.
+ return true
+ }
if err == errMissingHost {
// User error.
return false
diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go
index 5dbd7f9766..74b7494c0d 100644
--- a/src/os/wait_waitid.go
+++ b/src/os/wait_waitid.go
@@ -28,6 +28,12 @@ func (p *Process) blockUntilWaitable() (bool, error) {
_, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
runtime.KeepAlive(psig)
if e != 0 {
+ // waitid has been available since Linux 2.6.9, but
+ // reportedly is not available in Ubuntu on Windows.
+ // See issue 16610.
+ if e == syscall.ENOSYS {
+ return false, nil
+ }
return false, NewSyscallError("waitid", e)
}
return true, nil
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 66943495b5..147332e1fd 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -289,7 +289,7 @@ var aeskeysched [hashRandomBytes]byte
// used in hash{32,64}.go to seed the hash function
var hashkey [4]uintptr
-func init() {
+func alginit() {
// Install aes hash algorithm if we have the instructions we need
if (GOARCH == "386" || GOARCH == "amd64") &&
GOOS != "nacl" &&
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 1d00930ac5..e693f7e05f 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -439,7 +439,8 @@ func schedinit() {
stackinit()
mallocinit()
mcommoninit(_g_.m)
- typelinksinit()
+ alginit() // maps must not be used before this call
+ typelinksinit() // uses maps
itabsinit()
msigsave(_g_.m)
diff --git a/src/runtime/rt0_linux_amd64.s b/src/runtime/rt0_linux_amd64.s
index 564b51c0b3..ced471f5cb 100644
--- a/src/runtime/rt0_linux_amd64.s
+++ b/src/runtime/rt0_linux_amd64.s
@@ -12,13 +12,18 @@ TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
// When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded.
-TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x48
+// Note: This function calls external C code, which might required 16-byte stack
+// alignment after cmd/internal/obj applies its transformations.
+TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x50
+ MOVQ SP, AX
+ ANDQ $-16, SP
MOVQ BX, 0x10(SP)
MOVQ BP, 0x18(SP)
MOVQ R12, 0x20(SP)
MOVQ R13, 0x28(SP)
MOVQ R14, 0x30(SP)
MOVQ R15, 0x38(SP)
+ MOVQ AX, 0x40(SP)
MOVQ DI, _rt0_amd64_linux_lib_argc<>(SB)
MOVQ SI, _rt0_amd64_linux_lib_argv<>(SB)
@@ -50,6 +55,7 @@ restore:
MOVQ 0x28(SP), R13
MOVQ 0x30(SP), R14
MOVQ 0x38(SP), R15
+ MOVQ 0x40(SP), SP
RET
TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 6b6437dddd..52f6a94d46 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -162,11 +162,15 @@ TEXT runtime·mincore(SB),NOSPLIT,$0
TEXT time·now(SB), 7, $32
MOVW $8(R13), R0 // timeval
MOVW $0, R1 // zone
+ MOVW $0, R2 // see issue 16570
MOVW $SYS_gettimeofday, R12
SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec
-
+ CMP $0, R0
+ BNE inreg
+ MOVW 8(R13), R0
+ MOVW 12(R13), R1
+inreg:
MOVW R1, R2 // usec
-
MOVW R0, sec+0(FP)
MOVW $0, R1
MOVW R1, loc+4(FP)
@@ -178,9 +182,14 @@ TEXT time·now(SB), 7, $32
TEXT runtime·nanotime(SB),NOSPLIT,$32
MOVW $8(R13), R0 // timeval
MOVW $0, R1 // zone
+ MOVW $0, R2 // see issue 16570
MOVW $SYS_gettimeofday, R12
SWI $0x80 // Note: R0 is tv_sec, R1 is tv_usec
-
+ CMP $0, R0
+ BNE inreg
+ MOVW 8(R13), R0
+ MOVW 12(R13), R1
+inreg:
MOVW R1, R2
MOVW $1000000000, R3
MULLU R0, R3, (R1, R0)
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index a3b851d2fc..8e6b5b1ebf 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -155,9 +155,14 @@ TEXT time·now(SB),NOSPLIT,$40-12
MOVD RSP, R0 // timeval
MOVD R0, R9 // this is how dyld calls gettimeofday
MOVW $0, R1 // zone
+ MOVD $0, R2 // see issue 16570
MOVW $SYS_gettimeofday, R16
SVC $0x80 // Note: x0 is tv_sec, w1 is tv_usec
-
+ CMP $0, R0
+ BNE inreg
+ MOVD 0(RSP), R0
+ MOVW 8(RSP), R1
+inreg:
MOVD R0, sec+0(FP)
MOVW $1000, R3
MUL R3, R1
@@ -168,9 +173,14 @@ TEXT runtime·nanotime(SB),NOSPLIT,$40
MOVD RSP, R0 // timeval
MOVD R0, R9 // this is how dyld calls gettimeofday
MOVW $0, R1 // zone
+ MOVD $0, R2 // see issue 16570
MOVW $SYS_gettimeofday, R16
SVC $0x80 // Note: x0 is tv_sec, w1 is tv_usec
-
+ CMP $0, R0
+ BNE inreg
+ MOVD 0(RSP), R0
+ MOVW 8(RSP), R1
+inreg:
MOVW $1000000000, R3
MUL R3, R0
MOVW $1000, R3
diff --git a/src/syscall/syscall_darwin_386.go b/src/syscall/syscall_darwin_386.go
index 7dbb1c3d64..f75de000bd 100644
--- a/src/syscall/syscall_darwin_386.go
+++ b/src/syscall/syscall_darwin_386.go
@@ -26,14 +26,21 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
}
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
-func Gettimeofday(tv *Timeval) (err error) {
- // The tv passed to gettimeofday must be non-nil
- // but is otherwise unused. The answers come back
- // in the two registers.
+func Gettimeofday(tv *Timeval) error {
+ // The tv passed to gettimeofday must be non-nil.
+ // Before macOS Sierra (10.12), tv was otherwise unused and
+ // the answers came back in the two registers.
+ // As of Sierra, gettimeofday return zeros and populates
+ // tv itself.
sec, usec, err := gettimeofday(tv)
- tv.Sec = int32(sec)
- tv.Usec = int32(usec)
- return err
+ if err != nil {
+ return err
+ }
+ if sec != 0 || usec != 0 {
+ tv.Sec = int32(sec)
+ tv.Usec = int32(usec)
+ }
+ return nil
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
index 80e6024aeb..79083117b6 100644
--- a/src/syscall/syscall_darwin_amd64.go
+++ b/src/syscall/syscall_darwin_amd64.go
@@ -26,14 +26,21 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
}
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
-func Gettimeofday(tv *Timeval) (err error) {
- // The tv passed to gettimeofday must be non-nil
- // but is otherwise unused. The answers come back
- // in the two registers.
+func Gettimeofday(tv *Timeval) error {
+ // The tv passed to gettimeofday must be non-nil.
+ // Before macOS Sierra (10.12), tv was otherwise unused and
+ // the answers came back in the two registers.
+ // As of Sierra, gettimeofday return zeros and populates
+ // tv itself.
sec, usec, err := gettimeofday(tv)
- tv.Sec = sec
- tv.Usec = usec
- return err
+ if err != nil {
+ return err
+ }
+ if sec != 0 || usec != 0 {
+ tv.Sec = sec
+ tv.Usec = usec
+ }
+ return nil
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_darwin_arm.go b/src/syscall/syscall_darwin_arm.go
index c302d83131..fe431039f4 100644
--- a/src/syscall/syscall_darwin_arm.go
+++ b/src/syscall/syscall_darwin_arm.go
@@ -26,14 +26,19 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
}
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
-func Gettimeofday(tv *Timeval) (err error) {
+func Gettimeofday(tv *Timeval) error {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
- tv.Sec = int32(sec)
- tv.Usec = int32(usec)
- return err
+ if err != nil {
+ return err
+ }
+ if sec != 0 || usec != 0 {
+ tv.Sec = int32(sec)
+ tv.Usec = int32(usec)
+ }
+ return nil
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
index 29f40d4229..d396e25332 100644
--- a/src/syscall/syscall_darwin_arm64.go
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -26,14 +26,19 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
}
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
-func Gettimeofday(tv *Timeval) (err error) {
+func Gettimeofday(tv *Timeval) error {
// The tv passed to gettimeofday must be non-nil
// but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
- tv.Sec = sec
- tv.Usec = usec
- return err
+ if err != nil {
+ return err
+ }
+ if sec != 0 || usec != 0 {
+ tv.Sec = sec
+ tv.Usec = usec
+ }
+ return nil
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_darwin_test.go b/src/syscall/syscall_darwin_test.go
new file mode 100644
index 0000000000..cea5636d07
--- /dev/null
+++ b/src/syscall/syscall_darwin_test.go
@@ -0,0 +1,23 @@
+// Copyright 2016 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 darwin
+// +build amd64 386 arm arm64
+
+package syscall_test
+
+import (
+ "syscall"
+ "testing"
+)
+
+func TestDarwinGettimeofday(t *testing.T) {
+ tv := &syscall.Timeval{}
+ if err := syscall.Gettimeofday(tv); err != nil {
+ t.Fatal(err)
+ }
+ if tv.Sec == 0 && tv.Usec == 0 {
+ t.Fatal("Sec and Usec both zero")
+ }
+}