github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/drivers/shared/executor/executor_windows.go (about)

     1  //go:build windows
     2  
     3  package executor
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"syscall"
     9  )
    10  
    11  // configure new process group for child process
    12  func (e *UniversalExecutor) setNewProcessGroup() error {
    13  	// We need to check that as build flags includes windows for this file
    14  	if e.childCmd.SysProcAttr == nil {
    15  		e.childCmd.SysProcAttr = &syscall.SysProcAttr{}
    16  	}
    17  	e.childCmd.SysProcAttr.CreationFlags = syscall.CREATE_NEW_PROCESS_GROUP
    18  	return nil
    19  }
    20  
    21  // Cleanup any still hanging user processes
    22  func (e *UniversalExecutor) killProcessTree(proc *os.Process) error {
    23  	// We must first verify if the process is still running.
    24  	// (Windows process often lingered around after being reported as killed).
    25  	handle, err := syscall.OpenProcess(syscall.PROCESS_TERMINATE|syscall.SYNCHRONIZE|syscall.PROCESS_QUERY_INFORMATION, false, uint32(proc.Pid))
    26  	if err != nil {
    27  		return os.NewSyscallError("OpenProcess", err)
    28  	}
    29  	defer syscall.CloseHandle(handle)
    30  
    31  	result, err := syscall.WaitForSingleObject(syscall.Handle(handle), 0)
    32  
    33  	switch result {
    34  	case syscall.WAIT_OBJECT_0:
    35  		return nil
    36  	case syscall.WAIT_TIMEOUT:
    37  		// Process still running.  Just kill it.
    38  		return proc.Kill()
    39  	default:
    40  		return os.NewSyscallError("WaitForSingleObject", err)
    41  	}
    42  }
    43  
    44  // Send a Ctrl-Break signal for shutting down the process,
    45  // like in https://golang.org/src/os/signal/signal_windows_test.go
    46  func sendCtrlBreak(pid int) error {
    47  	dll, err := syscall.LoadDLL("kernel32.dll")
    48  	if err != nil {
    49  		return fmt.Errorf("Error loading kernel32.dll: %v", err)
    50  	}
    51  	proc, err := dll.FindProc("GenerateConsoleCtrlEvent")
    52  	if err != nil {
    53  		return fmt.Errorf("Cannot find procedure GenerateConsoleCtrlEvent: %v", err)
    54  	}
    55  	result, _, err := proc.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
    56  	if result == 0 {
    57  		return fmt.Errorf("Error sending ctrl-break event: %v", err)
    58  	}
    59  	return nil
    60  }
    61  
    62  // Send the process a Ctrl-Break event, allowing it to shutdown by itself
    63  // before being Terminate.
    64  func (e *UniversalExecutor) shutdownProcess(_ os.Signal, proc *os.Process) error {
    65  	if err := sendCtrlBreak(proc.Pid); err != nil {
    66  		return fmt.Errorf("executor shutdown error: %v", err)
    67  	}
    68  	e.logger.Debug("sent Ctrl-Break to process", "pid", proc.Pid)
    69  
    70  	return nil
    71  }