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.
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
)
20 case syscall
.WAIT_OBJECT_0
:
22 case syscall
.WAIT_FAILED
:
23 return nil, NewSyscallError("WaitForSingleObject", e
)
25 return nil, errors
.New("os: unexpected result from WaitForSingleObject")
28 e
= syscall
.GetExitCodeProcess(syscall
.Handle(handle
), &ec
)
30 return nil, NewSyscallError("GetExitCodeProcess", e
)
33 e
= syscall
.GetProcessTimes(syscall
.Handle(handle
), &u
.CreationTime
, &u
.ExitTime
, &u
.KernelTime
, &u
.UserTime
)
35 return nil, NewSyscallError("GetProcessTimes", e
)
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
)
44 return &ProcessState
{p
.Pid
, syscall
.WaitStatus
{ExitCode
: ec
}, &u
}, nil
47 func terminateProcess(pid
, exitcode
int) error
{
48 h
, e
:= syscall
.OpenProcess(syscall
.PROCESS_TERMINATE
, false, uint32(pid
))
50 return NewSyscallError("OpenProcess", e
)
52 defer syscall
.CloseHandle(h
)
53 e
= syscall
.TerminateProcess(h
, uint32(exitcode
))
54 return NewSyscallError("TerminateProcess", e
)
57 func (p
*Process
) signal(sig Signal
) error
{
58 handle
:= atomic
.LoadUintptr(&p
.handle
)
59 if handle
== uintptr(syscall
.InvalidHandle
) {
63 return errors
.New("os: process already finished")
66 err
:= terminateProcess(p
.Pid
, 1)
70 // TODO(rsc): Handle Interrupt too?
71 return syscall
.Errno(syscall
.EWINDOWS
)
74 func (p
*Process
) release() error
{
75 handle
:= atomic
.LoadUintptr(&p
.handle
)
76 if handle
== uintptr(syscall
.InvalidHandle
) {
79 e
:= syscall
.CloseHandle(syscall
.Handle(handle
))
81 return NewSyscallError("CloseHandle", e
)
83 atomic
.StoreUintptr(&p
.handle
, uintptr(syscall
.InvalidHandle
))
84 // no need for a finalizer anymore
85 runtime
.SetFinalizer(p
, nil)
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
))
94 return nil, NewSyscallError("OpenProcess", e
)
96 return newProcess(pid
, uintptr(h
)), nil
100 p
:= syscall
.GetCommandLine()
101 cmd
:= syscall
.UTF16ToString((*[0xffff]uint16)(unsafe
.Pointer(p
))[:])
103 arg0
, _
:= Executable()
104 Args
= []string{arg0
}
106 Args
= commandLineToArgv(cmd
)
110 // appendBSBytes appends n '\\' bytes to b and returns the resulting slice.
111 func appendBSBytes(b
[]byte, n
int) []byte {
118 // readNextArg splits command line string cmd into next
119 // argument and command line remainder.
120 func readNextArg(cmd
string) (arg
[]byte, rest
string) {
124 for ; len(cmd
) > 0; cmd
= cmd
[1:] {
129 return appendBSBytes(b
, nslash
), cmd
[1:]
132 b
= appendBSBytes(b
, nslash
/2)
134 // use "Prior to 2008" rule from
135 // http://daviddeley.com/autohotkey/parameters/parameters.htm
136 // section 5.2 to deal with double double quotes
137 if inquote
&& len(cmd
) > 1 && cmd
[1] == '"' {
151 b
= appendBSBytes(b
, nslash
)
155 return appendBSBytes(b
, nslash
), ""
158 // commandLineToArgv splits a command line into individual argument
159 // strings, following the Windows conventions documented
160 // at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
161 func commandLineToArgv(cmd
string) []string {
164 if cmd
[0] == ' ' || cmd
[0] == '\t' {
169 arg
, cmd
= readNextArg(cmd
)
170 args
= append(args
, string(arg
))
175 func ftToDuration(ft
*syscall
.Filetime
) time
.Duration
{
176 n
:= int64(ft
.HighDateTime
)<<32 + int64(ft
.LowDateTime
) // in 100-nanosecond intervals
177 return time
.Duration(n
*100) * time
.Nanosecond
180 func (p
*ProcessState
) userTime() time
.Duration
{
181 return ftToDuration(&p
.rusage
.UserTime
)
184 func (p
*ProcessState
) systemTime() time
.Duration
{
185 return ftToDuration(&p
.rusage
.KernelTime
)