github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/src/os/exec_windows.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os 6 7 import ( 8 "errors" 9 "runtime" 10 "sync/atomic" 11 "syscall" 12 "time" 13 "unsafe" 14 ) 15 16 func (p *Process) wait() (ps *ProcessState, err error) { 17 handle := atomic.LoadUintptr(&p.handle) 18 s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE) 19 switch s { 20 case syscall.WAIT_OBJECT_0: 21 break 22 case syscall.WAIT_FAILED: 23 return nil, NewSyscallError("WaitForSingleObject", e) 24 default: 25 return nil, errors.New("os: unexpected result from WaitForSingleObject") 26 } 27 var ec uint32 28 e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec) 29 if e != nil { 30 return nil, NewSyscallError("GetExitCodeProcess", e) 31 } 32 var u syscall.Rusage 33 e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime) 34 if e != nil { 35 return nil, NewSyscallError("GetProcessTimes", e) 36 } 37 p.setDone() 38 // NOTE(brainman): It seems that sometimes process is not dead 39 // when WaitForSingleObject returns. But we do not know any 40 // other way to wait for it. Sleeping for a while seems to do 41 // the trick sometimes. So we will sleep and smell the roses. 42 defer time.Sleep(5 * time.Millisecond) 43 defer p.Release() 44 return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil 45 } 46 47 func terminateProcess(pid, exitcode int) error { 48 h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid)) 49 if e != nil { 50 return NewSyscallError("OpenProcess", e) 51 } 52 defer syscall.CloseHandle(h) 53 e = syscall.TerminateProcess(h, uint32(exitcode)) 54 return NewSyscallError("TerminateProcess", e) 55 } 56 57 func (p *Process) signal(sig Signal) error { 58 handle := atomic.LoadUintptr(&p.handle) 59 if handle == uintptr(syscall.InvalidHandle) { 60 return syscall.EINVAL 61 } 62 if p.done() { 63 return errors.New("os: process already finished") 64 } 65 if sig == Kill { 66 err := terminateProcess(p.Pid, 1) 67 runtime.KeepAlive(p) 68 return err 69 } 70 // TODO(rsc): Handle Interrupt too? 71 return syscall.Errno(syscall.EWINDOWS) 72 } 73 74 func (p *Process) release() error { 75 handle := atomic.LoadUintptr(&p.handle) 76 if handle == uintptr(syscall.InvalidHandle) { 77 return syscall.EINVAL 78 } 79 e := syscall.CloseHandle(syscall.Handle(handle)) 80 if e != nil { 81 return NewSyscallError("CloseHandle", e) 82 } 83 atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle)) 84 // no need for a finalizer anymore 85 runtime.SetFinalizer(p, nil) 86 return nil 87 } 88 89 func findProcess(pid int) (p *Process, err error) { 90 const da = syscall.STANDARD_RIGHTS_READ | 91 syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE 92 h, e := syscall.OpenProcess(da, false, uint32(pid)) 93 if e != nil { 94 return nil, NewSyscallError("OpenProcess", e) 95 } 96 return newProcess(pid, uintptr(h)), nil 97 } 98 99 func init() { 100 var argc int32 101 cmd := syscall.GetCommandLine() 102 argv, e := syscall.CommandLineToArgv(cmd, &argc) 103 if e != nil { 104 return 105 } 106 defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv)))) 107 Args = make([]string, argc) 108 for i, v := range (*argv)[:argc] { 109 Args[i] = syscall.UTF16ToString((*v)[:]) 110 } 111 } 112 113 func ftToDuration(ft *syscall.Filetime) time.Duration { 114 n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals 115 return time.Duration(n*100) * time.Nanosecond 116 } 117 118 func (p *ProcessState) userTime() time.Duration { 119 return ftToDuration(&p.rusage.UserTime) 120 } 121 122 func (p *ProcessState) systemTime() time.Duration { 123 return ftToDuration(&p.rusage.KernelTime) 124 }