exec_windows.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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. "syscall"
  9. "time"
  10. "unsafe"
  11. )
  12. func (p *Process) wait() (ps *ProcessState, err error) {
  13. s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
  14. switch s {
  15. case syscall.WAIT_OBJECT_0:
  16. break
  17. case syscall.WAIT_FAILED:
  18. return nil, NewSyscallError("WaitForSingleObject", e)
  19. default:
  20. return nil, errors.New("os: unexpected result from WaitForSingleObject")
  21. }
  22. var ec uint32
  23. e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
  24. if e != nil {
  25. return nil, NewSyscallError("GetExitCodeProcess", e)
  26. }
  27. var u syscall.Rusage
  28. e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
  29. if e != nil {
  30. return nil, NewSyscallError("GetProcessTimes", e)
  31. }
  32. p.setDone()
  33. // NOTE(brainman): It seems that sometimes process is not dead
  34. // when WaitForSingleObject returns. But we do not know any
  35. // other way to wait for it. Sleeping for a while seems to do
  36. // the trick sometimes. So we will sleep and smell the roses.
  37. defer time.Sleep(5 * time.Millisecond)
  38. defer p.Release()
  39. return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
  40. }
  41. func terminateProcess(pid, exitcode int) error {
  42. h, e := syscall.OpenProcess(syscall.PROCESS_TERMINATE, false, uint32(pid))
  43. if e != nil {
  44. return NewSyscallError("OpenProcess", e)
  45. }
  46. defer syscall.CloseHandle(h)
  47. e = syscall.TerminateProcess(h, uint32(exitcode))
  48. return NewSyscallError("TerminateProcess", e)
  49. }
  50. func (p *Process) signal(sig Signal) error {
  51. if p.handle == uintptr(syscall.InvalidHandle) {
  52. return syscall.EINVAL
  53. }
  54. if p.done() {
  55. return errors.New("os: process already finished")
  56. }
  57. if sig == Kill {
  58. return terminateProcess(p.Pid, 1)
  59. }
  60. // TODO(rsc): Handle Interrupt too?
  61. return syscall.Errno(syscall.EWINDOWS)
  62. }
  63. func (p *Process) release() error {
  64. if p.handle == uintptr(syscall.InvalidHandle) {
  65. return syscall.EINVAL
  66. }
  67. e := syscall.CloseHandle(syscall.Handle(p.handle))
  68. if e != nil {
  69. return NewSyscallError("CloseHandle", e)
  70. }
  71. p.handle = uintptr(syscall.InvalidHandle)
  72. // no need for a finalizer anymore
  73. runtime.SetFinalizer(p, nil)
  74. return nil
  75. }
  76. func findProcess(pid int) (p *Process, err error) {
  77. const da = syscall.STANDARD_RIGHTS_READ |
  78. syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE
  79. h, e := syscall.OpenProcess(da, false, uint32(pid))
  80. if e != nil {
  81. return nil, NewSyscallError("OpenProcess", e)
  82. }
  83. return newProcess(pid, uintptr(h)), nil
  84. }
  85. func init() {
  86. var argc int32
  87. cmd := syscall.GetCommandLine()
  88. argv, e := syscall.CommandLineToArgv(cmd, &argc)
  89. if e != nil {
  90. return
  91. }
  92. defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
  93. Args = make([]string, argc)
  94. for i, v := range (*argv)[:argc] {
  95. Args[i] = string(syscall.UTF16ToString((*v)[:]))
  96. }
  97. }
  98. func ftToDuration(ft *syscall.Filetime) time.Duration {
  99. n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals
  100. return time.Duration(n*100) * time.Nanosecond
  101. }
  102. func (p *ProcessState) userTime() time.Duration {
  103. return ftToDuration(&p.rusage.UserTime)
  104. }
  105. func (p *ProcessState) systemTime() time.Duration {
  106. return ftToDuration(&p.rusage.KernelTime)
  107. }