From 7ae981daefd7d1fc26e3b41d3089e352380d19d7 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 9 Nov 2020 10:58:18 +0100 Subject: build: add linker patches for llvm-rc Signed-off-by: Jason A. Donenfeld --- ...d-link-recognize-arm-header-of-PE-objects.patch | 32 ++ ...al-with-ADDR32NB-relocations-the-same-way.patch | 31 ++ ...cmd-link-ignore-SEH-marking-on-PE-objects.patch | 47 +++ ...-do-not-mark-resource-section-as-writable.patch | 30 ++ ...cmd-link-handle-grouped-resource-sections.patch | 317 ++++++++++++++++ ...-CreateWaitableTimerEx-to-implement-uslee.patch | 406 +++++++++++++++++++++ ...ase-branch.go1.15-runtime-detect-services.patch | 135 +++++++ ...me-do-not-explicitly-exit-on-ctrl-handler.patch | 49 +++ go-patches/highres-timer.patch | 395 -------------------- go-patches/no-ctrlc-handler.patch | 184 ---------- 10 files changed, 1047 insertions(+), 579 deletions(-) create mode 100644 go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch create mode 100644 go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch create mode 100644 go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch create mode 100644 go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch create mode 100644 go-patches/0005-cmd-link-handle-grouped-resource-sections.patch create mode 100644 go-patches/0006-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch create mode 100644 go-patches/0007-Revert-release-branch.go1.15-runtime-detect-services.patch create mode 100644 go-patches/0008-runtime-do-not-explicitly-exit-on-ctrl-handler.patch delete mode 100644 go-patches/highres-timer.patch delete mode 100644 go-patches/no-ctrlc-handler.patch (limited to 'go-patches') diff --git a/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch b/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch new file mode 100644 index 00000000..3a310c5d --- /dev/null +++ b/go-patches/0001-cmd-link-recognize-arm-header-of-PE-objects.patch @@ -0,0 +1,32 @@ +From 2b3975549a043f66ad1580b0330c2bf47916f042 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 8 Nov 2020 02:48:09 +0100 +Subject: [PATCH 1/8] cmd/link: recognize arm header of PE objects + +The linker recognizes headers for 386 and amd64 PE objects, but not arm +objects. This is easily overlooked, since its the same as the 386 header +value, except the two nibbles of the first word are swapped. This commit +simply adds the check for this. Without it, .syso objects are rejected, +which means Windows binaries can't have resources built into them. + +Change-Id: I210411d978504c1a9540e23abc5a180e24f159ad +--- + src/cmd/link/internal/ld/lib.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go +index 0366bc7a6f..f98668a7dc 100644 +--- a/src/cmd/link/internal/ld/lib.go ++++ b/src/cmd/link/internal/ld/lib.go +@@ -1893,7 +1893,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, + return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file) + } + +- if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 { ++ if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 || c1 == 0xc4 && c2 == 0x01 { + ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { + textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.Syms.IncVersion(), f, pkg, length, pn) + if err != nil { +-- +2.29.1 + diff --git a/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch b/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch new file mode 100644 index 00000000..10137735 --- /dev/null +++ b/go-patches/0002-cmd-link-deal-with-ADDR32NB-relocations-the-same-way.patch @@ -0,0 +1,31 @@ +From b82dc55e45ee47e0df9604593c34d41654db45c8 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 8 Nov 2020 03:09:42 +0100 +Subject: [PATCH 2/8] cmd/link: deal with ADDR32NB relocations the same way as + ADDR32 on arm + +As far as I can tell, the addend is the same for both of these, and in +this context we don't really care about setting or unsetting the thumb +selection bit, so just treat these the same way. + +Change-Id: I3756c027239f77778c32b317733df9ac92272580 +--- + src/cmd/link/internal/loadpe/ldpe.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go +index cf76741f43..5839a6a5f2 100644 +--- a/src/cmd/link/internal/loadpe/ldpe.go ++++ b/src/cmd/link/internal/loadpe/ldpe.go +@@ -308,7 +308,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + + rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:]))) + +- case IMAGE_REL_ARM_ADDR32: ++ case IMAGE_REL_ARM_ADDR32, IMAGE_REL_ARM_ADDR32NB: + rType = objabi.R_ADDR + + rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:]))) +-- +2.29.1 + diff --git a/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch b/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch new file mode 100644 index 00000000..34bd75fb --- /dev/null +++ b/go-patches/0003-cmd-link-ignore-SEH-marking-on-PE-objects.patch @@ -0,0 +1,47 @@ +From b3b6bbb7094e9d1f8c73a13bdf2461dea5072265 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 8 Nov 2020 03:20:36 +0100 +Subject: [PATCH 3/8] cmd/link: ignore SEH marking on PE objects + +Microsoft's linker looks at whether all input objects have an empty +section called @feat.00. If all of them do, then it enables SEH; +otherwise it doesn't enable that feature. So, since around the Windows +XP SP2 era, most tools that make PE objects just tack on that section, +so that it won't gimp Microsoft's linker logic. Go doesn't support SEH, +so in theory, none of this really matters to us. But actually, if the +linker tries to ingest an object with @feat.00 -- which are produced by +LLVM's resource compiler, for example -- it chokes because of the +IMAGE_SYM_ABSOLUTE section that it doesn't know how to deal with. Since +@feat.00 is just a marking anyway, skip IMAGE_SYM_ABSOLUTE sections that +are called @feat.00. + +Change-Id: I1d7bfcf6001186c53e2c487c5ac251ca65efefee +--- + src/cmd/link/internal/loadpe/ldpe.go | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go +index 5839a6a5f2..b60b84ce9f 100644 +--- a/src/cmd/link/internal/loadpe/ldpe.go ++++ b/src/cmd/link/internal/loadpe/ldpe.go +@@ -6,6 +6,7 @@ + package loadpe + + import ( ++ "bytes" + "cmd/internal/bio" + "cmd/internal/objabi" + "cmd/internal/sys" +@@ -359,6 +360,9 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + if pesym.SectionNumber == IMAGE_SYM_DEBUG { + continue + } ++ if pesym.SectionNumber == IMAGE_SYM_ABSOLUTE && bytes.Equal(pesym.Name[:], []byte("@feat.00")) { ++ continue ++ } + var sect *pe.Section + if pesym.SectionNumber > 0 { + sect = f.Sections[pesym.SectionNumber-1] +-- +2.29.1 + diff --git a/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch b/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch new file mode 100644 index 00000000..7898b32a --- /dev/null +++ b/go-patches/0004-cmd-link-do-not-mark-resource-section-as-writable.patch @@ -0,0 +1,30 @@ +From 3d9d47826907f8836cf4f364e45b8e2580dbc470 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 8 Nov 2020 11:11:27 +0100 +Subject: [PATCH 4/8] cmd/link: do not mark resource section as writable + +Resources are immutable, and all other linkers set this section to be +read-only and not read-write. Fix this oversight by rmoving the writable +flag. + +Change-Id: Ib441bde6620be2000f1685df1ea7bfaebdbe7860 +--- + src/cmd/link/internal/ld/pe.go | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go +index c9cb25dbe5..ec5b6d5f52 100644 +--- a/src/cmd/link/internal/ld/pe.go ++++ b/src/cmd/link/internal/ld/pe.go +@@ -1482,7 +1482,7 @@ func addpersrc(ctxt *Link) { + data := rsrc.P + size := len(data) + h := pefile.addSection(".rsrc", size, size) +- h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA ++ h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA + h.checkOffset(ctxt.Out.Offset()) + + // relocation +-- +2.29.1 + diff --git a/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch b/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch new file mode 100644 index 00000000..0d57392f --- /dev/null +++ b/go-patches/0005-cmd-link-handle-grouped-resource-sections.patch @@ -0,0 +1,317 @@ +From 98ed6f945dbc81a238d079353cab576941f7bb79 Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Sun, 8 Nov 2020 11:57:42 +0100 +Subject: [PATCH 5/8] cmd/link: handle grouped resource sections + +The Go PE linker does not support enough generalized PE logic to +properly handle .rsrc sections gracefully. Instead a few things are +special cased for these. The linker also does not support PE's "grouped +sections" features, in which input objects have several named sections +that are sorted, merged, and renamed in the output file. In the past, +more sophisticated support for resources or for PE features like grouped +sections have not been necessary, as Go's own object formats are pretty +vanilla, and GNU binutils also produces pretty vanilla objects where all +sections are already merged. + +However, GNU binutils is lagging with arm support, and here LLVM has +picked up the slack. In particular, LLVM has its own rc/cvtres combo, +which are glued together in mingw LLVM distributions as windres, a +command line compatible tool with binutils' windres, which supports arm +and arm64. But there's a key difference between binutils' windres and +LLVM's windres: the LLVM one uses proper grouped sections. + +So, this commit adds grouped sections support for resource sections to +the linker. We don't attempt to plumb generic support for grouped +sections, just as there isn't generic support already for what resources +require. Instead we augment the resource handling logic to deal with +standard two-section resource objects. + +Change-Id: I059450021405cdf2ef1c195ddbab3960764ad711 +--- + src/cmd/link/internal/ld/lib.go | 2 +- + src/cmd/link/internal/ld/pe.go | 50 ++++++++++++++-------------- + src/cmd/link/internal/loadpe/ldpe.go | 47 ++++++++++++++------------ + 3 files changed, 52 insertions(+), 47 deletions(-) + +diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go +index f98668a7dc..f09b5910b9 100644 +--- a/src/cmd/link/internal/ld/lib.go ++++ b/src/cmd/link/internal/ld/lib.go +@@ -1900,7 +1900,7 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string, + Errorf(nil, "%v", err) + return + } +- if rsrc != 0 { ++ if rsrc != nil { + setpersrc(ctxt, rsrc) + } + ctxt.Textp2 = append(ctxt.Textp2, textp...) +diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go +index ec5b6d5f52..29094fe8ed 100644 +--- a/src/cmd/link/internal/ld/pe.go ++++ b/src/cmd/link/internal/ld/pe.go +@@ -253,7 +253,7 @@ type Dll struct { + } + + var ( +- rsrcsym loader.Sym ++ rsrcsyms []loader.Sym + PESECTHEADR int32 + PEFILEHEADR int32 + pe64 int +@@ -1464,47 +1464,47 @@ func (ctxt *Link) dope() { + initdynexport(ctxt) + } + +-func setpersrc(ctxt *Link, sym loader.Sym) { +- if rsrcsym != 0 { ++func setpersrc(ctxt *Link, syms []loader.Sym) { ++ if rsrcsyms != nil { + Errorf(nil, "too many .rsrc sections") + } +- +- rsrcsym = sym +- ctxt.loader.SetAttrReachable(rsrcsym, true) ++ rsrcsyms = syms ++ for i := range rsrcsyms { ++ ctxt.loader.SetAttrReachable(rsrcsyms[i], true) ++ } + } + + func addpersrc(ctxt *Link) { +- if rsrcsym == 0 { ++ if rsrcsyms == nil { + return + } + +- rsrc := ctxt.loader.Syms[rsrcsym] +- data := rsrc.P +- size := len(data) ++ var size int ++ for i := range rsrcsyms { ++ size += len(ctxt.loader.Syms[rsrcsyms[i]].P) ++ } + h := pefile.addSection(".rsrc", size, size) + h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA + h.checkOffset(ctxt.Out.Offset()) + +- // relocation +- for ri := range rsrc.R { +- r := &rsrc.R[ri] +- p := data[r.Off:] +- val := uint32(int64(h.virtualAddress) + r.Add) +- +- // 32-bit little-endian +- p[0] = byte(val) +- +- p[1] = byte(val >> 8) +- p[2] = byte(val >> 16) +- p[3] = byte(val >> 24) ++ for i := range rsrcsyms { ++ rsrc := ctxt.loader.Syms[rsrcsyms[i]] ++ splitResources := strings.Contains(rsrc.Name, ".rsrc$") ++ for ri := range rsrc.R { ++ r := &rsrc.R[ri] ++ p := rsrc.P[r.Off:] ++ val := uint32(int64(h.virtualAddress) + r.Add) ++ if splitResources { ++ val += uint32(len(rsrc.P)) ++ } ++ binary.LittleEndian.PutUint32(p, val) ++ } ++ ctxt.Out.Write(rsrc.P) + } +- +- ctxt.Out.Write(data) + h.pad(ctxt.Out, uint32(size)) + + // update data directory + pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.virtualAddress +- + pefile.dataDirectory[pe.IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.virtualSize + } + +diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go +index b60b84ce9f..08832ba552 100644 +--- a/src/cmd/link/internal/loadpe/ldpe.go ++++ b/src/cmd/link/internal/loadpe/ldpe.go +@@ -158,7 +158,7 @@ func makeUpdater(l *loader.Loader, bld *loader.SymbolBuilder, s loader.Sym) *loa + // Load loads the PE file pn from input. + // Symbols are written into syms, and a slice of the text symbols is returned. + // If an .rsrc section is found, its symbol is returned as rsrc. +-func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc loader.Sym, err error) { ++func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Reader, pkg string, length int64, pn string) (textp []loader.Sym, rsrc []loader.Sym, err error) { + lookup := func(name string, version int) (*loader.SymbolBuilder, loader.Sym) { + s := l.LookupOrCreateSym(name, version) + sb := l.MakeSymbolUpdater(s) +@@ -176,7 +176,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details) + f, err := pe.NewFile(sr) + if err != nil { +- return nil, 0, err ++ return nil, nil, err + } + defer f.Close() + +@@ -211,21 +211,21 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + bld.SetType(sym.STEXT) + + default: +- return nil, 0, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name) ++ return nil, nil, fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name) + } + + if bld.Type() != sym.SNOPTRBSS { + data, err := sect.Data() + if err != nil { +- return nil, 0, err ++ return nil, nil, err + } + sectdata[sect] = data + bld.SetData(data) + } + bld.SetSize(int64(sect.Size)) + sectsyms[sect] = s +- if sect.Name == ".rsrc" { +- rsrc = s ++ if sect.Name == ".rsrc" || strings.HasPrefix(sect.Name, ".rsrc$") { ++ rsrc = append(rsrc, s) + } + } + +@@ -246,22 +246,23 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + continue + } + ++ splitResources := strings.HasPrefix(rsect.Name, ".rsrc$") + sb := l.MakeSymbolUpdater(sectsyms[rsect]) + for j, r := range rsect.Relocs { + if int(r.SymbolTableIndex) >= len(f.COFFSymbols) { +- return nil, 0, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols)) ++ return nil, nil, fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols)) + } + pesym := &f.COFFSymbols[r.SymbolTableIndex] + _, gosym, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion) + if err != nil { +- return nil, 0, err ++ return nil, nil, err + } + if gosym == 0 { + name, err := pesym.FullName(f.StringTable) + if err != nil { + name = string(pesym.Name[:]) + } +- return nil, 0, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type) ++ return nil, nil, fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type) + } + + rSym := gosym +@@ -271,11 +272,11 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + var rType objabi.RelocType + switch arch.Family { + default: +- return nil, 0, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family) ++ return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family) + case sys.I386, sys.AMD64: + switch r.Type { + default: +- return nil, 0, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type) ++ return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type) + + case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, + IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 +@@ -302,7 +303,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + case sys.ARM: + switch r.Type { + default: +- return nil, 0, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type) ++ return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type) + + case IMAGE_REL_ARM_SECREL: + rType = objabi.R_PCREL +@@ -324,7 +325,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + // ld -r could generate multiple section symbols for the + // same section but with different values, we have to take + // that into account +- if issect(pesym) { ++ if issect(pesym) || splitResources { + rAdd += int64(pesym.Value) + } + +@@ -333,6 +334,10 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + rel.SetSiz(rSize) + rel.SetSym(rSym) + rel.SetAdd(rAdd) ++ ++ if splitResources { ++ l.SetAttrReachable(rSym, true) ++ } + } + + sb.SortRelocs() +@@ -346,7 +351,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + + name, err := pesym.FullName(f.StringTable) + if err != nil { +- return nil, 0, err ++ return nil, nil, err + } + if name == "" { + continue +@@ -373,7 +378,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + + bld, s, err := readpesym(l, arch, l.LookupOrCreateSym, f, pesym, sectsyms, localSymVersion) + if err != nil { +- return nil, 0, err ++ return nil, nil, err + } + + if pesym.SectionNumber == 0 { // extern +@@ -391,14 +396,14 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) { + sect = f.Sections[pesym.SectionNumber-1] + if _, found := sectsyms[sect]; !found { +- return nil, 0, fmt.Errorf("%s: %v: missing sect.sym", pn, s) ++ return nil, nil, fmt.Errorf("%s: %v: missing sect.sym", pn, s) + } + } else { +- return nil, 0, fmt.Errorf("%s: %v: sectnum < 0!", pn, s) ++ return nil, nil, fmt.Errorf("%s: %v: sectnum < 0!", pn, s) + } + + if sect == nil { +- return nil, 0, nil ++ return nil, nil, nil + } + + if l.OuterSym(s) != 0 { +@@ -407,7 +412,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + } + outerName := l.SymName(l.OuterSym(s)) + sectName := l.SymName(sectsyms[sect]) +- return nil, 0, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName) ++ return nil, nil, fmt.Errorf("%s: duplicate symbol reference: %s in both %s and %s", pn, l.SymName(s), outerName, sectName) + } + + bld = makeUpdater(l, bld, s) +@@ -418,7 +423,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + bld.SetSize(4) + if l.SymType(sectsym) == sym.STEXT { + if bld.External() && !bld.DuplicateOK() { +- return nil, 0, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s)) ++ return nil, nil, fmt.Errorf("%s: duplicate symbol definition", l.SymName(s)) + } + bld.SetExternal(true) + } +@@ -435,7 +440,7 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read + if l.SymType(s) == sym.STEXT { + for ; s != 0; s = l.SubSym(s) { + if l.AttrOnList(s) { +- return nil, 0, fmt.Errorf("symbol %s listed multiple times", l.SymName(s)) ++ return nil, nil, fmt.Errorf("symbol %s listed multiple times", l.SymName(s)) + } + l.SetAttrOnList(s, true) + textp = append(textp, s) +-- +2.29.1 + diff --git a/go-patches/0006-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch b/go-patches/0006-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch new file mode 100644 index 00000000..240d097e --- /dev/null +++ b/go-patches/0006-runtime-use-CreateWaitableTimerEx-to-implement-uslee.patch @@ -0,0 +1,406 @@ +From ef97bba4eec391707d08870252e555f3797ce270 Mon Sep 17 00:00:00 2001 +From: Alex Brainman +Date: Sun, 19 Jul 2020 16:06:48 +1000 +Subject: [PATCH 6/8] runtime: use CreateWaitableTimerEx to implement usleep +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +@jstarks suggested that recent versions of Windows provide access to high resolution timers. See + +https://github.com/golang/go/issues/8687#issuecomment-656259353 + +for details. + +I tried to run this C program on my Windows 10 computer + +``` + #include + #include + + #pragma comment(lib, "Winmm.lib") + +// Apparently this is already defined when I use msvc cl. +//#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002; + +int usleep(HANDLE timer, LONGLONG d) { + LARGE_INTEGER liDueTime; + DWORD ret; + LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds; + LARGE_INTEGER Frequency; + + QueryPerformanceFrequency(&Frequency); + QueryPerformanceCounter(&StartingTime); + + liDueTime.QuadPart = d; + liDueTime.QuadPart = liDueTime.QuadPart * 10; // us into 100 of ns units + liDueTime.QuadPart = -liDueTime.QuadPart; // negative for relative dure time + + if (!SetWaitableTimer(timer, &liDueTime, 0, NULL, NULL, 0)) { + printf("SetWaitableTimer failed: errno=%d\n", GetLastError()); + return 1; + } + + ret = WaitForSingleObject(timer, INFINITE); + if (ret != WAIT_OBJECT_0) { + printf("WaitForSingleObject failed: ret=%d errno=%d\n", ret, GetLastError()); + return 1; + } + + QueryPerformanceCounter(&EndingTime); + ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; + ElapsedMicroseconds.QuadPart *= 1000000; + ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; + + printf("delay is %lld us - slept for %lld us\n", d, ElapsedMicroseconds.QuadPart); + + return 0; +} + +int testTimer(DWORD createFlag) +{ + HANDLE timer; + + timer = CreateWaitableTimerEx(NULL, NULL, createFlag, TIMER_ALL_ACCESS); + if (timer == NULL) { + printf("CreateWaitableTimerEx failed: errno=%d\n", GetLastError()); + return 1; + } + + usleep(timer, 1000LL); + usleep(timer, 100LL); + usleep(timer, 10LL); + usleep(timer, 1LL); + + CloseHandle(timer); + + return 0; +} + +int main() +{ + printf("\n1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off\n"); + testTimer(0); + + printf("\n2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off\n"); + testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION); + + timeBeginPeriod(1); + + printf("\n3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on\n"); + testTimer(0); + + printf("\n4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on\n"); + testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION); +} +``` + +and I see this output + +``` +1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off +delay is 1000 us - slept for 4045 us +delay is 100 us - slept for 3915 us +delay is 10 us - slept for 3291 us +delay is 1 us - slept for 2234 us + +2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off +delay is 1000 us - slept for 1076 us +delay is 100 us - slept for 569 us +delay is 10 us - slept for 585 us +delay is 1 us - slept for 17 us + +3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on +delay is 1000 us - slept for 742 us +delay is 100 us - slept for 893 us +delay is 10 us - slept for 414 us +delay is 1 us - slept for 920 us + +4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on +delay is 1000 us - slept for 1466 us +delay is 100 us - slept for 559 us +delay is 10 us - slept for 535 us +delay is 1 us - slept for 5 us +``` + +That shows, that indeed using CREATE_WAITABLE_TIMER_HIGH_RESOLUTION +will provide sleeps as low as about 500 microseconds, while our +current approach provides about 1 millisecond sleep. + +New approach also does not require for timeBeginPeriod to be on, +so this change solves long standing problem with go programs draining +laptop battery, because it calls timeBeginPeriod. + +This change will only run on systems where +CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. If not +available, the runtime will fallback to original code that uses +timeBeginPeriod. + +This is how this change affects benchmark reported in issue #14790 + +name               old time/op  new time/op  delta +ChanToSyscallPing  1.05ms ± 2%  0.68ms ±11%  -35.43%  (p=0.000 n=10+10) + +The benchmark was run with GOMAXPROCS set to 1. + +Fixes #8687 +Updates #14790 + +Change-Id: I5b97ba58289c088c17c05292e12e45285c467eae +--- + src/runtime/os_windows.go | 58 +++++++++++++++++++++++++++++++++ + src/runtime/sys_windows_386.s | 36 ++++++++++++++++++++ + src/runtime/sys_windows_amd64.s | 32 ++++++++++++++++++ + src/runtime/sys_windows_arm.s | 18 ++++++++++ + 4 files changed, 144 insertions(+) + +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +index 769197db46..9aadd993f2 100644 +--- a/src/runtime/os_windows.go ++++ b/src/runtime/os_windows.go +@@ -21,6 +21,7 @@ const ( + //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" + //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" + //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" ++//go:cgo_import_dynamic runtime._CreateWaitableTimerExW CreateWaitableTimerExW%4 "kernel32.dll" + //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll" + //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll" +@@ -71,6 +72,7 @@ var ( + _CreateIoCompletionPort, + _CreateThread, + _CreateWaitableTimerA, ++ _CreateWaitableTimerExW, + _DuplicateHandle, + _ExitProcess, + _FreeEnvironmentStringsW, +@@ -158,6 +160,8 @@ type mOS struct { + waitsema uintptr // semaphore for parking on locks + resumesema uintptr // semaphore to indicate suspend/resume + ++ highResTimer uintptr // high resolution timer handle used in usleep ++ + // preemptExtLock synchronizes preemptM with entry/exit from + // external C code. + // +@@ -415,6 +419,12 @@ const osRelaxMinNS = 60 * 1e6 + // if we're already using the CPU, but if all Ps are idle there's no + // need to consume extra power to drive the high-res timer. + func osRelax(relax bool) uint32 { ++ if haveHighResTimer { ++ // Only call timeBeginPeriod/timeEndPeriod, if ++ // high resolution timer is not available. ++ return 0 ++ } ++ + if relax { + return uint32(stdcall1(_timeEndPeriod, 1)) + } else { +@@ -422,6 +432,37 @@ func osRelax(relax bool) uint32 { + } + } + ++// haveHighResTimer determines, if CreateWaitableTimerEx ++// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. ++var haveHighResTimer = false ++ ++// createHighResTimer calls CreateWaitableTimerEx with ++// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag to create high ++// resolution timer. createHighResTimer returns new timer ++// handle or 0, if CreateWaitableTimerEx failed. ++func createHighResTimer() uintptr { ++ const ( ++ // As per @jstarks, see ++ // https://github.com/golang/go/issues/8687#issuecomment-656259353 ++ _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002 ++ _TIMER_ALL_ACCESS = 0x1F0003 ++ ) ++ return stdcall4(_CreateWaitableTimerExW, 0, 0, _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, _TIMER_ALL_ACCESS) ++} ++ ++func initHighResTimer() { ++ if GOARCH == "arm" { ++ // TODO: Not yet implemented. ++ return ++ } ++ h := createHighResTimer() ++ if h != 0 { ++ haveHighResTimer = true ++ usleep2Addr = unsafe.Pointer(funcPC(usleep2HighRes)) ++ stdcall1(_CloseHandle, h) ++ } ++} ++ + func osinit() { + asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) + usleep2Addr = unsafe.Pointer(funcPC(usleep2)) +@@ -437,6 +478,7 @@ func osinit() { + + stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) + ++ initHighResTimer() + timeBeginPeriodRetValue = osRelax(false) + + ncpu = getproccount() +@@ -852,9 +894,20 @@ func minit() { + var thandle uintptr + stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) + ++ // Configure usleep timer, if possible. ++ var timer uintptr ++ if haveHighResTimer { ++ timer = createHighResTimer() ++ if timer == 0 { ++ print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n") ++ throw("CreateWaitableTimerEx when creating timer failed") ++ } ++ } ++ + mp := getg().m + lock(&mp.threadLock) + mp.thread = thandle ++ mp.highResTimer = timer + unlock(&mp.threadLock) + + // Query the true stack base from the OS. Currently we're +@@ -892,6 +945,10 @@ func unminit() { + lock(&mp.threadLock) + stdcall1(_CloseHandle, mp.thread) + mp.thread = 0 ++ if mp.highResTimer != 0 { ++ stdcall1(_CloseHandle, mp.highResTimer) ++ mp.highResTimer = 0 ++ } + unlock(&mp.threadLock) + } + +@@ -987,6 +1044,7 @@ func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr { + // in sys_windows_386.s and sys_windows_amd64.s + func onosstack(fn unsafe.Pointer, arg uint32) + func usleep2(usec uint32) ++func usleep2HighRes(usec uint32) + func switchtothread() + + var usleep2Addr unsafe.Pointer +diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s +index 9e1f40925d..4ac1527ab1 100644 +--- a/src/runtime/sys_windows_386.s ++++ b/src/runtime/sys_windows_386.s +@@ -428,6 +428,42 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20 + MOVL BP, SP + RET + ++// Runs on OS stack. duration (in 100ns units) is in BX. ++TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36 ++ // Want negative 100ns units. ++ NEGL BX ++ MOVL $-1, hi-4(SP) ++ MOVL BX, lo-8(SP) ++ ++ get_tls(CX) ++ MOVL g(CX), CX ++ MOVL g_m(CX), CX ++ MOVL (m_mOS+mOS_highResTimer)(CX), CX ++ MOVL CX, saved_timer-12(SP) ++ ++ MOVL $0, fResume-16(SP) ++ MOVL $0, lpArgToCompletionRoutine-20(SP) ++ MOVL $0, pfnCompletionRoutine-24(SP) ++ MOVL $0, lPeriod-28(SP) ++ LEAL lo-8(SP), BX ++ MOVL BX, lpDueTime-32(SP) ++ MOVL CX, hTimer-36(SP) ++ MOVL SP, BP ++ MOVL runtime·_SetWaitableTimer(SB), AX ++ CALL AX ++ MOVL BP, SP ++ ++ MOVL $0, ptime-28(SP) ++ MOVL $0, alertable-32(SP) ++ MOVL saved_timer-12(SP), CX ++ MOVL CX, handle-36(SP) ++ MOVL SP, BP ++ MOVL runtime·_NtWaitForSingleObject(SB), AX ++ CALL AX ++ MOVL BP, SP ++ ++ RET ++ + // Runs on OS stack. + TEXT runtime·switchtothread(SB),NOSPLIT,$0 + MOVL SP, BP +diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s +index 6c8eecd4e7..847542592b 100644 +--- a/src/runtime/sys_windows_amd64.s ++++ b/src/runtime/sys_windows_amd64.s +@@ -457,6 +457,38 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48 + MOVQ 40(SP), SP + RET + ++// Runs on OS stack. duration (in 100ns units) is in BX. ++TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72 ++ MOVQ SP, AX ++ ANDQ $~15, SP // alignment as per Windows requirement ++ MOVQ AX, 64(SP) ++ ++ get_tls(CX) ++ MOVQ g(CX), CX ++ MOVQ g_m(CX), CX ++ MOVQ (m_mOS+mOS_highResTimer)(CX), CX // hTimer ++ MOVQ CX, 48(SP) // save hTimer for later ++ // Want negative 100ns units. ++ NEGQ BX ++ LEAQ 56(SP), DX // lpDueTime ++ MOVQ BX, (DX) ++ MOVQ $0, R8 // lPeriod ++ MOVQ $0, R9 // pfnCompletionRoutine ++ MOVQ $0, AX ++ MOVQ AX, 32(SP) // lpArgToCompletionRoutine ++ MOVQ AX, 40(SP) // fResume ++ MOVQ runtime·_SetWaitableTimer(SB), AX ++ CALL AX ++ ++ MOVQ 48(SP), CX // handle ++ MOVQ $0, DX // alertable ++ MOVQ $0, R8 // ptime ++ MOVQ runtime·_NtWaitForSingleObject(SB), AX ++ CALL AX ++ ++ MOVQ 64(SP), SP ++ RET ++ + // Runs on OS stack. + TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0 + MOVQ SP, AX +diff --git a/src/runtime/sys_windows_arm.s b/src/runtime/sys_windows_arm.s +index 256b5ff7f0..e6c61a4e42 100644 +--- a/src/runtime/sys_windows_arm.s ++++ b/src/runtime/sys_windows_arm.s +@@ -468,6 +468,24 @@ TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$0 + MOVW R4, R13 // Restore SP + MOVM.IA.W (R13), [R4, R15] // pop {R4, pc} + ++// Runs on OS stack. Duration (in 100ns units) is in R0. ++// TODO: neeeds to be implemented properly. ++TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0 ++ MOVM.DB.W [R4, R14], (R13) // push {r4, lr} ++ MOVW R13, R4 // Save SP ++ SUB $8, R13 // R13 = R13 - 8 ++ BIC $0x7, R13 // Align SP for ABI ++ RSB $0, R0, R3 // R3 = -R0 ++ MOVW $0, R1 // R1 = FALSE (alertable) ++ MOVW $-1, R0 // R0 = handle ++ MOVW R13, R2 // R2 = pTime ++ MOVW R3, 0(R2) // time_lo ++ MOVW R0, 4(R2) // time_hi ++ MOVW runtime·_NtWaitForSingleObject(SB), R3 ++ BL (R3) ++ MOVW R4, R13 // Restore SP ++ MOVM.IA.W (R13), [R4, R15] // pop {R4, pc} ++ + // Runs on OS stack. + TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0 + MOVM.DB.W [R4, R14], (R13) // push {R4, lr} +-- +2.29.1 + diff --git a/go-patches/0007-Revert-release-branch.go1.15-runtime-detect-services.patch b/go-patches/0007-Revert-release-branch.go1.15-runtime-detect-services.patch new file mode 100644 index 00000000..5d09b3c2 --- /dev/null +++ b/go-patches/0007-Revert-release-branch.go1.15-runtime-detect-services.patch @@ -0,0 +1,135 @@ +From 82dfc8240f58880ec59a98ed9403d9997571573a Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Fri, 11 Sep 2020 13:04:11 +0200 +Subject: [PATCH 7/8] Revert "[release-branch.go1.15] runtime: detect services + in signal handler" + +This reverts commit b1253d24e159129c778377c3a2a0bde15904a417. +--- + src/runtime/os_windows.go | 73 +++------------------------------------ + 1 file changed, 4 insertions(+), 69 deletions(-) + +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +index 9aadd993f2..125bf0b225 100644 +--- a/src/runtime/os_windows.go ++++ b/src/runtime/os_windows.go +@@ -37,10 +37,7 @@ const ( + //go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll" + //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" +-//go:cgo_import_dynamic runtime._OpenProcess OpenProcess%3 "kernel32.dll" + //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" +-//go:cgo_import_dynamic runtime._ProcessIdToSessionId ProcessIdToSessionId%2 "kernel32.dll" +-//go:cgo_import_dynamic runtime._QueryFullProcessImageNameA QueryFullProcessImageNameA%4 "kernel32.dll" + //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll" + //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll" +@@ -89,10 +86,7 @@ var ( + _SetThreadContext, + _LoadLibraryW, + _LoadLibraryA, +- _OpenProcess, + _PostQueuedCompletionStatus, +- _ProcessIdToSessionId, +- _QueryFullProcessImageNameA, + _QueryPerformanceCounter, + _QueryPerformanceFrequency, + _ResumeThread, +@@ -136,8 +130,7 @@ var ( + // Load ntdll.dll manually during startup, otherwise Mingw + // links wrong printf function to cgo executable (see issue + // 12030 for details). +- _NtWaitForSingleObject stdFunction +- _NtQueryInformationProcess stdFunction ++ _NtWaitForSingleObject stdFunction + + // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them. + _timeBeginPeriod, +@@ -266,7 +259,6 @@ func loadOptionalSyscalls() { + throw("ntdll.dll not found") + } + _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000")) +- _NtQueryInformationProcess = windowsFindfunc(n32, []byte("NtQueryInformationProcess\000")) + + if GOARCH == "arm" { + _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000")) +@@ -1061,63 +1053,6 @@ func usleep(us uint32) { + onosstack(usleep2Addr, 10*us) + } + +-// isWindowsService returns whether the process is currently executing as a +-// Windows service. The below technique looks a bit hairy, but it's actually +-// exactly what the .NET framework does for the similarly named function: +-// https://github.com/dotnet/extensions/blob/f4066026ca06984b07e90e61a6390ac38152ba93/src/Hosting/WindowsServices/src/WindowsServiceHelpers.cs#L26-L31 +-// Specifically, it looks up whether the parent process has session ID zero +-// and is called "services". +-func isWindowsService() bool { +- const ( +- _CURRENT_PROCESS = ^uintptr(0) +- _PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 +- ) +- // pbi is a PROCESS_BASIC_INFORMATION struct, where we just care about +- // the 6th pointer inside of it, which contains the pid of the process +- // parent: +- // https://github.com/wine-mirror/wine/blob/42cb7d2ad1caba08de235e6319b9967296b5d554/include/winternl.h#L1294 +- var pbi [6]uintptr +- var pbiLen uint32 +- err := stdcall5(_NtQueryInformationProcess, _CURRENT_PROCESS, 0, uintptr(unsafe.Pointer(&pbi[0])), uintptr(unsafe.Sizeof(pbi)), uintptr(unsafe.Pointer(&pbiLen))) +- if err != 0 { +- return false +- } +- var psid uint32 +- err = stdcall2(_ProcessIdToSessionId, pbi[5], uintptr(unsafe.Pointer(&psid))) +- if err == 0 || psid != 0 { +- return false +- } +- pproc := stdcall3(_OpenProcess, _PROCESS_QUERY_LIMITED_INFORMATION, 0, pbi[5]) +- if pproc == 0 { +- return false +- } +- defer stdcall1(_CloseHandle, pproc) +- // exeName gets the path to the executable image of the parent process +- var exeName [261]byte +- exeNameLen := uint32(len(exeName) - 1) +- err = stdcall4(_QueryFullProcessImageNameA, pproc, 0, uintptr(unsafe.Pointer(&exeName[0])), uintptr(unsafe.Pointer(&exeNameLen))) +- if err == 0 || exeNameLen == 0 { +- return false +- } +- servicesLower := "services.exe" +- servicesUpper := "SERVICES.EXE" +- i := int(exeNameLen) - 1 +- j := len(servicesLower) - 1 +- if i < j { +- return false +- } +- for { +- if j == -1 { +- return i == -1 || exeName[i] == '\\' +- } +- if exeName[i] != servicesLower[j] && exeName[i] != servicesUpper[j] { +- return false +- } +- i-- +- j-- +- } +-} +- + func ctrlhandler1(_type uint32) uint32 { + var s uint32 + +@@ -1133,9 +1068,9 @@ func ctrlhandler1(_type uint32) uint32 { + if sigsend(s) { + return 1 + } +- if !islibrary && !isarchive && !isWindowsService() { +- // Only exit the program if we don't have a DLL or service. +- // See https://golang.org/issues/35965 and https://golang.org/issues/40167 ++ if !islibrary && !isarchive { ++ // Only exit the program if we don't have a DLL. ++ // See https://golang.org/issues/35965. + exit(2) // SIGINT, SIGTERM, etc + } + return 0 +-- +2.29.1 + diff --git a/go-patches/0008-runtime-do-not-explicitly-exit-on-ctrl-handler.patch b/go-patches/0008-runtime-do-not-explicitly-exit-on-ctrl-handler.patch new file mode 100644 index 00000000..4bc255c4 --- /dev/null +++ b/go-patches/0008-runtime-do-not-explicitly-exit-on-ctrl-handler.patch @@ -0,0 +1,49 @@ +From a9e2ff1fa414106c130907ac993600bd3adcd6cd Mon Sep 17 00:00:00 2001 +From: "Jason A. Donenfeld" +Date: Tue, 14 Jul 2020 01:41:03 -0600 +Subject: [PATCH 8/8] runtime: do not explicitly exit on ctrl handler + +The default ctrl+c handler should process exits in situations where it +makes sense, like console apps, but not in situations where it doesn't, +like libraries or services. Therefore, we should remove the exit(2) so +that the default handler is used for this. This also uses the more +proper windows exit code of STATUS_CONTROL_C_EXIT, with the base case +handler installed by KernelBase.dll. In particular, this helps in the +case of services, which previously would terminate when receiving +shutdown signals, instead of passing them onward to the service program. +In this CL, contrary to CL 244959, we do not need to special case +services with expensive detection algorithms, or rely on hard-coded +library/archive flags. + +Fixes #40167. +Fixes #40074. + +Change-Id: I9bf6ed6f65cefeff754d270aa33fa4df8d0b451f +Reviewed-on: https://go-review.googlesource.com/c/go/+/243597 +Run-TryBot: Jason A. Donenfeld +TryBot-Result: Gobot Gobot +Reviewed-by: Alex Brainman +Reviewed-by: Jason A. Donenfeld +--- + src/runtime/os_windows.go | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +index 125bf0b225..46f4a23e5b 100644 +--- a/src/runtime/os_windows.go ++++ b/src/runtime/os_windows.go +@@ -1068,11 +1068,6 @@ func ctrlhandler1(_type uint32) uint32 { + if sigsend(s) { + return 1 + } +- if !islibrary && !isarchive { +- // Only exit the program if we don't have a DLL. +- // See https://golang.org/issues/35965. +- exit(2) // SIGINT, SIGTERM, etc +- } + return 0 + } + +-- +2.29.1 + diff --git a/go-patches/highres-timer.patch b/go-patches/highres-timer.patch deleted file mode 100644 index 87dd6b17..00000000 --- a/go-patches/highres-timer.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 2975b381dc3f559a2eef875582d73cec00ab6b17 Mon Sep 17 00:00:00 2001 -From: Alex Brainman -Date: Sun, 19 Jul 2020 16:06:48 +1000 -Subject: [PATCH] runtime: use CreateWaitableTimerEx to implement usleep - -@jstarks suggested that recent versions of Windows provide access to high resolution timers. See - -https://github.com/golang/go/issues/8687#issuecomment-656259353 - -for details. - -I tried to run this C program on my Windows 10 computer - -``` - #include - #include - - #pragma comment(lib, "Winmm.lib") - -// Apparently this is already defined when I use msvc cl. -//#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002; - -int usleep(HANDLE timer, LONGLONG d) { - LARGE_INTEGER liDueTime; - DWORD ret; - LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds; - LARGE_INTEGER Frequency; - - QueryPerformanceFrequency(&Frequency); - QueryPerformanceCounter(&StartingTime); - - liDueTime.QuadPart = d; - liDueTime.QuadPart = liDueTime.QuadPart * 10; // us into 100 of ns units - liDueTime.QuadPart = -liDueTime.QuadPart; // negative for relative dure time - - if (!SetWaitableTimer(timer, &liDueTime, 0, NULL, NULL, 0)) { - printf("SetWaitableTimer failed: errno=%d\n", GetLastError()); - return 1; - } - - ret = WaitForSingleObject(timer, INFINITE); - if (ret != WAIT_OBJECT_0) { - printf("WaitForSingleObject failed: ret=%d errno=%d\n", ret, GetLastError()); - return 1; - } - - QueryPerformanceCounter(&EndingTime); - ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart; - ElapsedMicroseconds.QuadPart *= 1000000; - ElapsedMicroseconds.QuadPart /= Frequency.QuadPart; - - printf("delay is %lld us - slept for %lld us\n", d, ElapsedMicroseconds.QuadPart); - - return 0; -} - -int testTimer(DWORD createFlag) -{ - HANDLE timer; - - timer = CreateWaitableTimerEx(NULL, NULL, createFlag, TIMER_ALL_ACCESS); - if (timer == NULL) { - printf("CreateWaitableTimerEx failed: errno=%d\n", GetLastError()); - return 1; - } - - usleep(timer, 1000LL); - usleep(timer, 100LL); - usleep(timer, 10LL); - usleep(timer, 1LL); - - CloseHandle(timer); - - return 0; -} - -int main() -{ - printf("\n1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off\n"); - testTimer(0); - - printf("\n2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off\n"); - testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION); - - timeBeginPeriod(1); - - printf("\n3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on\n"); - testTimer(0); - - printf("\n4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on\n"); - testTimer(CREATE_WAITABLE_TIMER_HIGH_RESOLUTION); -} -``` - -and I see this output - -``` -1. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is off -delay is 1000 us - slept for 4045 us -delay is 100 us - slept for 3915 us -delay is 10 us - slept for 3291 us -delay is 1 us - slept for 2234 us - -2. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is off -delay is 1000 us - slept for 1076 us -delay is 100 us - slept for 569 us -delay is 10 us - slept for 585 us -delay is 1 us - slept for 17 us - -3. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is off - timeBeginPeriod is on -delay is 1000 us - slept for 742 us -delay is 100 us - slept for 893 us -delay is 10 us - slept for 414 us -delay is 1 us - slept for 920 us - -4. CREATE_WAITABLE_TIMER_HIGH_RESOLUTION is on - timeBeginPeriod is on -delay is 1000 us - slept for 1466 us -delay is 100 us - slept for 559 us -delay is 10 us - slept for 535 us -delay is 1 us - slept for 5 us -``` - -That shows, that indeed using CREATE_WAITABLE_TIMER_HIGH_RESOLUTION -will provide sleeps as low as about 500 microseconds, while our -current approach provides about 1 millisecond sleep. - -New approach also does not require for timeBeginPeriod to be on, -so this change solves long standing problem with go programs draining -laptop battery, because it calls timeBeginPeriod. - -This change will only run on systems where -CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. If not -available, the runtime will fallback to original code that uses -timeBeginPeriod. - -This is how this change affects benchmark reported in issue #14790 - -name               old time/op  new time/op  delta -ChanToSyscallPing  1.05ms ± 2%  0.68ms ±11%  -35.43%  (p=0.000 n=10+10) - -The benchmark was run with GOMAXPROCS set to 1. - -Fixes #8687 -Updates #14790 - -Change-Id: I5b97ba58289c088c17c05292e12e45285c467eae ---- - -diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go -index a62e941..46f4a23 100644 ---- a/src/runtime/os_windows.go -+++ b/src/runtime/os_windows.go -@@ -21,6 +21,7 @@ - //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" - //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" - //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" -+//go:cgo_import_dynamic runtime._CreateWaitableTimerExW CreateWaitableTimerExW%4 "kernel32.dll" - //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll" - //go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll" - //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll" -@@ -68,6 +69,7 @@ - _CreateIoCompletionPort, - _CreateThread, - _CreateWaitableTimerA, -+ _CreateWaitableTimerExW, - _DuplicateHandle, - _ExitProcess, - _FreeEnvironmentStringsW, -@@ -151,6 +153,8 @@ - waitsema uintptr // semaphore for parking on locks - resumesema uintptr // semaphore to indicate suspend/resume - -+ highResTimer uintptr // high resolution timer handle used in usleep -+ - // preemptExtLock synchronizes preemptM with entry/exit from - // external C code. - // -@@ -407,6 +411,12 @@ - // if we're already using the CPU, but if all Ps are idle there's no - // need to consume extra power to drive the high-res timer. - func osRelax(relax bool) uint32 { -+ if haveHighResTimer { -+ // Only call timeBeginPeriod/timeEndPeriod, if -+ // high resolution timer is not available. -+ return 0 -+ } -+ - if relax { - return uint32(stdcall1(_timeEndPeriod, 1)) - } else { -@@ -414,6 +424,37 @@ - } - } - -+// haveHighResTimer determines, if CreateWaitableTimerEx -+// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. -+var haveHighResTimer = false -+ -+// createHighResTimer calls CreateWaitableTimerEx with -+// CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag to create high -+// resolution timer. createHighResTimer returns new timer -+// handle or 0, if CreateWaitableTimerEx failed. -+func createHighResTimer() uintptr { -+ const ( -+ // As per @jstarks, see -+ // https://github.com/golang/go/issues/8687#issuecomment-656259353 -+ _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002 -+ _TIMER_ALL_ACCESS = 0x1F0003 -+ ) -+ return stdcall4(_CreateWaitableTimerExW, 0, 0, _CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, _TIMER_ALL_ACCESS) -+} -+ -+func initHighResTimer() { -+ if GOARCH == "arm" { -+ // TODO: Not yet implemented. -+ return -+ } -+ h := createHighResTimer() -+ if h != 0 { -+ haveHighResTimer = true -+ usleep2Addr = unsafe.Pointer(funcPC(usleep2HighRes)) -+ stdcall1(_CloseHandle, h) -+ } -+} -+ - func osinit() { - asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall)) - usleep2Addr = unsafe.Pointer(funcPC(usleep2)) -@@ -429,6 +470,7 @@ - - stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1) - -+ initHighResTimer() - timeBeginPeriodRetValue = osRelax(false) - - ncpu = getproccount() -@@ -844,9 +886,20 @@ - var thandle uintptr - stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) - -+ // Configure usleep timer, if possible. -+ var timer uintptr -+ if haveHighResTimer { -+ timer = createHighResTimer() -+ if timer == 0 { -+ print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n") -+ throw("CreateWaitableTimerEx when creating timer failed") -+ } -+ } -+ - mp := getg().m - lock(&mp.threadLock) - mp.thread = thandle -+ mp.highResTimer = timer - unlock(&mp.threadLock) - - // Query the true stack base from the OS. Currently we're -@@ -884,6 +937,10 @@ - lock(&mp.threadLock) - stdcall1(_CloseHandle, mp.thread) - mp.thread = 0 -+ if mp.highResTimer != 0 { -+ stdcall1(_CloseHandle, mp.highResTimer) -+ mp.highResTimer = 0 -+ } - unlock(&mp.threadLock) - } - -@@ -979,6 +1036,7 @@ - // in sys_windows_386.s and sys_windows_amd64.s - func onosstack(fn unsafe.Pointer, arg uint32) - func usleep2(usec uint32) -+func usleep2HighRes(usec uint32) - func switchtothread() - - var usleep2Addr unsafe.Pointer -diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s -index 9e1f409..4ac1527 100644 ---- a/src/runtime/sys_windows_386.s -+++ b/src/runtime/sys_windows_386.s -@@ -428,6 +428,42 @@ - MOVL BP, SP - RET - -+// Runs on OS stack. duration (in 100ns units) is in BX. -+TEXT runtime·usleep2HighRes(SB),NOSPLIT,$36 -+ // Want negative 100ns units. -+ NEGL BX -+ MOVL $-1, hi-4(SP) -+ MOVL BX, lo-8(SP) -+ -+ get_tls(CX) -+ MOVL g(CX), CX -+ MOVL g_m(CX), CX -+ MOVL (m_mOS+mOS_highResTimer)(CX), CX -+ MOVL CX, saved_timer-12(SP) -+ -+ MOVL $0, fResume-16(SP) -+ MOVL $0, lpArgToCompletionRoutine-20(SP) -+ MOVL $0, pfnCompletionRoutine-24(SP) -+ MOVL $0, lPeriod-28(SP) -+ LEAL lo-8(SP), BX -+ MOVL BX, lpDueTime-32(SP) -+ MOVL CX, hTimer-36(SP) -+ MOVL SP, BP -+ MOVL runtime·_SetWaitableTimer(SB), AX -+ CALL AX -+ MOVL BP, SP -+ -+ MOVL $0, ptime-28(SP) -+ MOVL $0, alertable-32(SP) -+ MOVL saved_timer-12(SP), CX -+ MOVL CX, handle-36(SP) -+ MOVL SP, BP -+ MOVL runtime·_NtWaitForSingleObject(SB), AX -+ CALL AX -+ MOVL BP, SP -+ -+ RET -+ - // Runs on OS stack. - TEXT runtime·switchtothread(SB),NOSPLIT,$0 - MOVL SP, BP -diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s -index 6c8eecd..8475425 100644 ---- a/src/runtime/sys_windows_amd64.s -+++ b/src/runtime/sys_windows_amd64.s -@@ -457,6 +457,38 @@ - MOVQ 40(SP), SP - RET - -+// Runs on OS stack. duration (in 100ns units) is in BX. -+TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$72 -+ MOVQ SP, AX -+ ANDQ $~15, SP // alignment as per Windows requirement -+ MOVQ AX, 64(SP) -+ -+ get_tls(CX) -+ MOVQ g(CX), CX -+ MOVQ g_m(CX), CX -+ MOVQ (m_mOS+mOS_highResTimer)(CX), CX // hTimer -+ MOVQ CX, 48(SP) // save hTimer for later -+ // Want negative 100ns units. -+ NEGQ BX -+ LEAQ 56(SP), DX // lpDueTime -+ MOVQ BX, (DX) -+ MOVQ $0, R8 // lPeriod -+ MOVQ $0, R9 // pfnCompletionRoutine -+ MOVQ $0, AX -+ MOVQ AX, 32(SP) // lpArgToCompletionRoutine -+ MOVQ AX, 40(SP) // fResume -+ MOVQ runtime·_SetWaitableTimer(SB), AX -+ CALL AX -+ -+ MOVQ 48(SP), CX // handle -+ MOVQ $0, DX // alertable -+ MOVQ $0, R8 // ptime -+ MOVQ runtime·_NtWaitForSingleObject(SB), AX -+ CALL AX -+ -+ MOVQ 64(SP), SP -+ RET -+ - // Runs on OS stack. - TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0 - MOVQ SP, AX -diff --git a/src/runtime/sys_windows_arm.s b/src/runtime/sys_windows_arm.s -index 256b5ff..e6c61a4 100644 ---- a/src/runtime/sys_windows_arm.s -+++ b/src/runtime/sys_windows_arm.s -@@ -468,6 +468,24 @@ - MOVW R4, R13 // Restore SP - MOVM.IA.W (R13), [R4, R15] // pop {R4, pc} - -+// Runs on OS stack. Duration (in 100ns units) is in R0. -+// TODO: neeeds to be implemented properly. -+TEXT runtime·usleep2HighRes(SB),NOSPLIT|NOFRAME,$0 -+ MOVM.DB.W [R4, R14], (R13) // push {r4, lr} -+ MOVW R13, R4 // Save SP -+ SUB $8, R13 // R13 = R13 - 8 -+ BIC $0x7, R13 // Align SP for ABI -+ RSB $0, R0, R3 // R3 = -R0 -+ MOVW $0, R1 // R1 = FALSE (alertable) -+ MOVW $-1, R0 // R0 = handle -+ MOVW R13, R2 // R2 = pTime -+ MOVW R3, 0(R2) // time_lo -+ MOVW R0, 4(R2) // time_hi -+ MOVW runtime·_NtWaitForSingleObject(SB), R3 -+ BL (R3) -+ MOVW R4, R13 // Restore SP -+ MOVM.IA.W (R13), [R4, R15] // pop {R4, pc} -+ - // Runs on OS stack. - TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0 - MOVM.DB.W [R4, R14], (R13) // push {R4, lr} diff --git a/go-patches/no-ctrlc-handler.patch b/go-patches/no-ctrlc-handler.patch deleted file mode 100644 index 157ed88f..00000000 --- a/go-patches/no-ctrlc-handler.patch +++ /dev/null @@ -1,184 +0,0 @@ -From 8bc7bff3bff8f61312f8d2307cfe2e433d356c31 Mon Sep 17 00:00:00 2001 -From: "Jason A. Donenfeld" -Date: Fri, 11 Sep 2020 13:04:11 +0200 -Subject: [PATCH 1/2] Revert "[release-branch.go1.15] runtime: detect services - in signal handler" - -This reverts commit b1253d24e159129c778377c3a2a0bde15904a417. ---- - src/runtime/os_windows.go | 73 +++------------------------------------ - 1 file changed, 4 insertions(+), 69 deletions(-) - -diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go -index 769197db46..a584ada702 100644 ---- a/src/runtime/os_windows.go -+++ b/src/runtime/os_windows.go -@@ -36,10 +36,7 @@ const ( - //go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll" - //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" - //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" --//go:cgo_import_dynamic runtime._OpenProcess OpenProcess%3 "kernel32.dll" - //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" --//go:cgo_import_dynamic runtime._ProcessIdToSessionId ProcessIdToSessionId%2 "kernel32.dll" --//go:cgo_import_dynamic runtime._QueryFullProcessImageNameA QueryFullProcessImageNameA%4 "kernel32.dll" - //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" - //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll" - //go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll" -@@ -87,10 +84,7 @@ var ( - _SetThreadContext, - _LoadLibraryW, - _LoadLibraryA, -- _OpenProcess, - _PostQueuedCompletionStatus, -- _ProcessIdToSessionId, -- _QueryFullProcessImageNameA, - _QueryPerformanceCounter, - _QueryPerformanceFrequency, - _ResumeThread, -@@ -134,8 +128,7 @@ var ( - // Load ntdll.dll manually during startup, otherwise Mingw - // links wrong printf function to cgo executable (see issue - // 12030 for details). -- _NtWaitForSingleObject stdFunction -- _NtQueryInformationProcess stdFunction -+ _NtWaitForSingleObject stdFunction - - // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them. - _timeBeginPeriod, -@@ -262,7 +255,6 @@ func loadOptionalSyscalls() { - throw("ntdll.dll not found") - } - _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000")) -- _NtQueryInformationProcess = windowsFindfunc(n32, []byte("NtQueryInformationProcess\000")) - - if GOARCH == "arm" { - _QueryPerformanceCounter = windowsFindfunc(k32, []byte("QueryPerformanceCounter\000")) -@@ -1003,63 +995,6 @@ func usleep(us uint32) { - onosstack(usleep2Addr, 10*us) - } - --// isWindowsService returns whether the process is currently executing as a --// Windows service. The below technique looks a bit hairy, but it's actually --// exactly what the .NET framework does for the similarly named function: --// https://github.com/dotnet/extensions/blob/f4066026ca06984b07e90e61a6390ac38152ba93/src/Hosting/WindowsServices/src/WindowsServiceHelpers.cs#L26-L31 --// Specifically, it looks up whether the parent process has session ID zero --// and is called "services". --func isWindowsService() bool { -- const ( -- _CURRENT_PROCESS = ^uintptr(0) -- _PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 -- ) -- // pbi is a PROCESS_BASIC_INFORMATION struct, where we just care about -- // the 6th pointer inside of it, which contains the pid of the process -- // parent: -- // https://github.com/wine-mirror/wine/blob/42cb7d2ad1caba08de235e6319b9967296b5d554/include/winternl.h#L1294 -- var pbi [6]uintptr -- var pbiLen uint32 -- err := stdcall5(_NtQueryInformationProcess, _CURRENT_PROCESS, 0, uintptr(unsafe.Pointer(&pbi[0])), uintptr(unsafe.Sizeof(pbi)), uintptr(unsafe.Pointer(&pbiLen))) -- if err != 0 { -- return false -- } -- var psid uint32 -- err = stdcall2(_ProcessIdToSessionId, pbi[5], uintptr(unsafe.Pointer(&psid))) -- if err == 0 || psid != 0 { -- return false -- } -- pproc := stdcall3(_OpenProcess, _PROCESS_QUERY_LIMITED_INFORMATION, 0, pbi[5]) -- if pproc == 0 { -- return false -- } -- defer stdcall1(_CloseHandle, pproc) -- // exeName gets the path to the executable image of the parent process -- var exeName [261]byte -- exeNameLen := uint32(len(exeName) - 1) -- err = stdcall4(_QueryFullProcessImageNameA, pproc, 0, uintptr(unsafe.Pointer(&exeName[0])), uintptr(unsafe.Pointer(&exeNameLen))) -- if err == 0 || exeNameLen == 0 { -- return false -- } -- servicesLower := "services.exe" -- servicesUpper := "SERVICES.EXE" -- i := int(exeNameLen) - 1 -- j := len(servicesLower) - 1 -- if i < j { -- return false -- } -- for { -- if j == -1 { -- return i == -1 || exeName[i] == '\\' -- } -- if exeName[i] != servicesLower[j] && exeName[i] != servicesUpper[j] { -- return false -- } -- i-- -- j-- -- } --} -- - func ctrlhandler1(_type uint32) uint32 { - var s uint32 - -@@ -1075,9 +1010,9 @@ func ctrlhandler1(_type uint32) uint32 { - if sigsend(s) { - return 1 - } -- if !islibrary && !isarchive && !isWindowsService() { -- // Only exit the program if we don't have a DLL or service. -- // See https://golang.org/issues/35965 and https://golang.org/issues/40167 -+ if !islibrary && !isarchive { -+ // Only exit the program if we don't have a DLL. -+ // See https://golang.org/issues/35965. - exit(2) // SIGINT, SIGTERM, etc - } - return 0 --- -2.28.0 - -From 84cc2046962e754af08f99327561be2e979eaf16 Mon Sep 17 00:00:00 2001 -From: "Jason A. Donenfeld" -Date: Tue, 14 Jul 2020 01:41:03 -0600 -Subject: [PATCH 2/2] runtime: do not explicitly exit on ctrl handler - -The default ctrl+c handler should process exits in situations where it -makes sense, like console apps, but not in situations where it doesn't, -like libraries or services. Therefore, we should remove the exit(2) so -that the default handler is used for this. This also uses the more -proper windows exit code of STATUS_CONTROL_C_EXIT, with the base case -handler installed by KernelBase.dll. In particular, this helps in the -case of services, which previously would terminate when receiving -shutdown signals, instead of passing them onward to the service program. -In this CL, contrary to CL 244959, we do not need to special case -services with expensive detection algorithms, or rely on hard-coded -library/archive flags. - -Fixes #40167. -Fixes #40074. - -Change-Id: I9bf6ed6f65cefeff754d270aa33fa4df8d0b451f -Reviewed-on: https://go-review.googlesource.com/c/go/+/243597 -Run-TryBot: Jason A. Donenfeld -TryBot-Result: Gobot Gobot -Reviewed-by: Alex Brainman -Reviewed-by: Jason A. Donenfeld ---- - src/runtime/os_windows.go | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go -index a584ada702..a62e941229 100644 ---- a/src/runtime/os_windows.go -+++ b/src/runtime/os_windows.go -@@ -1010,11 +1010,6 @@ func ctrlhandler1(_type uint32) uint32 { - if sigsend(s) { - return 1 - } -- if !islibrary && !isarchive { -- // Only exit the program if we don't have a DLL. -- // See https://golang.org/issues/35965. -- exit(2) // SIGINT, SIGTERM, etc -- } - return 0 - } - --- -2.28.0 - -- cgit v1.2.3-59-g8ed1b