PageRenderTime 26ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/libgo/go/os/exec_windows.go

https://gitlab.com/4144/gcc
Go | 187 lines | 157 code | 14 blank | 16 comment | 34 complexity | aae389ef916027e8b902fd4632b2d15e MD5 | raw file
  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. "runtime"
  8. "sync/atomic"
  9. "syscall"
  10. "time"
  11. "unsafe"
  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 terminateProcess(pid, exitcode int) error {
  45. h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid))
  46. if e != nil {
  47. return NewSyscallError("OpenProcess", e)
  48. }
  49. defer syscall.CloseHandle(h)
  50. e = syscall.TerminateProcess(h, uint32(exitcode))
  51. return NewSyscallError("TerminateProcess", e)
  52. }
  53. func (p *Process) signal(sig Signal) error {
  54. handle := atomic.LoadUintptr(&p.handle)
  55. if handle == uintptr(syscall.InvalidHandle) {
  56. return syscall.EINVAL
  57. }
  58. if p.done() {
  59. return errors.New("os: process already finished")
  60. }
  61. if sig == Kill {
  62. err := terminateProcess(p.Pid, 1)
  63. runtime.KeepAlive(p)
  64. return err
  65. }
  66. // TODO(rsc): Handle Interrupt too?
  67. return syscall.Errno(syscall.EWINDOWS)
  68. }
  69. func (p *Process) release() error {
  70. handle := atomic.LoadUintptr(&p.handle)
  71. if handle == uintptr(syscall.InvalidHandle) {
  72. return syscall.EINVAL
  73. }
  74. e := syscall.CloseHandle(syscall.Handle(handle))
  75. if e != nil {
  76. return NewSyscallError("CloseHandle", e)
  77. }
  78. atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle))
  79. // no need for a finalizer anymore
  80. runtime.SetFinalizer(p, nil)
  81. return nil
  82. }
  83. func findProcess(pid int) (p *Process, err error) {
  84. const da = syscall.STANDARD_RIGHTS_READ |
  85. syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
  86. h, e := syscall.OpenProcess(da, false, uint32(pid))
  87. if e != nil {
  88. return nil, NewSyscallError("OpenProcess", e)
  89. }
  90. return newProcess(pid, uintptr(h)), nil
  91. }
  92. func init() {
  93. p := syscall.GetCommandLine()
  94. cmd := syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(p))[:])
  95. if len(cmd) == 0 {
  96. arg0, _ := Executable()
  97. Args = []string{arg0}
  98. } else {
  99. Args = commandLineToArgv(cmd)
  100. }
  101. }
  102. // appendBSBytes appends n '\\' bytes to b and returns the resulting slice.
  103. func appendBSBytes(b []byte, n int) []byte {
  104. for ; n > 0; n-- {
  105. b = append(b, '\\')
  106. }
  107. return b
  108. }
  109. // readNextArg splits command line string cmd into next
  110. // argument and command line remainder.
  111. func readNextArg(cmd string) (arg []byte, rest string) {
  112. var b []byte
  113. var inquote bool
  114. var nslash int
  115. for ; len(cmd) > 0; cmd = cmd[1:] {
  116. c := cmd[0]
  117. switch c {
  118. case ' ', '\t':
  119. if !inquote {
  120. return appendBSBytes(b, nslash), cmd[1:]
  121. }
  122. case '"':
  123. b = appendBSBytes(b, nslash/2)
  124. if nslash%2 == 0 {
  125. // use "Prior to 2008" rule from
  126. // http://daviddeley.com/autohotkey/parameters/parameters.htm
  127. // section 5.2 to deal with double double quotes
  128. if inquote && len(cmd) > 1 && cmd[1] == '"' {
  129. b = append(b, c)
  130. cmd = cmd[1:]
  131. }
  132. inquote = !inquote
  133. } else {
  134. b = append(b, c)
  135. }
  136. nslash = 0
  137. continue
  138. case '\\':
  139. nslash++
  140. continue
  141. }
  142. b = appendBSBytes(b, nslash)
  143. nslash = 0
  144. b = append(b, c)
  145. }
  146. return appendBSBytes(b, nslash), ""
  147. }
  148. // commandLineToArgv splits a command line into individual argument
  149. // strings, following the Windows conventions documented
  150. // at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV
  151. func commandLineToArgv(cmd string) []string {
  152. var args []string
  153. for len(cmd) > 0 {
  154. if cmd[0] == ' ' || cmd[0] == '\t' {
  155. cmd = cmd[1:]
  156. continue
  157. }
  158. var arg []byte
  159. arg, cmd = readNextArg(cmd)
  160. args = append(args, string(arg))
  161. }
  162. return args
  163. }
  164. func ftToDuration(ft *syscall.Filetime) time.Duration {
  165. n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
  166. return time.Duration(n*100) * time.Nanosecond
  167. }
  168. func (p *ProcessState) userTime() time.Duration {
  169. return ftToDuration(&p.rusage.UserTime)
  170. }
  171. func (p *ProcessState) systemTime() time.Duration {
  172. return ftToDuration(&p.rusage.KernelTime)
  173. }