1// Copyright 2021 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 windows
6
7package testing
8
9import (
10	"errors"
11	"internal/syscall/windows"
12	"math/bits"
13	"syscall"
14	"time"
15)
16
17// isWindowsRetryable reports whether err is a Windows error code
18// that may be fixed by retrying a failed filesystem operation.
19func isWindowsRetryable(err error) bool {
20	for {
21		unwrapped := errors.Unwrap(err)
22		if unwrapped == nil {
23			break
24		}
25		err = unwrapped
26	}
27	if err == syscall.ERROR_ACCESS_DENIED {
28		return true // Observed in https://go.dev/issue/50051.
29	}
30	if err == windows.ERROR_SHARING_VIOLATION {
31		return true // Observed in https://go.dev/issue/51442.
32	}
33	return false
34}
35
36// highPrecisionTime represents a single point in time with query performance counter.
37// time.Time on Windows has low system granularity, which is not suitable for
38// measuring short time intervals.
39//
40// TODO: If Windows runtime implements high resolution timing then highPrecisionTime
41// can be removed.
42type highPrecisionTime struct {
43	now int64
44}
45
46// highPrecisionTimeNow returns high precision time for benchmarking.
47func highPrecisionTimeNow() highPrecisionTime {
48	var t highPrecisionTime
49	// This should always succeed for Windows XP and above.
50	t.now = windows.QueryPerformanceCounter()
51	return t
52}
53
54func (a highPrecisionTime) sub(b highPrecisionTime) time.Duration {
55	delta := a.now - b.now
56
57	if queryPerformanceFrequency == 0 {
58		queryPerformanceFrequency = windows.QueryPerformanceFrequency()
59	}
60	hi, lo := bits.Mul64(uint64(delta), uint64(time.Second)/uint64(time.Nanosecond))
61	quo, _ := bits.Div64(hi, lo, uint64(queryPerformanceFrequency))
62	return time.Duration(quo)
63}
64
65var queryPerformanceFrequency int64
66
67// highPrecisionTimeSince returns duration since a.
68func highPrecisionTimeSince(a highPrecisionTime) time.Duration {
69	return highPrecisionTimeNow().sub(a)
70}
71