libgo: update to Go 1.15.4 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/268177
This commit is contained in:
parent
0000ea4fb4
commit
cf392dbdf1
|
@ -1,4 +1,4 @@
|
||||||
ae20684902b82883d3d65f2cde0894c7cb3b995b
|
893fa057e36ae6c9b2ac5ffdf74634c35b3489c6
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the last
|
The first line of this file holds the git revision number of the last
|
||||||
merge done from the gofrontend repository.
|
merge done from the gofrontend repository.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
1984ee00048b63eacd2155cd6d74a2d13e998272
|
0e953add9656c32a788e06438cd7b533e968b7f8
|
||||||
|
|
||||||
The first line of this file holds the git revision number of the
|
The first line of this file holds the git revision number of the
|
||||||
last merge done from the master library sources.
|
last merge done from the master library sources.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
go1.15.3
|
go1.15.4
|
||||||
|
|
|
@ -655,11 +655,6 @@ var codeRepoVersionsTests = []struct {
|
||||||
path: "swtch.com/testmod",
|
path: "swtch.com/testmod",
|
||||||
versions: []string{"v1.0.0", "v1.1.1"},
|
versions: []string{"v1.0.0", "v1.1.1"},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
vcs: "git",
|
|
||||||
path: "gopkg.in/russross/blackfriday.v2",
|
|
||||||
versions: []string{"v2.0.0", "v2.0.1"},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
vcs: "git",
|
vcs: "git",
|
||||||
path: "gopkg.in/natefinch/lumberjack.v2",
|
path: "gopkg.in/natefinch/lumberjack.v2",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -896,6 +897,62 @@ func TestBestSpeedMaxMatchOffset(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBestSpeedShiftOffsets(t *testing.T) {
|
||||||
|
// Test if shiftoffsets properly preserves matches and resets out-of-range matches
|
||||||
|
// seen in https://github.com/golang/go/issues/4142
|
||||||
|
enc := newDeflateFast()
|
||||||
|
|
||||||
|
// testData may not generate internal matches.
|
||||||
|
testData := make([]byte, 32)
|
||||||
|
rng := rand.New(rand.NewSource(0))
|
||||||
|
for i := range testData {
|
||||||
|
testData[i] = byte(rng.Uint32())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode the testdata with clean state.
|
||||||
|
// Second part should pick up matches from the first block.
|
||||||
|
wantFirstTokens := len(enc.encode(nil, testData))
|
||||||
|
wantSecondTokens := len(enc.encode(nil, testData))
|
||||||
|
|
||||||
|
if wantFirstTokens <= wantSecondTokens {
|
||||||
|
t.Fatalf("test needs matches between inputs to be generated")
|
||||||
|
}
|
||||||
|
// Forward the current indicator to before wraparound.
|
||||||
|
enc.cur = bufferReset - int32(len(testData))
|
||||||
|
|
||||||
|
// Part 1 before wrap, should match clean state.
|
||||||
|
got := len(enc.encode(nil, testData))
|
||||||
|
if wantFirstTokens != got {
|
||||||
|
t.Errorf("got %d, want %d tokens", got, wantFirstTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify we are about to wrap.
|
||||||
|
if enc.cur != bufferReset {
|
||||||
|
t.Errorf("got %d, want e.cur to be at bufferReset (%d)", enc.cur, bufferReset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Part 2 should match clean state as well even if wrapped.
|
||||||
|
got = len(enc.encode(nil, testData))
|
||||||
|
if wantSecondTokens != got {
|
||||||
|
t.Errorf("got %d, want %d token", got, wantSecondTokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that we wrapped.
|
||||||
|
if enc.cur >= bufferReset {
|
||||||
|
t.Errorf("want e.cur to be < bufferReset (%d), got %d", bufferReset, enc.cur)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward the current buffer, leaving the matches at the bottom.
|
||||||
|
enc.cur = bufferReset
|
||||||
|
enc.shiftOffsets()
|
||||||
|
|
||||||
|
// Ensure that no matches were picked up.
|
||||||
|
got = len(enc.encode(nil, testData))
|
||||||
|
if wantFirstTokens != got {
|
||||||
|
t.Errorf("got %d, want %d tokens", got, wantFirstTokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMaxStackSize(t *testing.T) {
|
func TestMaxStackSize(t *testing.T) {
|
||||||
// This test must not run in parallel with other tests as debug.SetMaxStack
|
// This test must not run in parallel with other tests as debug.SetMaxStack
|
||||||
// affects all goroutines.
|
// affects all goroutines.
|
||||||
|
|
|
@ -270,6 +270,7 @@ func (e *deflateFast) matchLen(s, t int32, src []byte) int32 {
|
||||||
func (e *deflateFast) reset() {
|
func (e *deflateFast) reset() {
|
||||||
e.prev = e.prev[:0]
|
e.prev = e.prev[:0]
|
||||||
// Bump the offset, so all matches will fail distance check.
|
// Bump the offset, so all matches will fail distance check.
|
||||||
|
// Nothing should be >= e.cur in the table.
|
||||||
e.cur += maxMatchOffset
|
e.cur += maxMatchOffset
|
||||||
|
|
||||||
// Protect against e.cur wraparound.
|
// Protect against e.cur wraparound.
|
||||||
|
@ -288,17 +289,21 @@ func (e *deflateFast) shiftOffsets() {
|
||||||
for i := range e.table[:] {
|
for i := range e.table[:] {
|
||||||
e.table[i] = tableEntry{}
|
e.table[i] = tableEntry{}
|
||||||
}
|
}
|
||||||
e.cur = maxMatchOffset
|
e.cur = maxMatchOffset + 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift down everything in the table that isn't already too far away.
|
// Shift down everything in the table that isn't already too far away.
|
||||||
for i := range e.table[:] {
|
for i := range e.table[:] {
|
||||||
v := e.table[i].offset - e.cur + maxMatchOffset
|
v := e.table[i].offset - e.cur + maxMatchOffset + 1
|
||||||
if v < 0 {
|
if v < 0 {
|
||||||
|
// We want to reset e.cur to maxMatchOffset + 1, so we need to shift
|
||||||
|
// all table entries down by (e.cur - (maxMatchOffset + 1)).
|
||||||
|
// Because we ignore matches > maxMatchOffset, we can cap
|
||||||
|
// any negative offsets at 0.
|
||||||
v = 0
|
v = 0
|
||||||
}
|
}
|
||||||
e.table[i].offset = v
|
e.table[i].offset = v
|
||||||
}
|
}
|
||||||
e.cur = maxMatchOffset
|
e.cur = maxMatchOffset + 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -5265,6 +5265,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
wrote, err := st.body.Write(data)
|
wrote, err := st.body.Write(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
sc.sendWindowUpdate(nil, int(f.Length)-wrote)
|
||||||
return http2streamError(id, http2ErrCodeStreamClosed)
|
return http2streamError(id, http2ErrCodeStreamClosed)
|
||||||
}
|
}
|
||||||
if wrote != len(data) {
|
if wrote != len(data) {
|
||||||
|
@ -7167,6 +7168,7 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
|
||||||
cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
|
cc.inflow.add(http2transportDefaultConnFlow + http2initialWindowSize)
|
||||||
cc.bw.Flush()
|
cc.bw.Flush()
|
||||||
if cc.werr != nil {
|
if cc.werr != nil {
|
||||||
|
cc.Close()
|
||||||
return nil, cc.werr
|
return nil, cc.werr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7532,6 +7534,15 @@ func (cc *http2ClientConn) roundTrip(req *Request) (res *Response, gotErrAfterRe
|
||||||
bodyWriter := cc.t.getBodyWriterState(cs, body)
|
bodyWriter := cc.t.getBodyWriterState(cs, body)
|
||||||
cs.on100 = bodyWriter.on100
|
cs.on100 = bodyWriter.on100
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
cc.wmu.Lock()
|
||||||
|
werr := cc.werr
|
||||||
|
cc.wmu.Unlock()
|
||||||
|
if werr != nil {
|
||||||
|
cc.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
cc.wmu.Lock()
|
cc.wmu.Lock()
|
||||||
endStream := !hasBody && !hasTrailers
|
endStream := !hasBody && !hasTrailers
|
||||||
werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
|
werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)
|
||||||
|
|
|
@ -382,7 +382,7 @@ func (r *Request) Clone(ctx context.Context) *Request {
|
||||||
if s := r.TransferEncoding; s != nil {
|
if s := r.TransferEncoding; s != nil {
|
||||||
s2 := make([]string, len(s))
|
s2 := make([]string, len(s))
|
||||||
copy(s2, s)
|
copy(s2, s)
|
||||||
r2.TransferEncoding = s
|
r2.TransferEncoding = s2
|
||||||
}
|
}
|
||||||
r2.Form = cloneURLValues(r.Form)
|
r2.Form = cloneURLValues(r.Form)
|
||||||
r2.PostForm = cloneURLValues(r.PostForm)
|
r2.PostForm = cloneURLValues(r.PostForm)
|
||||||
|
|
|
@ -828,6 +828,27 @@ func TestWithContextDeepCopiesURL(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that Request.Clone creates a deep copy of TransferEncoding.
|
||||||
|
// See issue 41907.
|
||||||
|
func TestRequestCloneTransferEncoding(t *testing.T) {
|
||||||
|
body := strings.NewReader("body")
|
||||||
|
req, _ := NewRequest("POST", "https://example.org/", body)
|
||||||
|
req.TransferEncoding = []string{
|
||||||
|
"encoding1",
|
||||||
|
}
|
||||||
|
|
||||||
|
clonedReq := req.Clone(context.Background())
|
||||||
|
// modify original after deep copy
|
||||||
|
req.TransferEncoding[0] = "encoding2"
|
||||||
|
|
||||||
|
if req.TransferEncoding[0] != "encoding2" {
|
||||||
|
t.Error("expected req.TransferEncoding to be changed")
|
||||||
|
}
|
||||||
|
if clonedReq.TransferEncoding[0] != "encoding1" {
|
||||||
|
t.Error("expected clonedReq.TransferEncoding to be unchanged")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) {
|
func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) {
|
||||||
testNoPanicWithBasicAuth(t, h1Mode)
|
testNoPanicWithBasicAuth(t, h1Mode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,17 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
|
||||||
// and it's safe and valid to get Value's internal pointer.
|
// and it's safe and valid to get Value's internal pointer.
|
||||||
hard := func(v1, v2 Value) bool {
|
hard := func(v1, v2 Value) bool {
|
||||||
switch v1.Kind() {
|
switch v1.Kind() {
|
||||||
case Map, Slice, Ptr, Interface:
|
case Ptr:
|
||||||
|
if v1.typ.ptrdata == 0 {
|
||||||
|
// go:notinheap pointers can't be cyclic.
|
||||||
|
// At least, all of our current uses of go:notinheap have
|
||||||
|
// that property. The runtime ones aren't cyclic (and we don't use
|
||||||
|
// DeepEqual on them anyway), and the cgo-generated ones are
|
||||||
|
// all empty structs.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case Map, Slice, Interface:
|
||||||
// Nil pointers cannot be cyclic. Avoid putting them in the visited map.
|
// Nil pointers cannot be cyclic. Avoid putting them in the visited map.
|
||||||
return !v1.IsNil() && !v2.IsNil()
|
return !v1.IsNil() && !v2.IsNil()
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ func (f flag) ro() flag {
|
||||||
|
|
||||||
// pointer returns the underlying pointer represented by v.
|
// pointer returns the underlying pointer represented by v.
|
||||||
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
|
// v.Kind() must be Ptr, Map, Chan, Func, or UnsafePointer
|
||||||
|
// if v.Kind() == Ptr, the base type must not be go:notinheap.
|
||||||
func (v Value) pointer() unsafe.Pointer {
|
func (v Value) pointer() unsafe.Pointer {
|
||||||
if v.typ.size != ptrSize || !v.typ.pointers() {
|
if v.typ.size != ptrSize || !v.typ.pointers() {
|
||||||
panic("can't call pointer on a non-pointer Value")
|
panic("can't call pointer on a non-pointer Value")
|
||||||
|
@ -1263,7 +1264,16 @@ func (v Value) Pointer() uintptr {
|
||||||
// TODO: deprecate
|
// TODO: deprecate
|
||||||
k := v.kind()
|
k := v.kind()
|
||||||
switch k {
|
switch k {
|
||||||
case Chan, Map, Ptr, UnsafePointer:
|
case Ptr:
|
||||||
|
if v.typ.ptrdata == 0 {
|
||||||
|
// Handle pointers to go:notinheap types directly,
|
||||||
|
// so we never materialize such pointers as an
|
||||||
|
// unsafe.Pointer. (Such pointers are always indirect.)
|
||||||
|
// See issue 42076.
|
||||||
|
return *(*uintptr)(v.ptr)
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case Chan, Map, UnsafePointer:
|
||||||
return uintptr(v.pointer())
|
return uintptr(v.pointer())
|
||||||
case Func:
|
case Func:
|
||||||
p := v.pointer()
|
p := v.pointer()
|
||||||
|
|
|
@ -92,6 +92,7 @@ type pollDesc struct {
|
||||||
wg uintptr // pdReady, pdWait, G waiting for write or nil
|
wg uintptr // pdReady, pdWait, G waiting for write or nil
|
||||||
wt timer // write deadline timer
|
wt timer // write deadline timer
|
||||||
wd int64 // write deadline
|
wd int64 // write deadline
|
||||||
|
self *pollDesc // storage for indirect interface. See (*pollDesc).makeArg.
|
||||||
}
|
}
|
||||||
|
|
||||||
type pollCache struct {
|
type pollCache struct {
|
||||||
|
@ -160,6 +161,7 @@ func poll_runtime_pollOpen(fd uintptr) (uintptr, int) {
|
||||||
pd.wseq++
|
pd.wseq++
|
||||||
pd.wg = 0
|
pd.wg = 0
|
||||||
pd.wd = 0
|
pd.wd = 0
|
||||||
|
pd.self = pd
|
||||||
unlock(&pd.lock)
|
unlock(&pd.lock)
|
||||||
|
|
||||||
var errno int32
|
var errno int32
|
||||||
|
@ -279,14 +281,14 @@ func poll_runtime_pollSetDeadline(ctx uintptr, d int64, mode int) {
|
||||||
// Copy current seq into the timer arg.
|
// Copy current seq into the timer arg.
|
||||||
// Timer func will check the seq against current descriptor seq,
|
// Timer func will check the seq against current descriptor seq,
|
||||||
// if they differ the descriptor was reused or timers were reset.
|
// if they differ the descriptor was reused or timers were reset.
|
||||||
pd.rt.arg = pd
|
pd.rt.arg = pd.makeArg()
|
||||||
pd.rt.seq = pd.rseq
|
pd.rt.seq = pd.rseq
|
||||||
resettimer(&pd.rt, pd.rd)
|
resettimer(&pd.rt, pd.rd)
|
||||||
}
|
}
|
||||||
} else if pd.rd != rd0 || combo != combo0 {
|
} else if pd.rd != rd0 || combo != combo0 {
|
||||||
pd.rseq++ // invalidate current timers
|
pd.rseq++ // invalidate current timers
|
||||||
if pd.rd > 0 {
|
if pd.rd > 0 {
|
||||||
modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq)
|
modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq)
|
||||||
} else {
|
} else {
|
||||||
deltimer(&pd.rt)
|
deltimer(&pd.rt)
|
||||||
pd.rt.f = nil
|
pd.rt.f = nil
|
||||||
|
@ -295,14 +297,14 @@ func poll_runtime_pollSetDeadline(ctx uintptr, d int64, mode int) {
|
||||||
if pd.wt.f == nil {
|
if pd.wt.f == nil {
|
||||||
if pd.wd > 0 && !combo {
|
if pd.wd > 0 && !combo {
|
||||||
pd.wt.f = netpollWriteDeadline
|
pd.wt.f = netpollWriteDeadline
|
||||||
pd.wt.arg = pd
|
pd.wt.arg = pd.makeArg()
|
||||||
pd.wt.seq = pd.wseq
|
pd.wt.seq = pd.wseq
|
||||||
resettimer(&pd.wt, pd.wd)
|
resettimer(&pd.wt, pd.wd)
|
||||||
}
|
}
|
||||||
} else if pd.wd != wd0 || combo != combo0 {
|
} else if pd.wd != wd0 || combo != combo0 {
|
||||||
pd.wseq++ // invalidate current timers
|
pd.wseq++ // invalidate current timers
|
||||||
if pd.wd > 0 && !combo {
|
if pd.wd > 0 && !combo {
|
||||||
modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq)
|
modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq)
|
||||||
} else {
|
} else {
|
||||||
deltimer(&pd.wt)
|
deltimer(&pd.wt)
|
||||||
pd.wt.f = nil
|
pd.wt.f = nil
|
||||||
|
@ -556,3 +558,21 @@ func (c *pollCache) alloc() *pollDesc {
|
||||||
unlock(&c.lock)
|
unlock(&c.lock)
|
||||||
return pd
|
return pd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makeArg converts pd to an interface{}.
|
||||||
|
// makeArg does not do any allocation. Normally, such
|
||||||
|
// a conversion requires an allocation because pointers to
|
||||||
|
// go:notinheap types (which pollDesc is) must be stored
|
||||||
|
// in interfaces indirectly. See issue 42076.
|
||||||
|
func (pd *pollDesc) makeArg() (i interface{}) {
|
||||||
|
x := (*eface)(unsafe.Pointer(&i))
|
||||||
|
x._type = pdType
|
||||||
|
// For gccgo, we still use pd.self here, not &pd.self.
|
||||||
|
x.data = unsafe.Pointer(pd.self)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pdEface interface{} = (*pollDesc)(nil)
|
||||||
|
pdType *_type = efaceOf(&pdEface)._type
|
||||||
|
)
|
||||||
|
|
|
@ -1258,6 +1258,14 @@ found:
|
||||||
checkdead()
|
checkdead()
|
||||||
unlock(&sched.lock)
|
unlock(&sched.lock)
|
||||||
|
|
||||||
|
if GOOS == "darwin" {
|
||||||
|
// Make sure pendingPreemptSignals is correct when an M exits.
|
||||||
|
// For #41702.
|
||||||
|
if atomic.Load(&m.signalPending) != 0 {
|
||||||
|
atomic.Xadd(&pendingPreemptSignals, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if osStack {
|
if osStack {
|
||||||
// Return from mstart and let the system thread
|
// Return from mstart and let the system thread
|
||||||
// library free the g0 stack and terminate the thread.
|
// library free the g0 stack and terminate the thread.
|
||||||
|
@ -3349,11 +3357,24 @@ func syscall_runtime_AfterForkInChild() {
|
||||||
inForkedChild = false
|
inForkedChild = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pendingPreemptSignals is the number of preemption signals
|
||||||
|
// that have been sent but not received. This is only used on Darwin.
|
||||||
|
// For #41702.
|
||||||
|
var pendingPreemptSignals uint32
|
||||||
|
|
||||||
// Called from syscall package before Exec.
|
// Called from syscall package before Exec.
|
||||||
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
|
//go:linkname syscall_runtime_BeforeExec syscall.runtime_BeforeExec
|
||||||
func syscall_runtime_BeforeExec() {
|
func syscall_runtime_BeforeExec() {
|
||||||
// Prevent thread creation during exec.
|
// Prevent thread creation during exec.
|
||||||
execLock.lock()
|
execLock.lock()
|
||||||
|
|
||||||
|
// On Darwin, wait for all pending preemption signals to
|
||||||
|
// be received. See issue #41702.
|
||||||
|
if GOOS == "darwin" {
|
||||||
|
for int32(atomic.Load(&pendingPreemptSignals)) > 0 {
|
||||||
|
osyield()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from syscall package after Exec.
|
// Called from syscall package after Exec.
|
||||||
|
|
|
@ -347,6 +347,10 @@ func doSigPreempt(gp *g, ctxt *sigctxt, sigpc uintptr) {
|
||||||
// Acknowledge the preemption.
|
// Acknowledge the preemption.
|
||||||
atomic.Xadd(&gp.m.preemptGen, 1)
|
atomic.Xadd(&gp.m.preemptGen, 1)
|
||||||
atomic.Store(&gp.m.signalPending, 0)
|
atomic.Store(&gp.m.signalPending, 0)
|
||||||
|
|
||||||
|
if GOOS == "darwin" {
|
||||||
|
atomic.Xadd(&pendingPreemptSignals, -1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is false for gccgo.
|
// This is false for gccgo.
|
||||||
|
@ -404,6 +408,9 @@ func sigtrampgo(sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
|
||||||
// no non-Go signal handler for sigPreempt.
|
// no non-Go signal handler for sigPreempt.
|
||||||
// The default behavior for sigPreempt is to ignore
|
// The default behavior for sigPreempt is to ignore
|
||||||
// the signal, so badsignal will be a no-op anyway.
|
// the signal, so badsignal will be a no-op anyway.
|
||||||
|
if GOOS == "darwin" {
|
||||||
|
atomic.Xadd(&pendingPreemptSignals, -1)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
badsignal(uintptr(sig), &c)
|
badsignal(uintptr(sig), &c)
|
||||||
|
|
|
@ -9,12 +9,14 @@ package syscall_test
|
||||||
import (
|
import (
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -245,3 +247,46 @@ func TestInvalidExec(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestExec is for issue #41702.
|
||||||
|
func TestExec(t *testing.T) {
|
||||||
|
testenv.MustHaveExec(t)
|
||||||
|
cmd := exec.Command(os.Args[0], "-test.run=TestExecHelper")
|
||||||
|
cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=2")
|
||||||
|
o, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s\n%v", o, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestExecHelper is used by TestExec. It does nothing by itself.
|
||||||
|
// In testing on macOS 10.14, this used to fail with
|
||||||
|
// "signal: illegal instruction" more than half the time.
|
||||||
|
func TestExecHelper(t *testing.T) {
|
||||||
|
if os.Getenv("GO_WANT_HELPER_PROCESS") != "2" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't have to worry about restoring these values.
|
||||||
|
// We are in a child process that only runs this test,
|
||||||
|
// and we are going to call syscall.Exec anyhow.
|
||||||
|
runtime.GOMAXPROCS(50)
|
||||||
|
os.Setenv("GO_WANT_HELPER_PROCESS", "3")
|
||||||
|
|
||||||
|
stop := time.Now().Add(time.Second)
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
go func(i int) {
|
||||||
|
r := rand.New(rand.NewSource(int64(i)))
|
||||||
|
for time.Now().Before(stop) {
|
||||||
|
r.Uint64()
|
||||||
|
}
|
||||||
|
}(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
|
argv := []string{os.Args[0], "-test.run=TestExecHelper"}
|
||||||
|
syscall.Exec(os.Args[0], argv, os.Environ())
|
||||||
|
|
||||||
|
t.Error("syscall.Exec returned")
|
||||||
|
}
|
||||||
|
|
|
@ -325,10 +325,27 @@ func LoadLocationFromTZData(name string, data []byte) (*Location, error) {
|
||||||
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
|
if tx[i].when <= sec && (i+1 == len(tx) || sec < tx[i+1].when) {
|
||||||
l.cacheStart = tx[i].when
|
l.cacheStart = tx[i].when
|
||||||
l.cacheEnd = omega
|
l.cacheEnd = omega
|
||||||
|
zoneIdx := tx[i].index
|
||||||
if i+1 < len(tx) {
|
if i+1 < len(tx) {
|
||||||
l.cacheEnd = tx[i+1].when
|
l.cacheEnd = tx[i+1].when
|
||||||
|
} else if l.extend != "" {
|
||||||
|
// If we're at the end of the known zone transitions,
|
||||||
|
// try the extend string.
|
||||||
|
if name, _, estart, eend, ok := tzset(l.extend, l.cacheEnd, sec); ok {
|
||||||
|
l.cacheStart = estart
|
||||||
|
l.cacheEnd = eend
|
||||||
|
// Find the zone that is returned by tzset,
|
||||||
|
// the last transition is not always the correct zone.
|
||||||
|
for i, z := range l.zone {
|
||||||
|
if z.name == name {
|
||||||
|
zoneIdx = uint8(i)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
l.cacheZone = &l.zone[tx[i].index]
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.cacheZone = &l.zone[zoneIdx]
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,25 @@ func TestMalformedTZData(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadLocationFromTZDataSlim(t *testing.T) {
|
||||||
|
// A 2020b slim tzdata for Europe/Berlin
|
||||||
|
tzData := "TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\f\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9cٮ\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\tq\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xffͩ\x17\x90\xff\xff\xff\xff\u03a2C\x10\xff\xff\xff\xffϒ4\x10\xff\xff\xff\xffЂ%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xffѶ\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xffҡO\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xffըs\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\t\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13ܐ\x00\x00\x00\x00\x17\x03͐\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18㯐\x00\x00\x00\x00\x19Ӡ\x90\x00\x00\x00\x00\x1aÑ\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\\c\x10\x00\x00\x00\x00\"LT\x10\x00\x00\x00\x00#<E\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%\x1c'\x10\x00\x00\x00\x00&\f\x18\x10\x00\x00\x00\x00'\x05C\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00(\xe5%\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xc5\a\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xa4\xe9\x90\x00\x00\x00\x00-\x94ڐ\x00\x00\x00\x00.\x84ː\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000d\xad\x90\x00\x00\x00\x001]\xd9\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\f\x88\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\t\x00\x00*0\x01\rLMT\x00CEST\x00CET\x00CEMT\x00\nCET-1CEST,M3.5.0,M10.5.0/3\n"
|
||||||
|
|
||||||
|
reference, err := time.LoadLocationFromTZData("Europe/Berlin", []byte(tzData))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d := time.Date(2020, time.October, 29, 15, 30, 0, 0, reference)
|
||||||
|
tzName, tzOffset := d.Zone()
|
||||||
|
if want := "CET"; tzName != want {
|
||||||
|
t.Errorf("Zone name == %s, want %s", tzName, want)
|
||||||
|
}
|
||||||
|
if want := 3600; tzOffset != want {
|
||||||
|
t.Errorf("Zone offset == %d, want %d", tzOffset, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTzset(t *testing.T) {
|
func TestTzset(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
inStr string
|
inStr string
|
||||||
|
|
Loading…
Reference in New Issue