Source file src/os/exec_windows.go
1
2
3
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
39
40
41
42
43 defer time.Sleep(5 * time.Millisecond)
44 defer p.Release()
45 return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
46 }
47
48 func terminateProcess(pid, exitcode int) error {
49 h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid))
50 if e != nil {
51 return NewSyscallError("OpenProcess", e)
52 }
53 defer syscall.CloseHandle(h)
54 e = syscall.TerminateProcess(h, uint32(exitcode))
55 return NewSyscallError("TerminateProcess", e)
56 }
57
58 func (p *Process) signal(sig Signal) error {
59 handle := atomic.LoadUintptr(&p.handle)
60 if handle == uintptr(syscall.InvalidHandle) {
61 return syscall.EINVAL
62 }
63 if p.done() {
64 return errors.New("os: process already finished")
65 }
66 if sig == Kill {
67 err := terminateProcess(p.Pid, 1)
68 runtime.KeepAlive(p)
69 return err
70 }
71
72 return syscall.Errno(syscall.EWINDOWS)
73 }
74
75 func (p *Process) release() error {
76 handle := atomic.LoadUintptr(&p.handle)
77 if handle == uintptr(syscall.InvalidHandle) {
78 return syscall.EINVAL
79 }
80 e := syscall.CloseHandle(syscall.Handle(handle))
81 if e != nil {
82 return NewSyscallError("CloseHandle", e)
83 }
84 atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle))
85
86 runtime.SetFinalizer(p, nil)
87 return nil
88 }
89
90 func findProcess(pid int) (p *Process, err error) {
91 const da = syscall.STANDARD_RIGHTS_READ |
92 syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
93 h, e := syscall.OpenProcess(da, false, uint32(pid))
94 if e != nil {
95 return nil, NewSyscallError("OpenProcess", e)
96 }
97 return newProcess(pid, uintptr(h)), nil
98 }
99
100 func init() {
101 p := syscall.GetCommandLine()
102 cmd := syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(p))[:])
103 if len(cmd) == 0 {
104 arg0, _ := Executable()
105 Args = []string{arg0}
106 } else {
107 Args = commandLineToArgv(cmd)
108 }
109 }
110
111
112 func appendBSBytes(b []byte, n int) []byte {
113 for ; n > 0; n-- {
114 b = append(b, '\\')
115 }
116 return b
117 }
118
119
120
121 func readNextArg(cmd string) (arg []byte, rest string) {
122 var b []byte
123 var inquote bool
124 var nslash int
125 for ; len(cmd) > 0; cmd = cmd[1:] {
126 c := cmd[0]
127 switch c {
128 case ' ', '\t':
129 if !inquote {
130 return appendBSBytes(b, nslash), cmd[1:]
131 }
132 case '"':
133 b = appendBSBytes(b, nslash/2)
134 if nslash%2 == 0 {
135
136
137
138 if inquote && len(cmd) > 1 && cmd[1] == '"' {
139 b = append(b, c)
140 cmd = cmd[1:]
141 }
142 inquote = !inquote
143 } else {
144 b = append(b, c)
145 }
146 nslash = 0
147 continue
148 case '\\':
149 nslash++
150 continue
151 }
152 b = appendBSBytes(b, nslash)
153 nslash = 0
154 b = append(b, c)
155 }
156 return appendBSBytes(b, nslash), ""
157 }
158
159
160
161
162 func commandLineToArgv(cmd string) []string {
163 var args []string
164 for len(cmd) > 0 {
165 if cmd[0] == ' ' || cmd[0] == '\t' {
166 cmd = cmd[1:]
167 continue
168 }
169 var arg []byte
170 arg, cmd = readNextArg(cmd)
171 args = append(args, string(arg))
172 }
173 return args
174 }
175
176 func ftToDuration(ft *syscall.Filetime) time.Duration {
177 n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
178 return time.Duration(n*100) * time.Nanosecond
179 }
180
181 func (p *ProcessState) userTime() time.Duration {
182 return ftToDuration(&p.rusage.UserTime)
183 }
184
185 func (p *ProcessState) systemTime() time.Duration {
186 return ftToDuration(&p.rusage.KernelTime)
187 }
188
View as plain text