exec_windows.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  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. package os
  5. import (
  6. "errors"
  7. "internal/syscall/windows"
  8. "runtime"
  9. "sync/atomic"
  10. "syscall"
  11. "time"
  12. )
  13. func (p *Process) wait() (ps *ProcessState, err error) {
  14. handle := atomic.LoadUintptr(&p.handle)
  15. s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
  16. switch s {
  17. case syscall.WAIT_OBJECT_0:
  18. break
  19. case syscall.WAIT_FAILED:
  20. return nil, NewSyscallError("WaitForSingleObject", e)
  21. default:
  22. return nil, errors.New("os: unexpected result from WaitForSingleObject")
  23. }
  24. var ec uint32
  25. e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec)
  26. if e != nil {
  27. return nil, NewSyscallError("GetExitCodeProcess", e)
  28. }
  29. var u syscall.Rusage
  30. e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
  31. if e != nil {
  32. return nil, NewSyscallError("GetProcessTimes", e)
  33. }
  34. p.setDone()
  35. // NOTE(brainman): It seems that sometimes process is not dead
  36. // when WaitForSingleObject returns. But we do not know any
  37. // other way to wait for it. Sleeping for a while seems to do
  38. // the trick sometimes.
  39. // See https://golang.org/issue/25965 for details.
  40. defer time.Sleep(5 * time.Millisecond)
  41. defer p.Release()
  42. return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
  43. }
  44. func (p *Process) signal(sig Signal) error {
  45. handle := atomic.LoadUintptr(&p.handle)
  46. if handle == uintptr(syscall.InvalidHandle) {
  47. return syscall.EINVAL
  48. }
  49. if p.done() {
  50. return ErrProcessDone
  51. }
  52. if sig == Kill {
  53. var terminationHandle syscall.Handle
  54. e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0)
  55. if e != nil {
  56. return NewSyscallError("DuplicateHandle", e)
  57. }
  58. runtime.KeepAlive(p)
  59. defer syscall.CloseHandle(terminationHandle)
  60. e = syscall.TerminateProcess(syscall.Handle(terminationHandle), 1)
  61. return NewSyscallError("TerminateProcess", e)
  62. }
  63. // TODO(rsc): Handle Interrupt too?
  64. return syscall.Errno(syscall.EWINDOWS)
  65. }
  66. func (p *Process) release() error {
  67. handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle))
  68. if handle == uintptr(syscall.InvalidHandle) {
  69. return syscall.EINVAL
  70. }
  71. e := syscall.CloseHandle(syscall.Handle(handle))
  72. if e != nil {
  73. return NewSyscallError("CloseHandle", e)
  74. }
  75. // no need for a finalizer anymore
  76. runtime.SetFinalizer(p, nil)
  77. return nil
  78. }
  79. func findProcess(pid int) (p *Process, err error) {
  80. const da = syscall.STANDARD_RIGHTS_READ |
  81. syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
  82. h, e := syscall.OpenProcess(da, false, uint32(pid))
  83. if e != nil {
  84. return nil, NewSyscallError("OpenProcess", e)
  85. }
  86. return newProcess(pid, uintptr(h)), nil
  87. }
  88. func init() {
  89. cmd := windows.UTF16PtrToString(syscall.GetCommandLine())
  90. if len(cmd) == 0 {
  91. arg0, _ := Executable()
  92. Args = []string{arg0}
  93. } else {
  94. Args = commandLineToArgv(cmd)
  95. }
  96. }
  97. // appendBSBytes appends n '\\' bytes to b and returns the resulting slice.
  98. func appendBSBytes(b []byte, n int) []byte {
  99. for ; n > 0; n-- {
  100. b = append(b, '\\')
  101. }
  102. return b
  103. }
  104. // readNextArg splits command line string cmd into next
  105. // argument and command line remainder.
  106. func readNextArg(cmd string) (arg []byte, rest string) {
  107. var b []byte
  108. var inquote bool
  109. var nslash int
  110. for ; len(cmd) > 0; cmd = cmd[1:] {
  111. c := cmd[0]
  112. switch c {
  113. case ' ', '\t':
  114. if !inquote {
  115. return appendBSBytes(b, nslash), cmd[1:]
  116. }
  117. case '"':
  118. b = appendBSBytes(b, nslash/2)
  119. if nslash%2 == 0 {
  120. // use "Prior to 2008" rule from
  121. // http://daviddeley.com/autohotkey/parameters/parameters.htm
  122. // section 5.2 to deal with double double quotes
  123. if inquote && len(cmd) > 1 && cmd[1] == '"' {
  124. b = append(b, c)
  125. cmd = cmd[1:]
  126. }
  127. inquote = !inquote
  128. } else {
  129. b = append(b, c)
  130. }
  131. nslash = 0
  132. continue
  133. case '\\':
  134. nslash++
  135. continue
  136. }
  137. b = appendBSBytes(b, nslash)
  138. nslash = 0
  139. b = append(b, c)
  140. }
  141. return appendBSBytes(b, nslash), ""
  142. }
  143. // commandLineToArgv splits a command line into individual argument
  144. // strings, following the Windows conventions documented
  145. // at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
  146. func commandLineToArgv(cmd string) []string {
  147. var args []string
  148. for len(cmd) > 0 {
  149. if cmd[0] == ' ' || cmd[0] == '\t' {
  150. cmd = cmd[1:]
  151. continue
  152. }
  153. var arg []byte
  154. arg, cmd = readNextArg(cmd)
  155. args = append(args, string(arg))
  156. }
  157. return args
  158. }
  159. func ftToDuration(ft *syscall.Filetime) time.Duration {
  160. n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
  161. return time.Duration(n*100) * time.Nanosecond
  162. }
  163. func (p *ProcessState) userTime() time.Duration {
  164. return ftToDuration(&p.rusage.UserTime)
  165. }
  166. func (p *ProcessState) systemTime() time.Duration {
  167. return ftToDuration(&p.rusage.KernelTime)
  168. }