Documentation ¶
Overview ¶
Package graceful facilitates orderly shutdown of processes on Windows. It does this by injecting a thread into the target process that calls ExitProcess() from within the target process' address space.
This package is based on ideas put forth by Andrew Tucker in a Dr. Dobb's article published in 1999 titled "A Safer Alternative to TerminateProcess()": http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547
This package also draws inspiration from the git-for-windows implementation of the same idea: https://github.com/git-for-windows/msys2-runtime/pull/15/commits/e9cb332976cf6ba44d9f5fc0ed4f725ce43fe646
Example ¶
package main import ( "context" "fmt" "os" "os/exec" "time" "github.com/gentlemanautomaton/graceful" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() cmd := exec.Command("ping", "127.0.0.1") if err := cmd.Start(); err != nil { fmt.Printf("unable to start ping: %v\n", err) os.Exit(2) } fmt.Println("ping started") if err := graceful.Exit(ctx, cmd.Process.Pid, 2); err != nil { fmt.Printf("exit failed: %v\n", err) graceful.Terminate(cmd.Process.Pid, 2) // Forcefully end the process (but know that this won't kill child processes) os.Exit(2) } cmd.Wait() fmt.Println("ping exited") }
Output: ping started ping exited
Index ¶
Examples ¶
Constants ¶
const ( ProcessTerminate = 0x0001 // PROCESS_TERMINATE ProcessCreateThread = 0x0002 // PROCESS_CREATE_THREAD ProcessVMOperation = 0x0008 // PROCESS_VM_OPERATION ProcessVMRead = 0x0010 // PROCESS_VM_READ ProcessVMWrite = 0x0020 // PROCESS_VM_WRITE ProcessQueryInformation = 0x0400 // PROCESS_QUERY_INFORMATION ProcessCreateRemoteThread = ProcessCreateThread | ProcessQueryInformation | ProcessVMOperation | ProcessVMWrite | ProcessVMRead | ProcessTerminate )
These are win32 process security and access rights necessary to perform a call to CreateRemoteThread().
Reference: https://msdn.microsoft.com/library/ms682437
Variables ¶
var ( // ErrDifferentArch is returned when the target process has a different // architecture (x86 or x64) than the calling process. Both processes must // be of the same architecture for an exit to be performed. ErrDifferentArch = errors.New("target process architecture differs from the caller") )
Functions ¶
func Exit ¶
Exit attempts to force an exit within a target process. The process is identified by its process id. If successful, the process will exit with the given exit code.
Exit is more rude than sending a real SIGINT signal. Exit is less rude than Terminate.
Exit works by effectively calling os.Exit(code) within the target process, with all the caveats that would entail. It calls the ExitProcess() function in the win32 API.
If the calling process architecture differs from that of the target process, ErrDifferentArch will be returned.
The returned error will be nil if the process exited. If it is non-nil, the process may still be running. If the context has been cancelled the context's error may be returned.
TODO: Check to make sure the process is actually running first.
func ExitOrTerminate ¶
ExitOrTerminate attempts to use Exit to end a target process. If Exit fails or the context is cancelled, Terminate will be called.
FIXME: The termination portion of this function is not implemented yet.
func Terminate ¶
Terminate forcefully ends the target process. The process is identified by its process id. The process will be given no opportunity to execute a system shutdown or run any cleanup functions. Child processes will be orphaned.
TODO: Check to make sure the process is actually running first.
TODO: Kill the entire process tree of the target process.
Types ¶
This section is empty.