97 lines
2.5 KiB
Go
97 lines
2.5 KiB
Go
// 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.
|
|
|
|
//go:build faketime && !windows
|
|
|
|
// Faketime isn't currently supported on Windows. This would require
|
|
// 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
|
|
}
|
|
|
|
//go:linkname time_now time.now
|
|
func time_now() (sec int64, nsec int32, mono int64) {
|
|
return faketime / 1e9, int32(faketime % 1e9), faketime
|
|
}
|
|
|
|
// write is like the Unix write system call.
|
|
// We have to avoid write barriers to avoid potential deadlock
|
|
// on write calls.
|
|
//go:nowritebarrierrec
|
|
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
|
|
}
|