gvisor-lx/pkg/tcpip/stdclock.go
Leadaxe 117243aa02 snapshot: sagernet/gvisor v0.0.0-20260727.0-sing-box-mod.1 + SPEC 048 guard
Обновление снапшота с v0.0.0-20250811.0 на пин, которого требует
sing-box после мержа 235 коммитов (upstream d620bbbf2 "Update gvisor to
20260727.0"). Прежний снапшот был взят 2026-08-04 ровно с той версии,
на которой тогда стоял апстрим; разрыв возник 2026-08-05 вместе с его
бампом.

За год апстрим-gvisor изменил ~14 000 строк в 292 файлах. Значимое для
нас — сетевой стек: tcp/connect.go (PMTU-discovery + исправление
начального RTT/RTO: раньше задержка ACK внутри стека завышала стартовый
таймаут на несколько RTT), tcp/snd.go, tcp/rcv.go, stack/conntrack.go,
stack/packet_buffer.go. Всего 30 файлов в TCP и 37 в stack.

Баг SPEC 048 апстрим НЕ исправил — проверено по коду новой версии:
handleConnecting по-прежнему проверяет состояние endpoint'а, но не ep.h,
а performHandshake так же зануляет h и отпускает мьютекс до Close().
Поэтому guard перенесён (12 строк) вместе со своим тестом (45 строк).

Red/green проверен на новой базе: без guard'а тест падает с той же
nil-паникой, что в полевом крашдампе; с ним зелёный.
2026-08-05 14:53:31 +03:00

113 lines
3.6 KiB
Go

// Copyright 2018 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tcpip
import (
"fmt"
"time"
)
// stdClock implements Clock with the time package.
//
// +stateify savable
type stdClock struct {
// baseTime holds the time when the clock was constructed.
//
// This value is used to calculate the monotonic time from the time package.
// As per https://golang.org/pkg/time/#hdr-Monotonic_Clocks,
//
// Operating systems provide both a “wall clock,” which is subject to
// changes for clock synchronization, and a “monotonic clock,” which is not.
// The general rule is that the wall clock is for telling time and the
// monotonic clock is for measuring time. Rather than split the API, in this
// package the Time returned by time.Now contains both a wall clock reading
// and a monotonic clock reading; later time-telling operations use the wall
// clock reading, but later time-measuring operations, specifically
// comparisons and subtractions, use the monotonic clock reading.
//
// ...
//
// If Times t and u both contain monotonic clock readings, the operations
// t.After(u), t.Before(u), t.Equal(u), and t.Sub(u) are carried out using
// the monotonic clock readings alone, ignoring the wall clock readings. If
// either t or u contains no monotonic clock reading, these operations fall
// back to using the wall clock readings.
//
// Given the above, we can safely conclude that time.Since(baseTime) will
// return monotonically increasing values if we use time.Now() to set baseTime
// at the time of clock construction.
//
// Note that time.Since(t) is shorthand for time.Now().Sub(t), as per
// https://golang.org/pkg/time/#Since.
baseTime time.Time `state:"nosave"`
// monotonicOffset is the offset applied to the calculated monotonic time.
//
// monotonicOffset is assigned after restore so that the monotonic time
// will continue from where it "left off" before saving as part of S/R.
monotonicOffset MonotonicTime
}
// NewStdClock returns an instance of a clock that uses the time package.
func NewStdClock() Clock {
return &stdClock{
baseTime: time.Now(),
}
}
var _ Clock = (*stdClock)(nil)
// Now implements Clock.Now.
func (*stdClock) Now() time.Time {
return time.Now()
}
// NowMonotonic implements Clock.NowMonotonic.
func (s *stdClock) NowMonotonic() MonotonicTime {
sinceBase := time.Since(s.baseTime)
if sinceBase < 0 {
panic(fmt.Sprintf("got negative duration = %s since base time = %s", sinceBase, s.baseTime))
}
return s.monotonicOffset.Add(sinceBase)
}
// AfterFunc implements Clock.AfterFunc.
func (*stdClock) AfterFunc(d time.Duration, f func()) Timer {
return &stdTimer{
t: time.AfterFunc(d, f),
}
}
type stdTimer struct {
t *time.Timer
}
var _ Timer = (*stdTimer)(nil)
// Stop implements Timer.Stop.
func (st *stdTimer) Stop() bool {
return st.t.Stop()
}
// Reset implements Timer.Reset.
func (st *stdTimer) Reset(d time.Duration) {
st.t.Reset(d)
}
// NewStdTimer returns a Timer implemented with the time package.
func NewStdTimer(t *time.Timer) Timer {
return &stdTimer{t: t}
}