aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-08-27 08:11:01 -0600
committerJason A. Donenfeld <Jason@zx2c4.com>2019-08-27 12:12:46 -0600
commit79bbd4dcd021fcf0393932bb908b372aafd92430 (patch)
tree4e7e8ae27ebb69d60180c037831fa249fbbeeba1
parentbuild: use goproxy when not remastering (diff)
downloadwireguard-windows-79bbd4dcd021fcf0393932bb908b372aafd92430.tar.xz
wireguard-windows-79bbd4dcd021fcf0393932bb908b372aafd92430.zip
build: backport resume monitoring for timers
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
-rw-r--r--Makefile23
-rw-r--r--build.bat4
-rw-r--r--golang-runtime-resume-timers.patch187
3 files changed, 208 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index c622fce8..67d85c6c 100644
--- a/Makefile
+++ b/Makefile
@@ -3,16 +3,31 @@ export CGO_ENABLED := 1
export CGO_CFLAGS := -O3 -Wall -Wno-unused-function -Wno-switch -std=gnu11 -DWINVER=0x0601
export CGO_LDFLAGS := -Wl,--major-os-version=6 -Wl,--minor-os-version=1 -Wl,--major-subsystem-version=6 -Wl,--minor-subsystem-version=1 -Wl,--tsaware
export GOOS := windows
+OLD_GOROOT := $(GOROOT)
+export GOROOT := $(CURDIR)/.deps/goroot
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
-SOURCE_FILES := $(call rwildcard,,*.go *.c *.h)
+SOURCE_FILES := $(call rwildcard,,*.go *.c *.h) .deps/prepared
RESOURCE_FILES := resources.rc version.h manifest.xml $(patsubst %.svg,%.ico,$(wildcard ui/icon/*.svg))
+REQUIRED_GO_VERSION := go1.13beta1
+ifneq ($(shell go version 2>/dev/null | cut -d ' ' -f 3),$(REQUIRED_GO_VERSION))
+$(error $(REQUIRED_GO_VERSION) is required)
+endif
+
DEPLOYMENT_HOST ?= winvm
DEPLOYMENT_PATH ?= Desktop
all: amd64/wireguard.exe x86/wireguard.exe
+.deps/prepared: export GOROOT := $(OLD_GOROOT)
+.deps/prepared: $(wildcard golang-*.patch)
+ rm -rf .deps && mkdir -p .deps
+ if ! rsync --exclude=pkg/obj/go-build/trim.txt -aq $$(go env GOROOT)/ .deps/goroot; then chmod -R +w .deps/goroot; exit 1; fi
+ chmod -R +w .deps/goroot
+ cat $^ | patch -f -N -r- -p1 -d .deps/goroot
+ touch $@
+
%.ico: %.svg
convert -background none $< -define icon:auto-resize="256,128,96,64,48,32,16" $@
@@ -22,18 +37,14 @@ resources_amd64.syso: $(RESOURCE_FILES)
resources_386.syso: $(RESOURCE_FILES)
i686-w64-mingw32-windres -i $< -o $@ -O coff
-VERSIONCHECK := @[ "$$(go version | cut -d ' ' -f 3)" == go1.13beta1 ]
-
amd64/wireguard.exe: export CC := x86_64-w64-mingw32-gcc
amd64/wireguard.exe: export GOARCH := amd64
amd64/wireguard.exe: resources_amd64.syso $(SOURCE_FILES)
- $(VERSIONCHECK)
go build $(GOFLAGS) -o $@
x86/wireguard.exe: export CC := i686-w64-mingw32-gcc
x86/wireguard.exe: export GOARCH := 386
x86/wireguard.exe: resources_386.syso $(SOURCE_FILES)
- $(VERSIONCHECK)
go build $(GOFLAGS) -o $@
remaster: export CC := x86_64-w64-mingw32-gcc
@@ -54,6 +65,6 @@ deploy: amd64/wireguard.exe
scp $< $(DEPLOYMENT_HOST):$(DEPLOYMENT_PATH)
clean:
- rm -rf *.syso ui/icon/*.ico x86/ amd64/ .deps
+ rm -rf *.syso ui/icon/*.ico x86/ amd64/ .deps/
.PHONY: deploy clean fmt remaster all
diff --git a/build.bat b/build.bat
index 3361b28b..3c1cba66 100644
--- a/build.bat
+++ b/build.bat
@@ -23,6 +23,10 @@ if exist .deps\prepared goto :render
rem Mirror of https://sourceforge.net/projects/ezwinports/files/make-4.2.1-without-guile-w32-bin.zip
call :download make.zip https://download.wireguard.com/windows-toolchain/distfiles/make-4.2.1-without-guile-w32-bin.zip 30641be9602712be76212b99df7209f4f8f518ba764cf564262bc9d6e4047cc7 "--strip-components 1 bin" || goto :error
call :download wireguard-tools.zip https://git.zx2c4.com/WireGuard/snapshot/WireGuard-0.0.20190702.zip 2fb45e145f36e4e965f8acb48061603a2192c6729266cbcd9f9669024e433588 "--exclude wg-quick --strip-components 1" || goto :error
+ rem Mirror of https://sourceforge.net/projects/gnuwin32/files/patch/2.5.9-7/patch-2.5.9-7-bin.zip with fixed manifest
+ call :download patch.zip https://download.wireguard.com/windows-toolchain/distfiles/patch-2.5.9-7-bin-fixed-manifest.zip 25977006ca9713f2662a5d0a2ed3a5a138225b8be3757035bd7da9dcf985d0a1 "--strip-components 1 bin" || goto :error
+ echo [+] Patching go
+ for %%a in ("..\golang-*.patch") do .\patch.exe -f -N -r- -d go -p1 --binary < "%%a" || goto :error
copy /y NUL prepared > NUL || goto :error
cd .. || goto :error
diff --git a/golang-runtime-resume-timers.patch b/golang-runtime-resume-timers.patch
new file mode 100644
index 00000000..17e09bb3
--- /dev/null
+++ b/golang-runtime-resume-timers.patch
@@ -0,0 +1,187 @@
+From e7384a38af94ff5e7e748f1424d766e1d3316f8d Mon Sep 17 00:00:00 2001
+From: Jason A. Donenfeld <Jason@zx2c4.com>
+Date: Tue, 27 Aug 2019 06:46:16 -0600
+Subject: [PATCH] runtime: monitor for suspend/resume to kick timeouts
+
+Starting in Windows 8, the wait functions don't take into account
+suspend time, even though the monotonic counters do. This results in
+timer buckets stalling on resume. Therefore, this commit makes it so
+that on resume, we return from the wait functions and recalculate the
+amount of time left to wait.
+
+Fixes: #31528
+
+Change-Id: I0db02cc72188cb620954e87a0180e0a3c83f4a56
+---
+
+diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
+index 074ae0f..6cc9670 100644
+--- a/src/runtime/os_windows.go
++++ b/src/runtime/os_windows.go
+@@ -49,6 +49,7 @@
+ //go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._VirtualQuery VirtualQuery%3 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
++//go:cgo_import_dynamic runtime._WaitForMultipleObjects WaitForMultipleObjects%4 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
+ //go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
+
+@@ -96,6 +97,7 @@
+ _VirtualFree,
+ _VirtualQuery,
+ _WaitForSingleObject,
++ _WaitForMultipleObjects,
+ _WriteConsoleW,
+ _WriteFile,
+ _ stdFunction
+@@ -139,7 +141,8 @@
+ func ctrlhandler()
+
+ type mOS struct {
+- waitsema uintptr // semaphore for parking on locks
++ waitsema uintptr // semaphore for parking on locks
++ resumesema uintptr // semaphore to indicate suspend/resume
+ }
+
+ //go:linkname os_sigpipe os.sigpipe
+@@ -258,6 +261,34 @@
+ }
+ }
+
++func monitorSuspendResume() {
++ powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000"))
++ if powrprof == 0 {
++ return // Running on Windows 7, where we don't need it anyway.
++ }
++ powerRegisterSuspendResumeNotification := windowsFindfunc(powrprof, []byte("PowerRegisterSuspendResumeNotification\000"))
++ if powerRegisterSuspendResumeNotification == nil {
++ return // Running on Windows 7, where we don't need it anyway.
++ }
++ var fn interface{} = func(context uintptr, changeType uint32, setting uintptr) uintptr {
++ lock(&allglock)
++ for _, gp := range allgs {
++ if gp.m != nil && gp.m.resumesema != 0 {
++ stdcall1(_SetEvent, gp.m.resumesema)
++ }
++ }
++ unlock(&allglock)
++ return 0
++ }
++ var handle uintptr
++ callback := compileCallback(*efaceOf(&fn), true)
++ if stdcall3(powerRegisterSuspendResumeNotification, 2,
++ uintptr(unsafe.Pointer(&[2]uintptr{callback, 0})),
++ uintptr(unsafe.Pointer(&handle))) != 0 {
++ throw("PowerRegisterSuspendResumeNotification failure")
++ }
++}
++
+ //go:nosplit
+ func getLoadLibrary() uintptr {
+ return uintptr(unsafe.Pointer(_LoadLibraryW))
+@@ -488,6 +519,10 @@
+ }
+
+ stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
++
++ // We call this all the way here, late in init, so that malloc works
++ // for the callback function this generates.
++ monitorSuspendResume()
+ }
+
+ // exiting is set to non-zero when the process is exiting.
+@@ -606,21 +641,34 @@
+ _WAIT_FAILED = 0xFFFFFFFF
+ )
+
+- // store ms in ns to save stack space
++ var result uintptr
++ var elapsed, start int64
++retry:
+ if ns < 0 {
+- ns = _INFINITE
++ result = stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(_INFINITE))
+ } else {
+- ns = int64(timediv(ns, 1000000, nil))
+- if ns == 0 {
+- ns = 1
++ if start == 0 {
++ start = nanotime()
+ }
++ ms := int64(timediv(ns-elapsed, 1000000, nil))
++ if ms == 0 {
++ ms = 1
++ }
++ result = stdcall4(_WaitForMultipleObjects, 2,
++ uintptr(unsafe.Pointer(&[2]uintptr{getg().m.waitsema, getg().m.resumesema})),
++ 0, uintptr(ms))
+ }
+-
+- result := stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns))
+ switch result {
+ case _WAIT_OBJECT_0: //signaled
+ return 0
+
++ case _WAIT_OBJECT_0 + 1: //system resume
++ elapsed = nanotime() - start
++ if elapsed >= ns {
++ return -1
++ }
++ goto retry
++
+ case _WAIT_TIMEOUT:
+ return -1
+
+@@ -667,6 +715,15 @@
+ throw("runtime.semacreate")
+ })
+ }
++ mp.resumesema = stdcall4(_CreateEventA, 0, 0, 0, 0)
++ if mp.resumesema == 0 {
++ systemstack(func() {
++ print("runtime: createevent failed; errno=", getlasterror(), "\n")
++ throw("runtime.semacreate")
++ })
++ stdcall1(_CloseHandle, mp.waitsema)
++ mp.waitsema = 0
++ }
+ }
+
+ // May run with m.p==nil, so write barriers are not allowed. This
+diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
+index 722a73d..0e2fcfb 100644
+--- a/src/runtime/syscall_windows.go
++++ b/src/runtime/syscall_windows.go
+@@ -74,16 +74,18 @@
+ argsize += uintptrSize
+ }
+
+- lock(&cbs.lock)
+- defer unlock(&cbs.lock)
++ lock(&cbs.lock) // We don't unlock this in a defer because this is used from the system stack.
+
+ n := cbs.n
+ for i := 0; i < n; i++ {
+ if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack {
+- return callbackasmAddr(i)
++ r := callbackasmAddr(i)
++ unlock(&cbs.lock)
++ return r
+ }
+ }
+ if n >= cb_max {
++ unlock(&cbs.lock)
+ throw("too many callback functions")
+ }
+
+@@ -99,7 +101,9 @@
+ cbs.ctxt[n] = c
+ cbs.n++
+
+- return callbackasmAddr(n)
++ r := callbackasmAddr(n)
++ unlock(&cbs.lock)
++ return r
+ }
+
+ const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800