os: add Process.Kill and Process.Signal R=alex.brainman, r, rsc, krasin, iant, rsc, r CC=golang-dev https://golang.org/cl/4437091
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile index c781df7..497e5a9 100644 --- a/src/pkg/os/Makefile +++ b/src/pkg/os/Makefile
@@ -27,6 +27,7 @@ sys_bsd.go\ exec_posix.go\ exec_unix.go\ + signal_unix.go\ GOFILES_darwin=\ dir_unix.go\ @@ -38,6 +39,7 @@ sys_bsd.go\ exec_posix.go\ exec_unix.go\ + signal_unix.go\ GOFILES_linux=\ dir_unix.go\ @@ -49,6 +51,7 @@ sys_linux.go\ exec_posix.go\ exec_unix.go\ + signal_unix.go\ GOFILES_windows=\ dir_windows.go\ @@ -60,6 +63,7 @@ sys_windows.go\ exec_posix.go\ exec_windows.go\ + signal_windows.go\ GOFILES_plan9=\ dir_plan9.go\ @@ -72,4 +76,12 @@ GOFILES+=$(GOFILES_$(GOOS)) +CLEANFILES+=signal_unix.go signal_windows.go + include ../../Make.pkg + +signal_unix.go: ../syscall/zerrors_$(GOOS)_$(GOARCH).go + ./mkunixsignals.sh $< > $@ || rm -f $@ + +signal_windows.go: ../syscall/ztypes_$(GOOS)_$(GOARCH).go + ./mkunixsignals.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/exec_posix.go b/src/pkg/os/exec_posix.go index 9102dc0..bf992ef 100644 --- a/src/pkg/os/exec_posix.go +++ b/src/pkg/os/exec_posix.go
@@ -4,7 +4,25 @@ package os -import "syscall" +import ( + "runtime" + "syscall" +) + +// A Signal can represent any operating system signal. +type Signal interface { + String() string +} + +type UnixSignal int32 + +func (sig UnixSignal) String() string { + s := runtime.Signame(int32(sig)) + if len(s) > 0 { + return s + } + return "UnixSignal" +} // StartProcess starts a new process with the program, arguments and attributes // specified by name, argv and attr. @@ -34,6 +52,11 @@ return newProcess(pid, h), nil } +// Kill causes the Process to exit immediately. +func (p *Process) Kill() Error { + return p.Signal(SIGKILL) +} + // Exec replaces the current process with an execution of the // named binary, with arguments argv and environment envv. // If successful, Exec never returns. If it fails, it returns an Error.
diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go index 8990d6a..cf5ea9b 100644 --- a/src/pkg/os/exec_unix.go +++ b/src/pkg/os/exec_unix.go
@@ -45,6 +45,14 @@ return w, nil } +// Signal sends a signal to the Process. +func (p *Process) Signal(sig Signal) Error { + if e := syscall.Kill(p.Pid, int(sig.(UnixSignal))); e != 0 { + return Errno(e) + } + return nil +} + // Release releases any resources associated with the Process. func (p *Process) Release() Error { // NOOP for unix.
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go index ae8ffea..bac33b9 100644 --- a/src/pkg/os/exec_windows.go +++ b/src/pkg/os/exec_windows.go
@@ -20,13 +20,23 @@ return nil, ErrorString("os: unexpected result from WaitForSingleObject") } var ec uint32 - e = syscall.GetExitCodeProcess(uint32(p.handle), &ec) + e = syscall.GetExitCodeProcess(int32(p.handle), &ec) if e != 0 { return nil, NewSyscallError("GetExitCodeProcess", e) } return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil } +// Signal sends a signal to the Process. +func (p *Process) Signal(sig Signal) Error { + switch sig.(UnixSignal) { + case SIGKILL: + e := syscall.TerminateProcess(int32(p.handle), 1) + return NewSyscallError("TerminateProcess", e) + } + return Errno(syscall.EWINDOWS) +} + func (p *Process) Release() Error { if p.handle == -1 { return EINVAL
diff --git a/src/pkg/os/signal/mkunix.sh b/src/pkg/os/mkunixsignals.sh similarity index 96% rename from src/pkg/os/signal/mkunix.sh rename to src/pkg/os/mkunixsignals.sh index 653b016..6ec764c 100755 --- a/src/pkg/os/signal/mkunix.sh +++ b/src/pkg/os/mkunixsignals.sh
@@ -8,7 +8,7 @@ echo cat <<EOH -package signal +package os import ( "syscall"
diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile index 013b91a..26f5876 100644 --- a/src/pkg/os/signal/Makefile +++ b/src/pkg/os/signal/Makefile
@@ -7,11 +7,5 @@ TARG=os/signal GOFILES=\ signal.go\ - unix.go\ - -CLEANFILES+=unix.go include ../../../Make.pkg - -unix.go: ../../syscall/zerrors_$(GOOS)_$(GOARCH).go - ./mkunix.sh $< > $@ || rm -f $@
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go index 666c03e..520f3f8 100644 --- a/src/pkg/os/signal/signal.go +++ b/src/pkg/os/signal/signal.go
@@ -6,35 +6,20 @@ package signal import ( + "os" "runtime" - "strconv" ) -// A Signal can represent any operating system signal. -type Signal interface { - String() string -} - -type UnixSignal int32 - -func (sig UnixSignal) String() string { - s := runtime.Signame(int32(sig)) - if len(s) > 0 { - return s - } - return "Signal " + strconv.Itoa(int(sig)) -} - // Incoming is the global signal channel. // All signals received by the program will be delivered to this channel. -var Incoming <-chan Signal +var Incoming <-chan os.Signal -func process(ch chan<- Signal) { +func process(ch chan<- os.Signal) { for { var mask uint32 = runtime.Sigrecv() for sig := uint(0); sig < 32; sig++ { if mask&(1<<sig) != 0 { - ch <- UnixSignal(sig) + ch <- os.UnixSignal(sig) } } } @@ -42,7 +27,7 @@ func init() { runtime.Siginit() - ch := make(chan Signal) // Done here so Incoming can have type <-chan Signal + ch := make(chan os.Signal) // Done here so Incoming can have type <-chan Signal Incoming = ch go process(ch) }
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go index f2679f1..00eb295 100644 --- a/src/pkg/os/signal/signal_test.go +++ b/src/pkg/os/signal/signal_test.go
@@ -5,6 +5,7 @@ package signal import ( + "os" "syscall" "testing" ) @@ -13,7 +14,7 @@ // Send this process a SIGHUP. syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGHUP, 0) - if sig := (<-Incoming).(UnixSignal); sig != SIGHUP { - t.Errorf("signal was %v, want %v", sig, SIGHUP) + if sig := (<-Incoming).(os.UnixSignal); sig != os.SIGHUP { + t.Errorf("signal was %v, want %v", sig, os.SIGHUP) } }
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go index bb93533..d01664d 100644 --- a/src/pkg/syscall/syscall_windows.go +++ b/src/pkg/syscall/syscall_windows.go
@@ -141,8 +141,9 @@ //sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (errno int) //sys CancelIo(s uint32) (errno int) //sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (errno int) = CreateProcessW -//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) -//sys GetExitCodeProcess(handle uint32, exitcode *uint32) (errno int) +//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno int) +//sys TerminateProcess(handle int32, exitcode uint32) (errno int) +//sys GetExitCodeProcess(handle int32, exitcode *uint32) (errno int) //sys GetStartupInfo(startupInfo *StartupInfo) (errno int) = GetStartupInfoW //sys GetCurrentProcess() (pseudoHandle int32, errno int) //sys DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (errno int) @@ -697,10 +698,6 @@ // TODO(brainman): fix all needed for os -const ( - SIGTRAP = 5 -) - func Getpid() (pid int) { return -1 } func Getppid() (ppid int) { return -1 }
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go index ce36ab6..447b090 100644 --- a/src/pkg/syscall/zsyscall_windows_386.go +++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -46,6 +46,7 @@ procCancelIo = getSysProcAddr(modkernel32, "CancelIo") procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW") procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess") + procTerminateProcess = getSysProcAddr(modkernel32, "TerminateProcess") procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess") procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW") procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess") @@ -542,7 +543,7 @@ return } -func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) { +func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle int32, errno int) { var _p0 uint32 if inheritHandle { _p0 = 1 @@ -550,7 +551,7 @@ _p0 = 0 } r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid)) - handle = uint32(r0) + handle = int32(r0) if handle == 0 { if e1 != 0 { errno = int(e1) @@ -563,7 +564,21 @@ return } -func GetExitCodeProcess(handle uint32, exitcode *uint32) (errno int) { +func TerminateProcess(handle int32, exitcode uint32) (errno int) { + r1, _, e1 := Syscall(procTerminateProcess, 2, uintptr(handle), uintptr(exitcode), 0) + if int(r1) == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = EINVAL + } + } else { + errno = 0 + } + return +} + +func GetExitCodeProcess(handle int32, exitcode *uint32) (errno int) { r1, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) if int(r1) == 0 { if e1 != 0 {
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go index 7b15ea4..b04fea5 100644 --- a/src/pkg/syscall/ztypes_windows_386.go +++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -49,6 +49,23 @@ ) const ( + // More invented values for signals + SIGHUP = 0x1 + SIGINT = 0x2 + SIGQUIT = 0x3 + SIGILL = 0x4 + SIGTRAP = 0x5 + SIGABRT = 0x6 + SIGBUS = 0x7 + SIGFPE = 0x8 + SIGKILL = 0x9 + SIGSEGV = 0xb + SIGPIPE = 0xd + SIGALRM = 0xe + SIGTERM = 0xf +) + +const ( GENERIC_READ = 0x80000000 GENERIC_WRITE = 0x40000000 GENERIC_EXECUTE = 0x20000000