]> Cypherpunks repositories - gostls13.git/commitdiff
os: add handling of os.Interrupt for windows
authorConstantin Konstantinidis <constantinkonstantinidis@gmail.com>
Sun, 28 Nov 2021 14:19:15 +0000 (15:19 +0100)
committerIan Lance Taylor <iant@golang.org>
Sun, 3 Apr 2022 21:26:39 +0000 (21:26 +0000)
Add GenerateConsoleCtrlEvent call to internal syscall package.
Define ErrProcessDone while reviewing handling of os.Signal().
Update test to run for windows using the added call.

Fixes #42311
Fixes #46354

Change-Id: I460955efc76c4febe04b612ac9a0670e62ba5ff3
Reviewed-on: https://go-review.googlesource.com/c/go/+/367495
Trust: Patrik Nyblom <pnyb@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/internal/syscall/windows/syscall_windows.go
src/internal/syscall/windows/zsyscall_windows.go
src/os/exec/exec_windows_test.go
src/os/exec_posix.go
src/os/exec_windows.go
src/os/signal/signal_windows_test.go
src/runtime/signal_windows_test.go

index f8965d0bab175de81d8f0355794ded7ff253ea9d..07d0cc7cccd120cb78e26615dab5748473c083cd 100644 (file)
@@ -344,3 +344,4 @@ func LoadGetFinalPathNameByHandle() error {
 //sys  DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
 
 //sys  RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036
+//sys  GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err error) = kernel32.GenerateConsoleCtrlEvent
index aaad4a5b94b7e5f7a277c021790a2d94dbb09bf9..4de662cc0801b022f21af8670f1ee10c79e34f8e 100644 (file)
@@ -54,6 +54,7 @@ var (
        procSetTokenInformation          = modadvapi32.NewProc("SetTokenInformation")
        procSystemFunction036            = modadvapi32.NewProc("SystemFunction036")
        procGetAdaptersAddresses         = modiphlpapi.NewProc("GetAdaptersAddresses")
+       procGenerateConsoleCtrlEvent     = modkernel32.NewProc("GenerateConsoleCtrlEvent")
        procGetACP                       = modkernel32.NewProc("GetACP")
        procGetComputerNameExW           = modkernel32.NewProc("GetComputerNameExW")
        procGetConsoleCP                 = modkernel32.NewProc("GetConsoleCP")
@@ -161,6 +162,14 @@ func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapter
        return
 }
 
+func GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err error) {
+       r1, _, e1 := syscall.Syscall(procGenerateConsoleCtrlEvent.Addr(), 2, uintptr(ctrlEvent), uintptr(processGroupID), 0)
+       if r1 == 0 {
+               err = errnoErr(e1)
+       }
+       return
+}
+
 func GetACP() (acp uint32) {
        r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0)
        acp = uint32(r0)
index 8e31e47190feaf374ed0b6163f49e5b289018903..503867f9c897bf7f5d4fc20f2134d5ca4522d511 100644 (file)
@@ -7,6 +7,7 @@
 package exec_test
 
 import (
+       "internal/testenv"
        "io"
        "os"
        "os/exec"
@@ -54,3 +55,20 @@ func TestNoInheritHandles(t *testing.T) {
                t.Fatalf("got exit code %d; want 88", exitError.ExitCode())
        }
 }
+
+func TestErrProcessDone(t *testing.T) {
+       testenv.MustHaveGoBuild(t)
+       // On Windows, ProcAttr cannot be empty
+       p, err := os.StartProcess(testenv.GoToolPath(t), []string{""},
+               &os.ProcAttr{Dir: "", Env: nil, Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, Sys: nil})
+       if err != nil {
+               t.Errorf("starting test process: %v", err)
+       }
+       _, err = p.Wait()
+       if err != nil {
+               t.Errorf("Wait: %v", err)
+       }
+       if got := p.Signal(os.Kill); got != os.ErrProcessDone {
+               t.Fatalf("got %v want %v", got, os.ErrProcessDone)
+       }
+}
index e1e7d53a27af06201e3b6713e2ee8ebaf16d459c..3dc18a84bd9921fb70773d959b22aba0ba5d7d15 100644 (file)
@@ -15,9 +15,7 @@ import (
 
 // The only signal values guaranteed to be present in the os package on all
 // systems are os.Interrupt (send the process an interrupt) and os.Kill (force
-// the process to exit). On Windows, sending os.Interrupt to a process with
-// os.Process.Signal is not implemented; it will return an error instead of
-// sending a signal.
+// the process to exit).
 var (
        Interrupt Signal = syscall.SIGINT
        Kill      Signal = syscall.SIGKILL
index 239bed198f7fd020f25de0d3f240d1ed7428d1ef..bc232e0a00470eb2751aa3749ff2aecd54225253 100644 (file)
@@ -47,13 +47,14 @@ func (p *Process) wait() (ps *ProcessState, err error) {
 
 func (p *Process) signal(sig Signal) error {
        handle := atomic.LoadUintptr(&p.handle)
-       if handle == uintptr(syscall.InvalidHandle) {
-               return syscall.EINVAL
-       }
        if p.done() {
                return ErrProcessDone
        }
-       if sig == Kill {
+       s, ok := sig.(syscall.Signal)
+       if !ok {
+               return syscall.EWINDOWS
+       }
+       if s == syscall.SIGKILL {
                var terminationHandle syscall.Handle
                e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0)
                if e != nil {
@@ -61,11 +62,17 @@ func (p *Process) signal(sig Signal) error {
                }
                runtime.KeepAlive(p)
                defer syscall.CloseHandle(terminationHandle)
-               e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
+               e = syscall.TerminateProcess(terminationHandle, 1)
                return NewSyscallError("TerminateProcess", e)
        }
-       // TODO(rsc): Handle Interrupt too?
-       return syscall.Errno(syscall.EWINDOWS)
+       if s == syscall.SIGINT {
+               e := windows.GenerateConsoleCtrlEvent(syscall.CTRL_BREAK_EVENT, uint32(p.Pid))
+               if e != nil {
+                       return NewSyscallError("GenerateConsoleCtrlEvent", e)
+               }
+               return nil
+       }
+       return syscall.EWINDOWS
 }
 
 func (p *Process) release() error {
index 9b145515726c7ec820dbe2a0f151a2ce1f6c0981..89c072ca6e87c872e239271eee926407ac7a3262 100644 (file)
@@ -15,21 +15,6 @@ import (
        "time"
 )
 
-func sendCtrlBreak(t *testing.T, pid int) {
-       d, e := syscall.LoadDLL("kernel32.dll")
-       if e != nil {
-               t.Fatalf("LoadDLL: %v\n", e)
-       }
-       p, e := d.FindProc("GenerateConsoleCtrlEvent")
-       if e != nil {
-               t.Fatalf("FindProc: %v\n", e)
-       }
-       r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
-       if r == 0 {
-               t.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
-       }
-}
-
 func TestCtrlBreak(t *testing.T) {
        // create source file
        const source = `
@@ -90,7 +75,7 @@ func main() {
        }
        go func() {
                time.Sleep(1 * time.Second)
-               sendCtrlBreak(t, cmd.Process.Pid)
+               cmd.Process.Signal(os.Interrupt)
        }()
        err = cmd.Wait()
        if err != nil {
index add23cd2926996a03e7d559eac87dca788352c81..1f329f4548d5cd49cfbc3d571edd22903bcb126e 100644 (file)
@@ -59,22 +59,6 @@ func TestVectoredHandlerDontCrashOnLibrary(t *testing.T) {
        }
 }
 
-func sendCtrlBreak(pid int) error {
-       kernel32, err := syscall.LoadDLL("kernel32.dll")
-       if err != nil {
-               return fmt.Errorf("LoadDLL: %v\n", err)
-       }
-       generateEvent, err := kernel32.FindProc("GenerateConsoleCtrlEvent")
-       if err != nil {
-               return fmt.Errorf("FindProc: %v\n", err)
-       }
-       result, _, err := generateEvent.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
-       if result == 0 {
-               return fmt.Errorf("GenerateConsoleCtrlEvent: %v\n", err)
-       }
-       return nil
-}
-
 // TestCtrlHandler tests that Go can gracefully handle closing the console window.
 // See https://golang.org/issues/41884.
 func TestCtrlHandler(t *testing.T) {
@@ -183,7 +167,7 @@ func TestLibraryCtrlHandler(t *testing.T) {
                } else if strings.TrimSpace(line) != "ready" {
                        errCh <- fmt.Errorf("unexpected message: %v", line)
                } else {
-                       errCh <- sendCtrlBreak(cmd.Process.Pid)
+                       errCh <- cmd.Process.Signal(syscall.SIGINT)
                }
        }()