Source file
src/os/exec_windows.go
1
2
3
4
5 package os
6
7 import (
8 "errors"
9 "internal/syscall/windows"
10 "runtime"
11 "syscall"
12 "time"
13 )
14
15
16
17
18 func (p *Process) wait() (ps *ProcessState, err error) {
19 handle, status := p.handleTransientAcquire()
20 switch status {
21 case statusDone:
22 return nil, ErrProcessDone
23 case statusReleased:
24 return nil, syscall.EINVAL
25 }
26 defer p.handleTransientRelease()
27
28 s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
29 switch s {
30 case syscall.WAIT_OBJECT_0:
31 break
32 case syscall.WAIT_FAILED:
33 return nil, NewSyscallError("WaitForSingleObject", e)
34 default:
35 return nil, errors.New("os: unexpected result from WaitForSingleObject")
36 }
37 var ec uint32
38 e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec)
39 if e != nil {
40 return nil, NewSyscallError("GetExitCodeProcess", e)
41 }
42 var u syscall.Rusage
43 e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
44 if e != nil {
45 return nil, NewSyscallError("GetProcessTimes", e)
46 }
47 defer p.Release()
48 return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
49 }
50
51 func (p *Process) signal(sig Signal) error {
52 handle, status := p.handleTransientAcquire()
53 switch status {
54 case statusDone:
55 return ErrProcessDone
56 case statusReleased:
57 return syscall.EINVAL
58 }
59 defer p.handleTransientRelease()
60
61 if sig == Kill {
62 var terminationHandle syscall.Handle
63 e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0)
64 if e != nil {
65 return NewSyscallError("DuplicateHandle", e)
66 }
67 runtime.KeepAlive(p)
68 defer syscall.CloseHandle(terminationHandle)
69 e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
70 return NewSyscallError("TerminateProcess", e)
71 }
72
73 return syscall.Errno(syscall.EWINDOWS)
74 }
75
76 func (p *Process) release() error {
77
78
79
80
81
82 if old := p.handlePersistentRelease(statusReleased); old == statusReleased {
83 return syscall.EINVAL
84 }
85
86
87 runtime.SetFinalizer(p, nil)
88 return nil
89 }
90
91 func (p *Process) closeHandle() {
92 syscall.CloseHandle(syscall.Handle(p.handle))
93 }
94
95 func findProcess(pid int) (p *Process, err error) {
96 const da = syscall.STANDARD_RIGHTS_READ |
97 syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
98 h, e := syscall.OpenProcess(da, false, uint32(pid))
99 if e != nil {
100 return nil, NewSyscallError("OpenProcess", e)
101 }
102 return newHandleProcess(pid, uintptr(h)), nil
103 }
104
105 func init() {
106 cmd := windows.UTF16PtrToString(syscall.GetCommandLine())
107 if len(cmd) == 0 {
108 arg0, _ := Executable()
109 Args = []string{arg0}
110 } else {
111 Args = commandLineToArgv(cmd)
112 }
113 }
114
115
116 func appendBSBytes(b []byte, n int) []byte {
117 for ; n > 0; n-- {
118 b = append(b, '\\')
119 }
120 return b
121 }
122
123
124
125 func readNextArg(cmd string) (arg []byte, rest string) {
126 var b []byte
127 var inquote bool
128 var nslash int
129 for ; len(cmd) > 0; cmd = cmd[1:] {
130 c := cmd[0]
131 switch c {
132 case ' ', '\t':
133 if !inquote {
134 return appendBSBytes(b, nslash), cmd[1:]
135 }
136 case '"':
137 b = appendBSBytes(b, nslash/2)
138 if nslash%2 == 0 {
139
140
141
142 if inquote && len(cmd) > 1 && cmd[1] == '"' {
143 b = append(b, c)
144 cmd = cmd[1:]
145 }
146 inquote = !inquote
147 } else {
148 b = append(b, c)
149 }
150 nslash = 0
151 continue
152 case '\\':
153 nslash++
154 continue
155 }
156 b = appendBSBytes(b, nslash)
157 nslash = 0
158 b = append(b, c)
159 }
160 return appendBSBytes(b, nslash), ""
161 }
162
163
164
165
166 func commandLineToArgv(cmd string) []string {
167 var args []string
168 for len(cmd) > 0 {
169 if cmd[0] == ' ' || cmd[0] == '\t' {
170 cmd = cmd[1:]
171 continue
172 }
173 var arg []byte
174 arg, cmd = readNextArg(cmd)
175 args = append(args, string(arg))
176 }
177 return args
178 }
179
180 func ftToDuration(ft *syscall.Filetime) time.Duration {
181 n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
182 return time.Duration(n*100) * time.Nanosecond
183 }
184
185 func (p *ProcessState) userTime() time.Duration {
186 return ftToDuration(&p.rusage.UserTime)
187 }
188
189 func (p *ProcessState) systemTime() time.Duration {
190 return ftToDuration(&p.rusage.KernelTime)
191 }
192
View as plain text