]> Cypherpunks repositories - gostls13.git/commitdiff
Revert "runtime: remove slow time compatibility hacks for wine"
authorDaniel Martí <mvdan@mvdan.cc>
Mon, 2 Sep 2019 14:34:20 +0000 (14:34 +0000)
committerDaniel Martí <mvdan@mvdan.cc>
Mon, 2 Sep 2019 21:46:03 +0000 (21:46 +0000)
This reverts CL 191759.

Reason for revert: broke most Go programs using the time package on Wine,
including on 4.15, the latest stable version. Only wine-staging (with
experimental patches) contains an upstream fix we could rely on.

Change-Id: Ic8ba126022e54f412174042fbb9abed82d5eb318
Reviewed-on: https://go-review.googlesource.com/c/go/+/192622
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
src/runtime/os_windows.go
src/runtime/sys_windows_386.s
src/runtime/sys_windows_amd64.s
src/runtime/sys_windows_arm.s

index 2a2b5fa122c92d4c891a71e1c7f83984307476e0..cd9e98914c54c5e7097e07330d34fc9e1e39bede 100644 (file)
@@ -76,10 +76,12 @@ var (
        _GetStdHandle,
        _GetSystemDirectoryA,
        _GetSystemInfo,
+       _GetSystemTimeAsFileTime,
        _GetThreadContext,
        _LoadLibraryW,
        _LoadLibraryA,
        _QueryPerformanceCounter,
+       _QueryPerformanceFrequency,
        _ResumeThread,
        _SetConsoleCtrlHandler,
        _SetErrorMode,
@@ -252,6 +254,11 @@ func loadOptionalSyscalls() {
        if _WSAGetOverlappedResult == nil {
                throw("WSAGetOverlappedResult not found")
        }
+
+       if windowsFindfunc(n32, []byte("wine_get_version\000")) != nil {
+               // running on Wine
+               initWine(k32)
+       }
 }
 
 func monitorSuspendResume() {
@@ -411,6 +418,77 @@ func osinit() {
 
 func nanotime() int64
 
+// useQPCTime controls whether time.now and nanotime use QueryPerformanceCounter.
+// This is only set to 1 when running under Wine.
+var useQPCTime uint8
+
+var qpcStartCounter int64
+var qpcMultiplier int64
+
+//go:nosplit
+func nanotimeQPC() int64 {
+       var counter int64 = 0
+       stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter)))
+
+       // returns number of nanoseconds
+       return (counter - qpcStartCounter) * qpcMultiplier
+}
+
+//go:nosplit
+func nowQPC() (sec int64, nsec int32, mono int64) {
+       var ft int64
+       stdcall1(_GetSystemTimeAsFileTime, uintptr(unsafe.Pointer(&ft)))
+
+       t := (ft - 116444736000000000) * 100
+
+       sec = t / 1000000000
+       nsec = int32(t - sec*1000000000)
+
+       mono = nanotimeQPC()
+       return
+}
+
+func initWine(k32 uintptr) {
+       _GetSystemTimeAsFileTime = windowsFindfunc(k32, []byte("GetSystemTimeAsFileTime\000"))
+       if _GetSystemTimeAsFileTime == nil {
+               throw("could not find GetSystemTimeAsFileTime() syscall")
+       }
+
+       _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000"))
+       _QueryPerformanceFrequency = windowsFindfunc(k32, []byte("QueryPerformanceFrequency\000"))
+       if _QueryPerformanceCounter == nil || _QueryPerformanceFrequency == nil {
+               throw("could not find QPC syscalls")
+       }
+
+       // We can not simply fallback to GetSystemTimeAsFileTime() syscall, since its time is not monotonic,
+       // instead we use QueryPerformanceCounter family of syscalls to implement monotonic timer
+       // https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
+
+       var tmp int64
+       stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&tmp)))
+       if tmp == 0 {
+               throw("QueryPerformanceFrequency syscall returned zero, running on unsupported hardware")
+       }
+
+       // This should not overflow, it is a number of ticks of the performance counter per second,
+       // its resolution is at most 10 per usecond (on Wine, even smaller on real hardware), so it will be at most 10 millions here,
+       // panic if overflows.
+       if tmp > (1<<31 - 1) {
+               throw("QueryPerformanceFrequency overflow 32 bit divider, check nosplit discussion to proceed")
+       }
+       qpcFrequency := int32(tmp)
+       stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&qpcStartCounter)))
+
+       // Since we are supposed to run this time calls only on Wine, it does not lose precision,
+       // since Wine's timer is kind of emulated at 10 Mhz, so it will be a nice round multiplier of 100
+       // but for general purpose system (like 3.3 Mhz timer on i7) it will not be very precise.
+       // We have to do it this way (or similar), since multiplying QPC counter by 100 millions overflows
+       // int64 and resulted time will always be invalid.
+       qpcMultiplier = int64(timediv(1000000000, qpcFrequency, nil))
+
+       useQPCTime = 1
+}
+
 //go:nosplit
 func getRandomData(r []byte) {
        n := 0
index b8a8ad865bb0a14d9f390d64b6f2f62bf885c99c..761da8eaef1a4d8313bd9e8b43ba91bff7f91ddb 100644 (file)
@@ -445,6 +445,8 @@ TEXT runtime·switchtothread(SB),NOSPLIT,$0
 #define time_hi2 8
 
 TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+       CMPB    runtime·useQPCTime(SB), $0
+       JNE     useQPC
 loop:
        MOVL    (_INTERRUPT_TIME+time_hi1), AX
        MOVL    (_INTERRUPT_TIME+time_lo), CX
@@ -461,8 +463,13 @@ loop:
        MOVL    AX, ret_lo+0(FP)
        MOVL    DX, ret_hi+4(FP)
        RET
+useQPC:
+       JMP     runtime·nanotimeQPC(SB)
+       RET
 
 TEXT time·now(SB),NOSPLIT,$0-20
+       CMPB    runtime·useQPCTime(SB), $0
+       JNE     useQPC
 loop:
        MOVL    (_INTERRUPT_TIME+time_hi1), AX
        MOVL    (_INTERRUPT_TIME+time_lo), CX
@@ -531,3 +538,6 @@ wall:
        MOVL    AX, sec+0(FP)
        MOVL    DX, sec+4(FP)
        RET
+useQPC:
+       JMP     runtime·nowQPC(SB)
+       RET
index d62fd411b1214c3da136e36c58ae6eca0cc37d31..2aea8eaff7ec15eb93d84fe39ebe2701a4c48b06 100644 (file)
@@ -474,6 +474,8 @@ TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
 #define time_hi2 8
 
 TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+       CMPB    runtime·useQPCTime(SB), $0
+       JNE     useQPC
        MOVQ    $_INTERRUPT_TIME, DI
 loop:
        MOVL    time_hi1(DI), AX
@@ -486,8 +488,13 @@ loop:
        IMULQ   $100, CX
        MOVQ    CX, ret+0(FP)
        RET
+useQPC:
+       JMP     runtime·nanotimeQPC(SB)
+       RET
 
 TEXT time·now(SB),NOSPLIT,$0-24
+       CMPB    runtime·useQPCTime(SB), $0
+       JNE     useQPC
        MOVQ    $_INTERRUPT_TIME, DI
 loop:
        MOVL    time_hi1(DI), AX
@@ -527,3 +534,6 @@ wall:
        SUBQ    DX, CX
        MOVL    CX, nsec+8(FP)
        RET
+useQPC:
+       JMP     runtime·nowQPC(SB)
+       RET
index 294e217e6c6406e5d6f3184a549c974642badcf5..8f8af0a4f7ec5f668441a2817807043f03fd59e7 100644 (file)
@@ -496,6 +496,10 @@ TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
 #define time_hi2 8
 
 TEXT runtime·nanotime(SB),NOSPLIT,$0-8
+       MOVW    $0, R0
+       MOVB    runtime·useQPCTime(SB), R0
+       CMP     $0, R0
+       BNE     useQPC
        MOVW    $_INTERRUPT_TIME, R3
 loop:
        MOVW    time_hi1(R3), R1
@@ -513,8 +517,15 @@ loop:
        MOVW    R3, ret_lo+0(FP)
        MOVW    R4, ret_hi+4(FP)
        RET
+useQPC:
+       B       runtime·nanotimeQPC(SB)                // tail call
+       RET
 
 TEXT time·now(SB),NOSPLIT,$0-20
+       MOVW    $0, R0
+       MOVB    runtime·useQPCTime(SB), R0
+       CMP     $0, R0
+       BNE     useQPC
        MOVW    $_INTERRUPT_TIME, R3
 loop:
        MOVW    time_hi1(R3), R1
@@ -583,6 +594,9 @@ wall:
        MOVW    R7,sec_hi+4(FP)
        MOVW    R1,nsec+8(FP)
        RET
+useQPC:
+       B       runtime·nanotimeQPC(SB)                // tail call
+       RET
 
 // save_g saves the g register (R10) into thread local memory
 // so that we can call externally compiled