81 lines · 1.7 KB · Go
RawDownload
//go:build windows package cli import (	"fmt"	"os/exec"	"sync"	"unsafe" 	"golang.org/x/sys/windows") var commandJobs sync.Map func configureCommandGroup(cmd *exec.Cmd) {	job, err := windows.CreateJobObject(nil, nil)	if err != nil {		return	}	info := windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION{}	info.BasicLimitInformation.LimitFlags = windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE	if _, err := windows.SetInformationJobObject(		job,		windows.JobObjectExtendedLimitInformation,		uintptr(unsafe.Pointer(&info)),		uint32(unsafe.Sizeof(info)),	); err != nil {		_ = windows.CloseHandle(job)		return	}	commandJobs.Store(cmd, job)} func attachCommandGroup(cmd *exec.Cmd) error {	if cmd == nil || cmd.Process == nil {		return nil	}	value, ok := commandJobs.Load(cmd)	if !ok {		return nil	}	job, ok := value.(windows.Handle)	if !ok || job == 0 {		return nil	}	process, err := windows.OpenProcess(windows.PROCESS_SET_QUOTA|windows.PROCESS_TERMINATE, false, uint32(cmd.Process.Pid))	if err != nil {		cleanupCommandGroup(cmd)		return nil	}	defer windows.CloseHandle(process)	if err := windows.AssignProcessToJobObject(job, process); err != nil {		cleanupCommandGroup(cmd)		return nil	}	return nil} func killCommandGroup(cmd *exec.Cmd) {	if cmd == nil || cmd.Process == nil {		return	}	if value, ok := commandJobs.Load(cmd); ok {		if job, ok := value.(windows.Handle); ok && job != 0 {			_ = windows.TerminateJobObject(job, 1)		}	}	_ = exec.Command("taskkill", "/T", "/F", "/PID", fmt.Sprint(cmd.Process.Pid)).Run()	_ = cmd.Process.Kill()} func cleanupCommandGroup(cmd *exec.Cmd) {	value, ok := commandJobs.LoadAndDelete(cmd)	if !ok {		return	}	if job, ok := value.(windows.Handle); ok && job != 0 {		_ = windows.CloseHandle(job)	}}