blob: c64d2994a901303463fc4ceb86831272355977bf [file] [log] [blame] [edit]
// Copyright 2019 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 faketime
// +build !windows
// Faketime isn't currently supported on Windows. This would require:
//
// 1. Shadowing time_now, which is implemented in assembly on Windows.
// Since that's exported directly to the time package from runtime
// assembly, this would involve moving it from sys_windows_*.s into
// its own assembly files build-tagged with !faketime and using the
// implementation of time_now from timestub.go in faketime mode.
//
// 2. Modifying syscall.Write to call syscall.faketimeWrite,
// translating the Stdout and Stderr handles into FDs 1 and 2.
// (See CL 192739 PS 3.)
package runtime
import "unsafe"
// faketime is the simulated time in nanoseconds since 1970 for the
// playground.
var faketime int64 = 1257894000000000000
var faketimeState struct {
lock mutex
// lastfaketime is the last faketime value written to fd 1 or 2.
lastfaketime int64
// lastfd is the fd to which lastfaketime was written.
//
// Subsequent writes to the same fd may use the same
// timestamp, but the timestamp must increase if the fd
// changes.
lastfd uintptr
}
//go:nosplit
func nanotime() int64 {
return faketime
}
func walltime() (sec int64, nsec int32) {
return faketime / 1000000000, int32(faketime % 1000000000)
}
func write(fd uintptr, p unsafe.Pointer, n int32) int32 {
if !(fd == 1 || fd == 2) {
// Do an ordinary write.
return write1(fd, p, n)
}
// Write with the playback header.
// First, lock to avoid interleaving writes.
lock(&faketimeState.lock)
// If the current fd doesn't match the fd of the previous write,
// ensure that the timestamp is strictly greater. That way, we can
// recover the original order even if we read the fds separately.
t := faketimeState.lastfaketime
if fd != faketimeState.lastfd {
t++
faketimeState.lastfd = fd
}
if faketime > t {
t = faketime
}
faketimeState.lastfaketime = t
// Playback header: 0 0 P B <8-byte time> <4-byte data length> (big endian)
var buf [4 + 8 + 4]byte
buf[2] = 'P'
buf[3] = 'B'
tu := uint64(t)
buf[4] = byte(tu >> (7 * 8))
buf[5] = byte(tu >> (6 * 8))
buf[6] = byte(tu >> (5 * 8))
buf[7] = byte(tu >> (4 * 8))
buf[8] = byte(tu >> (3 * 8))
buf[9] = byte(tu >> (2 * 8))
buf[10] = byte(tu >> (1 * 8))
buf[11] = byte(tu >> (0 * 8))
nu := uint32(n)
buf[12] = byte(nu >> (3 * 8))
buf[13] = byte(nu >> (2 * 8))
buf[14] = byte(nu >> (1 * 8))
buf[15] = byte(nu >> (0 * 8))
write1(fd, unsafe.Pointer(&buf[0]), int32(len(buf)))
// Write actual data.
res := write1(fd, p, n)
unlock(&faketimeState.lock)
return res
}