mirror of
https://github.com/golang/go.git
synced 2026-01-29 23:22:06 +03:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d81858868 | ||
|
|
681a667ced | ||
|
|
806a84d3f1 | ||
|
|
87d4bd1997 | ||
|
|
1e933ed7c0 | ||
|
|
78d024a588 | ||
|
|
7a62274065 | ||
|
|
219ca602ab | ||
|
|
26015b9563 | ||
|
|
9fde86b012 | ||
|
|
3a03e877cc | ||
|
|
10316757ce | ||
|
|
da070bed19 | ||
|
|
09fc3cc5df | ||
|
|
17a48e0a00 |
@@ -30,6 +30,13 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
|
||||
See the <a href="/security">security policy</a> for more details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.7 is a major release of Go.
|
||||
Read the <a href="/doc/go1.7">Go 1.7 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--{
|
||||
"Title": "Go 1.7 Release Notes DRAFT",
|
||||
"Title": "Go 1.7 Release Notes",
|
||||
"Path": "/doc/go1.7",
|
||||
"Template": true
|
||||
}-->
|
||||
@@ -25,15 +25,6 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
<p>
|
||||
<!-- TODO: REMOVE THIS COMMENT -->
|
||||
<!-- TODO: Also remove "DRAFT" in the "Title" at the top of this file. -->
|
||||
<i>NOTE: This is a DRAFT of the Go 1.7 release notes, prepared for the Go 1.7 beta.
|
||||
Go 1.7 has NOT yet been released.
|
||||
By our regular schedule, it is expected some time in August 2016.
|
||||
</i>
|
||||
</p>
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1.7</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -203,7 +203,7 @@ To build without <code>cgo</code>, set the environment variable
|
||||
Change to the directory that will be its parent
|
||||
and make sure the <code>go</code> directory does not exist.
|
||||
Then clone the repository and check out the latest release tag
|
||||
(<code class="versionTag">go1.6</code>, for example):</p>
|
||||
(<code class="versionTag">go1.7</code>, for example):</p>
|
||||
|
||||
<pre>
|
||||
$ git clone https://go.googlesource.com/go
|
||||
@@ -391,7 +391,7 @@ New releases are announced on the
|
||||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
|
||||
mailing list.
|
||||
Each announcement mentions the latest release tag, for instance,
|
||||
<code class="versionTag">go1.6</code>.
|
||||
<code class="versionTag">go1.7</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -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>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
|
||||
<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr>
|
||||
<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
23
src/syscall/syscall_darwin_test.go
Normal file
23
src/syscall/syscall_darwin_test.go
Normal file
@@ -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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user