添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 5 package os 7 import ( 8 "errors" 9 "internal/syscall/windows" 10 "runtime" 11 "syscall" 12 "time" 13 ) 15 // Note that Process.mode is always modeHandle because Windows always requires 16 // a handle. A manually-created Process literal is not valid. 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() 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 } 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() 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 // TODO(rsc): Handle Interrupt too? 73 return syscall.Errno(syscall.EWINDOWS) 74 } 76 func (p *Process) release() error { 77 // Drop the Process' reference and mark handle unusable for 78 // future calls. 79 // 80 // The API on Windows expects EINVAL if Release is called multiple 81 // times. 82 if old := p.handlePersistentRelease(statusReleased); old == statusReleased { 83 return syscall.EINVAL 84 } 86 // no need for a finalizer anymore 87 runtime.SetFinalizer(p, nil) 88 return nil 89 } 91 func (p *Process) closeHandle() { 92 syscall.CloseHandle(syscall.Handle(p.handle)) 93 } 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 } 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 } 115 // appendBSBytes appends n '\\' bytes to b and returns the resulting slice. 116 func appendBSBytes(b []byte, n int) []byte { 117 for ; n > 0; n-- { 118 b = append(b, '\\') 119 } 120 return b 121 } 123 // readNextArg splits command line string cmd into next 124 // argument and command line remainder. 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 // use "Prior to 2008" rule from 140 // http://daviddeley.com/autohotkey/parameters/parameters.htm 141 // section 5.2 to deal with double double quotes 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 } 163 // commandLineToArgv splits a command line into individual argument 164 // strings, following the Windows conventions documented 165 // at http://daviddeley.com/autohotkey/parameters/parameters.htm#WINARGV 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 } 180 func ftToDuration(ft *syscall.Filetime) time.Duration { 181 n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals 182 return time.Duration(n*100) * time.Nanosecond 183 } 185 func (p *ProcessState) userTime() time.Duration { 186 return ftToDuration(&p.rusage.UserTime) 187 } 189 func (p *ProcessState) systemTime() time.Duration { 190 return ftToDuration(&p.rusage.KernelTime) 191 }

View as plain text