1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build faketime && !windows
6
7// Faketime isn't currently supported on Windows. This would require
8// modifying syscall.Write to call syscall.faketimeWrite,
9// translating the Stdout and Stderr handles into FDs 1 and 2.
10// (See CL 192739 PS 3.)
11
12package runtime
13
14import "unsafe"
15
16// faketime is the simulated time in nanoseconds since 1970 for the
17// playground.
18var faketime int64 = 1257894000000000000
19
20var faketimeState struct {
21	lock mutex
22
23	// lastfaketime is the last faketime value written to fd 1 or 2.
24	lastfaketime int64
25
26	// lastfd is the fd to which lastfaketime was written.
27	//
28	// Subsequent writes to the same fd may use the same
29	// timestamp, but the timestamp must increase if the fd
30	// changes.
31	lastfd uintptr
32}
33
34//go:linkname nanotime
35//go:nosplit
36func nanotime() int64 {
37	return faketime
38}
39
40//go:linkname time_now time.now
41func time_now() (sec int64, nsec int32, mono int64) {
42	return faketime / 1e9, int32(faketime % 1e9), faketime
43}
44
45// write is like the Unix write system call.
46// We have to avoid write barriers to avoid potential deadlock
47// on write calls.
48//
49//go:nowritebarrierrec
50func write(fd uintptr, p unsafe.Pointer, n int32) int32 {
51	if !(fd == 1 || fd == 2) {
52		// Do an ordinary write.
53		return write1(fd, p, n)
54	}
55
56	// Write with the playback header.
57
58	// First, lock to avoid interleaving writes.
59	lock(&faketimeState.lock)
60
61	// If the current fd doesn't match the fd of the previous write,
62	// ensure that the timestamp is strictly greater. That way, we can
63	// recover the original order even if we read the fds separately.
64	t := faketimeState.lastfaketime
65	if fd != faketimeState.lastfd {
66		t++
67		faketimeState.lastfd = fd
68	}
69	if faketime > t {
70		t = faketime
71	}
72	faketimeState.lastfaketime = t
73
74	// Playback header: 0 0 P B <8-byte time> <4-byte data length> (big endian)
75	var buf [4 + 8 + 4]byte
76	buf[2] = 'P'
77	buf[3] = 'B'
78	tu := uint64(t)
79	buf[4] = byte(tu >> (7 * 8))
80	buf[5] = byte(tu >> (6 * 8))
81	buf[6] = byte(tu >> (5 * 8))
82	buf[7] = byte(tu >> (4 * 8))
83	buf[8] = byte(tu >> (3 * 8))
84	buf[9] = byte(tu >> (2 * 8))
85	buf[10] = byte(tu >> (1 * 8))
86	buf[11] = byte(tu >> (0 * 8))
87	nu := uint32(n)
88	buf[12] = byte(nu >> (3 * 8))
89	buf[13] = byte(nu >> (2 * 8))
90	buf[14] = byte(nu >> (1 * 8))
91	buf[15] = byte(nu >> (0 * 8))
92	write1(fd, unsafe.Pointer(&buf[0]), int32(len(buf)))
93
94	// Write actual data.
95	res := write1(fd, p, n)
96
97	unlock(&faketimeState.lock)
98	return res
99}
100