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