type Time struct { // wall and ext encode the wall time seconds, wall time nanoseconds, // and optional monotonic clock reading in nanoseconds. // // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic), // a 33-bit seconds field, and a 30-bit wall time nanoseconds field. // The nanoseconds field is in the range [0, 999999999]. // If the hasMonotonic bit is 0, then the 33-bit field must be zero // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext. // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit // unsigned wall seconds since Jan 1 year 1885, and ext holds a // signed 64-bit monotonic clock reading, nanoseconds since process start.
// loc specifies the Location that should be used to // determine the minute, hour, month, day, and year // that correspond to this Time. // The nil location means UTC. // All UTC times are represented with loc==nil, never loc==&utcLoc. loc *Location // 时区,在此先不讨论 }
// Monotonic times are reported as offsets from startNano. // We initialize startNano to runtimeNano() - 1 so that on systems where // monotonic time resolution is fairly low (e.g. Windows 2008 // which appears to have a default resolution of 15ms), // we avoid ever reporting a monotonic time of 0. // (Callers may want to use 0 as "time not set".)
//go:nosplit //go:cgo_unsafe_args funcnanotime1()int64 { var r struct { t int64// raw timer numer, denom uint32// conversion factors. nanoseconds = t * numer / denom. } libcCall(unsafe.Pointer(funcPC(nanotime_trampoline)), unsafe.Pointer(&r)) // Note: Apple seems unconcerned about overflow here. See // https://developer.apple.com/library/content/qa/qa1398/_index.html // Note also, numer == denom == 1 is common. t := r.t if r.numer != 1 { t *= int64(r.numer) } if r.denom != 1 { t /= int64(r.denom) } return t } funcnanotime_trampoline()
//go:nosplit //go:cgo_unsafe_args funcwalltime1() (int64, int32) { var t timespec libcCall(unsafe.Pointer(funcPC(walltime_trampoline)), unsafe.Pointer(&t)) return t.tv_sec, int32(t.tv_nsec) } funcwalltime_trampoline()
// func walltime1() (sec int64, nsec int32) // non-zero frame-size means bp is saved and restored TEXT runtime·walltime1(SB),NOSPLIT,$16-12 // We don't know how much stack space the VDSO code will need, // so switch to g0. // In particular, a kernel configured with CONFIG_OPTIMIZE_INLINING=n // and hardening can use a full page of stack space in gettime_sym // due to stack probes inserted to avoid stack/heap collisions. // See issue #20427.
MOVQ SP, R12 // Save old SP; R12 unchanged by C code.
get_tls(CX) MOVQ g(CX), AX MOVQ g_m(AX), BX // BX unchanged by C code.
// Set vdsoPC and vdsoSP for SIGPROF traceback. // Save the old values on stack and restore them on exit, // so this function is reentrant. MOVQ m_vdsoPC(BX), CX MOVQ m_vdsoSP(BX), DX MOVQ CX, 0(SP) MOVQ DX, 8(SP)
CMPQ AX, m_curg(BX) // Only switch if on curg. JNE noswitch
MOVQ m_g0(BX), DX MOVQ (g_sched+gobuf_sp)(DX), SP // Set SP to g0 stack
noswitch: SUBQ $16, SP // Space for results ANDQ $~15, SP // Align for C code
MOVL $0, DI // CLOCK_REALTIME LEAQ 0(SP), SI MOVQ runtime·vdsoClockgettimeSym(SB), AX CMPQ AX, $0 JEQ fallback CALL AX ret: MOVQ 0(SP), AX // sec MOVQ 8(SP), DX // nsec MOVQ R12, SP // Restore real SP // Restore vdsoPC, vdsoSP // We don't worry about being signaled between the two stores. // If we are not in a signal handler, we'll restore vdsoSP to 0, // and no one will care about vdsoPC. If we are in a signal handler, // we cannot receive another signal. MOVQ 8(SP), CX MOVQ CX, m_vdsoSP(BX) MOVQ 0(SP), CX MOVQ CX, m_vdsoPC(BX) MOVQ AX, sec+0(FP) MOVL DX, nsec+8(FP) RET fallback: MOVQ $SYS_clock_gettime, AX SYSCALL JMP ret
// func nanotime1() int64 TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 // Switch to g0 stack. See comment above in runtime·walltime.
MOVQ SP, R12 // Save old SP; R12 unchanged by C code.
get_tls(CX) MOVQ g(CX), AX MOVQ g_m(AX), BX // BX unchanged by C code.
// Set vdsoPC and vdsoSP for SIGPROF traceback. // Save the old values on stack and restore them on exit, // so this function is reentrant. MOVQ m_vdsoPC(BX), CX MOVQ m_vdsoSP(BX), DX MOVQ CX, 0(SP) MOVQ DX, 8(SP)
CMPQ AX, m_curg(BX) // Only switch if on curg. JNE noswitch
MOVQ m_g0(BX), DX MOVQ (g_sched+gobuf_sp)(DX), SP // Set SP to g0 stack
noswitch: SUBQ $16, SP // Space for results ANDQ $~15, SP // Align for C code
MOVL $1, DI // CLOCK_MONOTONIC LEAQ 0(SP), SI MOVQ runtime·vdsoClockgettimeSym(SB), AX CMPQ AX, $0 JEQ fallback CALL AX ret: MOVQ 0(SP), AX // sec MOVQ 8(SP), DX // nsec MOVQ R12, SP // Restore real SP // Restore vdsoPC, vdsoSP // We don't worry about being signaled between the two stores. // If we are not in a signal handler, we'll restore vdsoSP to 0, // and no one will care about vdsoPC. If we are in a signal handler, // we cannot receive another signal. MOVQ 8(SP), CX MOVQ CX, m_vdsoSP(BX) MOVQ 0(SP), CX MOVQ CX, m_vdsoPC(BX) // sec is in AX, nsec in DX // return nsec in AX IMULQ $1000000000, AX ADDQ DX, AX MOVQ AX, ret+0(FP) RET fallback: MOVQ $SYS_clock_gettime, AX SYSCALL JMP ret
// Unix returns the local Time corresponding to the given Unix time, // sec seconds and nsec nanoseconds since January 1, 1970 UTC. // It is valid to pass nsec outside the range [0, 999999999]. // Not all sec values have a corresponding time value. One such // value is 1<<63-1 (the largest int64 value).
// Unix 返回与给定 Unix 时间相对应的本地时间,自 1970 年 1 月 1 日 UTC 以来的秒秒和纳秒纳秒。 // 在 [0, 999999999] 范围之外传递 nsec 是有效的。 // 并非所有秒值都有对应的时间值。 一个这样的值是 1<<63-1(最大的 int64 值)。 funcUnix(sec int64, nsec int64) Time { if nsec < 0 || nsec >= 1e9 { n := nsec / 1e9 sec += n nsec -= n * 1e9 if nsec < 0 { nsec += 1e9 sec-- } } return unixTime(sec, int32(nsec)) }
// Sub returns the duration t-u. If the result exceeds the maximum (or minimum) // value that can be stored in a Duration, the maximum (or minimum) duration // will be returned. // To compute t-d for a duration d, use t.Add(-d). func(t Time) Sub(u Time) Duration { if t.wall&u.wall&hasMonotonic != 0 { te := t.ext ue := u.ext d := Duration(te - ue) if d < 0 && te > ue { return maxDuration // t - u is positive out of range } if d > 0 && te < ue { return minDuration // t - u is negative out of range } return d } d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec()) // Check for overflow or underflow. switch { case u.Add(d).Equal(t): return d // d is correct case t.Before(u): return minDuration // t - u is negative out of range default: return maxDuration // t - u is positive out of range } }