diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go index a6f509dc48c..59529a6d243 100644 --- a/src/cmd/cgo/util.go +++ b/src/cmd/cgo/util.go @@ -32,10 +32,11 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) { if err != nil { fatal("%s", err) } - pid, err := os.ForkExec(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2}) + p, err := os.StartProcess(cmd, argv, os.Environ(), "", []*os.File{r0, w1, w2}) if err != nil { fatal("%s", err) } + defer p.Release() r0.Close() w1.Close() w2.Close() @@ -55,7 +56,7 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) { <-c <-c - w, err := os.Wait(pid, 0) + w, err := p.Wait(0) if err != nil { fatal("%s", err) } diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go index f1b11a760c5..968b8e0f95d 100644 --- a/src/cmd/godoc/main.go +++ b/src/cmd/godoc/main.go @@ -83,20 +83,21 @@ func exec(rw http.ResponseWriter, args []string) (status int) { if *verbose { log.Printf("executing %v", args) } - pid, err := os.ForkExec(bin, args, os.Environ(), *goroot, fds) + p, err := os.StartProcess(bin, args, os.Environ(), *goroot, fds) defer r.Close() w.Close() if err != nil { - log.Printf("os.ForkExec(%q): %v", bin, err) + log.Printf("os.StartProcess(%q): %v", bin, err) return 2 } + defer p.Release() var buf bytes.Buffer io.Copy(&buf, r) - wait, err := os.Wait(pid, 0) + wait, err := p.Wait(0) if err != nil { os.Stderr.Write(buf.Bytes()) - log.Printf("os.Wait(%d, 0): %v", pid, err) + log.Printf("os.Wait(%d, 0): %v", p.Pid, err) return 2 } status = wait.ExitStatus() diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go index 4f4c8c77701..80f6f3c7dd4 100644 --- a/src/pkg/exec/exec.go +++ b/src/pkg/exec/exec.go @@ -22,12 +22,12 @@ const ( // Stdin, Stdout, and Stderr are Files representing pipes // connected to the running command's standard input, output, and error, // or else nil, depending on the arguments to Run. -// Pid is the running command's operating system process ID. +// Process represents the underlying operating system process. type Cmd struct { - Stdin *os.File - Stdout *os.File - Stderr *os.File - Pid int + Stdin *os.File + Stdout *os.File + Stderr *os.File + Process *os.Process } // PathError records the name of a binary that was not @@ -88,24 +88,24 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) { // If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr) // of the returned Cmd is the other end of the pipe. // Otherwise the field in Cmd is nil. -func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) { - p = new(Cmd) +func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (c *Cmd, err os.Error) { + c = new(Cmd) var fd [3]*os.File - if fd[0], p.Stdin, err = modeToFiles(stdin, 0); err != nil { + if fd[0], c.Stdin, err = modeToFiles(stdin, 0); err != nil { goto Error } - if fd[1], p.Stdout, err = modeToFiles(stdout, 1); err != nil { + if fd[1], c.Stdout, err = modeToFiles(stdout, 1); err != nil { goto Error } if stderr == MergeWithStdout { fd[2] = fd[1] - } else if fd[2], p.Stderr, err = modeToFiles(stderr, 2); err != nil { + } else if fd[2], c.Stderr, err = modeToFiles(stderr, 2); err != nil { goto Error } // Run command. - p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:]) + c.Process, err = os.StartProcess(name, argv, envv, dir, fd[0:]) if err != nil { goto Error } @@ -118,7 +118,7 @@ func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int if fd[2] != os.Stderr && fd[2] != fd[1] { fd[2].Close() } - return p, nil + return c, nil Error: if fd[0] != os.Stdin && fd[0] != nil { @@ -130,63 +130,67 @@ Error: if fd[2] != os.Stderr && fd[2] != nil && fd[2] != fd[1] { fd[2].Close() } - if p.Stdin != nil { - p.Stdin.Close() + if c.Stdin != nil { + c.Stdin.Close() } - if p.Stdout != nil { - p.Stdout.Close() + if c.Stdout != nil { + c.Stdout.Close() } - if p.Stderr != nil { - p.Stderr.Close() + if c.Stderr != nil { + c.Stderr.Close() + } + if c.Process != nil { + c.Process.Release() } return nil, err } -// Wait waits for the running command p, -// returning the Waitmsg returned by os.Wait and an error. -// The options are passed through to os.Wait. -// Setting options to 0 waits for p to exit; +// Wait waits for the running command c, +// returning the Waitmsg returned when the process exits. +// The options are passed to the process's Wait method. +// Setting options to 0 waits for c to exit; // other options cause Wait to return for other // process events; see package os for details. -func (p *Cmd) Wait(options int) (*os.Waitmsg, os.Error) { - if p.Pid <= 0 { +func (c *Cmd) Wait(options int) (*os.Waitmsg, os.Error) { + if c.Process == nil { return nil, os.ErrorString("exec: invalid use of Cmd.Wait") } - w, err := os.Wait(p.Pid, options) + w, err := c.Process.Wait(options) if w != nil && (w.Exited() || w.Signaled()) { - p.Pid = -1 + c.Process.Release() + c.Process = nil } return w, err } -// Close waits for the running command p to exit, +// Close waits for the running command c to exit, // if it hasn't already, and then closes the non-nil file descriptors -// p.Stdin, p.Stdout, and p.Stderr. -func (p *Cmd) Close() os.Error { - if p.Pid > 0 { +// c.Stdin, c.Stdout, and c.Stderr. +func (c *Cmd) Close() os.Error { + if c.Process != nil { // Loop on interrupt, but // ignore other errors -- maybe // caller has already waited for pid. - _, err := p.Wait(0) + _, err := c.Wait(0) for err == os.EINTR { - _, err = p.Wait(0) + _, err = c.Wait(0) } } // Close the FDs that are still open. var err os.Error - if p.Stdin != nil && p.Stdin.Fd() >= 0 { - if err1 := p.Stdin.Close(); err1 != nil { + if c.Stdin != nil && c.Stdin.Fd() >= 0 { + if err1 := c.Stdin.Close(); err1 != nil { err = err1 } } - if p.Stdout != nil && p.Stdout.Fd() >= 0 { - if err1 := p.Stdout.Close(); err1 != nil && err != nil { + if c.Stdout != nil && c.Stdout.Fd() >= 0 { + if err1 := c.Stdout.Close(); err1 != nil && err != nil { err = err1 } } - if p.Stderr != nil && p.Stderr != p.Stdout && p.Stderr.Fd() >= 0 { - if err1 := p.Stderr.Close(); err1 != nil && err != nil { + if c.Stderr != nil && c.Stderr != c.Stdout && c.Stderr.Fd() >= 0 { + if err1 := c.Stderr.Close(); err1 != nil && err != nil { err = err1 } } diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go index 03cfafa7b82..52d521d3db3 100644 --- a/src/pkg/http/triv.go +++ b/src/pkg/http/triv.go @@ -99,15 +99,16 @@ func DateServer(rw http.ResponseWriter, req *http.Request) { fmt.Fprintf(rw, "pipe: %s\n", err) return } - pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w}) + p, err := os.StartProcess("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w}) defer r.Close() w.Close() if err != nil { fmt.Fprintf(rw, "fork/exec: %s\n", err) return } + defer p.Release() io.Copy(rw, r) - wait, err := os.Wait(pid, 0) + wait, err := p.Wait(0) if err != nil { fmt.Fprintf(rw, "wait: %s\n", err) return diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile index f6caf084cca..3a81afe39a4 100644 --- a/src/pkg/os/Makefile +++ b/src/pkg/os/Makefile @@ -22,21 +22,25 @@ GOFILES_freebsd=\ env_unix.go\ file_unix.go\ sys_bsd.go\ + exec_unix.go\ GOFILES_darwin=\ env_unix.go\ file_unix.go\ sys_bsd.go\ + exec_unix.go\ GOFILES_linux=\ env_unix.go\ file_unix.go\ sys_linux.go\ + exec_unix.go\ GOFILES_windows=\ env_windows.go\ file_windows.go\ sys_windows.go\ + exec_windows.go\ GOFILES+=$(GOFILES_$(GOOS)) diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go index 100d984d170..dbdfacc5857 100644 --- a/src/pkg/os/exec.go +++ b/src/pkg/os/exec.go @@ -5,17 +5,29 @@ package os import ( + "runtime" "syscall" ) -// ForkExec forks the current process and invokes Exec with the program, arguments, -// and environment specified by name, argv, and envv. It returns the process -// id of the forked process and an Error, if any. The fd array specifies the +// Process stores the information about a process created by StartProcess. +type Process struct { + Pid int + handle int +} + +func newProcess(pid, handle int) *Process { + p := &Process{pid, handle} + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +// StartProcess starts a new process with the program, arguments, +// and environment specified by name, argv, and envv. The fd array specifies the // file descriptors to be set up in the new process: fd[0] will be Unix file // descriptor 0 (standard input), fd[1] descriptor 1, and so on. A nil entry // will cause the child to have no open file descriptor with that index. // If dir is not empty, the child chdirs into the directory before execing the program. -func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) { +func StartProcess(name string, argv []string, envv []string, dir string, fd []*File) (p *Process, err Error) { if envv == nil { envv = Environ() } @@ -29,17 +41,17 @@ func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) } } - p, e := syscall.ForkExec(name, argv, envv, dir, intfd) + pid, h, e := syscall.StartProcess(name, argv, envv, dir, intfd) if e != 0 { - return 0, &PathError{"fork/exec", name, Errno(e)} + return nil, &PathError{"fork/exec", name, Errno(e)} } - return p, nil + return newProcess(pid, h), nil } // Exec replaces the current process with an execution of the // named binary, with arguments argv and environment envv. // If successful, Exec never returns. If it fails, it returns an Error. -// ForkExec is almost always a better way to execute a program. +// StartProcess is almost always a better way to execute a program. func Exec(name string, argv []string, envv []string) Error { if envv == nil { envv = Environ() @@ -65,37 +77,18 @@ type Waitmsg struct { Rusage *syscall.Rusage // System-dependent resource usage info. } -// Options for Wait. -const ( - WNOHANG = syscall.WNOHANG // Don't wait if no process has exited. - WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported. - WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED. - WRUSAGE = 1 << 20 // Record resource usage. -) - -// WRUSAGE must not be too high a bit, to avoid clashing with Linux's -// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of -// the options - // Wait waits for process pid to exit or stop, and then returns a // Waitmsg describing its status and an Error, if any. The options // (WNOHANG etc.) affect the behavior of the Wait call. +// Wait is equivalent to calling FindProcess and then Wait +// and Release on the result. func Wait(pid int, options int) (w *Waitmsg, err Error) { - var status syscall.WaitStatus - var rusage *syscall.Rusage - if options&WRUSAGE != 0 { - rusage = new(syscall.Rusage) - options ^= WRUSAGE + p, e := FindProcess(pid) + if e != nil { + return nil, e } - pid1, e := syscall.Wait4(pid, &status, options, rusage) - if e != 0 { - return nil, NewSyscallError("wait", e) - } - w = new(Waitmsg) - w.Pid = pid1 - w.WaitStatus = status - w.Rusage = rusage - return w, nil + defer p.Release() + return p.Wait(options) } // Convert i to decimal string. diff --git a/src/pkg/os/exec_unix.go b/src/pkg/os/exec_unix.go new file mode 100644 index 00000000000..8990d6a97ec --- /dev/null +++ b/src/pkg/os/exec_unix.go @@ -0,0 +1,63 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "runtime" + "syscall" +) + +// Options for Wait. +const ( + WNOHANG = syscall.WNOHANG // Don't wait if no process has exited. + WSTOPPED = syscall.WSTOPPED // If set, status of stopped subprocesses is also reported. + WUNTRACED = syscall.WUNTRACED // Usually an alias for WSTOPPED. + WRUSAGE = 1 << 20 // Record resource usage. +) + +// WRUSAGE must not be too high a bit, to avoid clashing with Linux's +// WCLONE, WALL, and WNOTHREAD flags, which sit in the top few bits of +// the options + +// Wait waits for the Process to exit or stop, and then returns a +// Waitmsg describing its status and an Error, if any. The options +// (WNOHANG etc.) affect the behavior of the Wait call. +func (p *Process) Wait(options int) (w *Waitmsg, err Error) { + if p.Pid == -1 { + return nil, EINVAL + } + var status syscall.WaitStatus + var rusage *syscall.Rusage + if options&WRUSAGE != 0 { + rusage = new(syscall.Rusage) + options ^= WRUSAGE + } + pid1, e := syscall.Wait4(p.Pid, &status, options, rusage) + if e != 0 { + return nil, NewSyscallError("wait", e) + } + w = new(Waitmsg) + w.Pid = pid1 + w.WaitStatus = status + w.Rusage = rusage + return w, nil +} + +// Release releases any resources associated with the Process. +func (p *Process) Release() Error { + // NOOP for unix. + p.Pid = -1 + // no need for a finalizer anymore + runtime.SetFinalizer(p, nil) + return nil +} + +// FindProcess looks for a running process by its pid. +// The Process it returns can be used to obtain information +// about the underlying operating system process. +func FindProcess(pid int) (p *Process, err Error) { + // NOOP for unix. + return newProcess(pid, 0), nil +} diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go new file mode 100644 index 00000000000..73c0104cafd --- /dev/null +++ b/src/pkg/os/exec_windows.go @@ -0,0 +1,50 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "runtime" + "syscall" +) + +func (p *Process) Wait(options int) (w *Waitmsg, err Error) { + s, e := syscall.WaitForSingleObject(int32(p.handle), syscall.INFINITE) + switch s { + case syscall.WAIT_OBJECT_0: + break + case syscall.WAIT_FAILED: + return nil, NewSyscallError("WaitForSingleObject", e) + default: + return nil, ErrorString("os: unexpected result from WaitForSingleObject") + } + var ec uint32 + if ok, e := syscall.GetExitCodeProcess(uint32(p.handle), &ec); !ok { + return nil, NewSyscallError("GetExitCodeProcess", e) + } + return &Waitmsg{p.Pid, syscall.WaitStatus{s, ec}, new(syscall.Rusage)}, nil +} + +func (p *Process) Release() Error { + if p.handle == -1 { + return EINVAL + } + if ok, e := syscall.CloseHandle(int32(p.handle)); !ok { + return NewSyscallError("CloseHandle", e) + } + p.handle = -1 + // no need for a finalizer anymore + runtime.SetFinalizer(p, nil) + return nil +} + +func FindProcess(pid int) (p *Process, err Error) { + const da = syscall.STANDARD_RIGHTS_READ | + syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE + h, e := syscall.OpenProcess(da, false, uint32(pid)) + if e != 0 { + return nil, NewSyscallError("OpenProcess", e) + } + return newProcess(pid, int(h)), nil +} diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index 49b58c83c80..2ea8acdc430 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -427,10 +427,11 @@ func TestForkExec(t *testing.T) { adir = "/" expect = "/\n" } - pid, err := ForkExec(cmd, args, nil, adir, []*File{nil, w, Stderr}) + p, err := StartProcess(cmd, args, nil, adir, []*File{nil, w, Stderr}) if err != nil { - t.Fatalf("ForkExec: %v", err) + t.Fatalf("StartProcess: %v", err) } + defer p.Release() w.Close() var b bytes.Buffer @@ -440,7 +441,7 @@ func TestForkExec(t *testing.T) { args[0] = cmd t.Errorf("exec %q returned %q wanted %q", strings.Join(args, " "), output, expect) } - Wait(pid, 0) + p.Wait(0) } func checkMode(t *testing.T, path string, mode uint32) { @@ -750,15 +751,16 @@ func run(t *testing.T, cmd []string) string { if err != nil { t.Fatal(err) } - pid, err := ForkExec("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr}) + p, err := StartProcess("/bin/hostname", []string{"hostname"}, nil, "/", []*File{nil, w, Stderr}) if err != nil { t.Fatal(err) } + defer p.Release() w.Close() var b bytes.Buffer io.Copy(&b, r) - Wait(pid, 0) + p.Wait(0) output := b.String() if n := len(output); n > 0 && output[n-1] == '\n' { output = output[0 : n-1] diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go index c7f7893e7d8..04c066918f8 100644 --- a/src/pkg/syscall/exec_unix.go +++ b/src/pkg/syscall/exec_unix.go @@ -310,3 +310,9 @@ func Exec(argv0 string, argv []string, envv []string) (err int) { uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0]))) return int(err1) } + +// StartProcess wraps ForkExec for package os. +func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) { + pid, err = forkExec(argv0, argv, envv, false, dir, fd) + return pid, 0, err +} diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go index 64a0030dc6b..1ce26550666 100644 --- a/src/pkg/syscall/exec_windows.go +++ b/src/pkg/syscall/exec_windows.go @@ -117,13 +117,9 @@ func SetNonblock(fd int, nonblocking bool) (errno int) { // TODO(kardia): Add trace //The command and arguments are passed via the Command line parameter. -func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) { - if traceme == true { - return 0, EWINDOWS - } - +func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) { if len(fd) > 3 { - return 0, EWINDOWS + return 0, 0, EWINDOWS } //CreateProcess will throw an error if the dir is not set to a valid dir @@ -153,19 +149,19 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri var currentProc, _ = GetCurrentProcess() if len(fd) > 0 && fd[0] > 0 { if ok, err := DuplicateHandle(currentProc, int32(fd[0]), currentProc, &startupInfo.StdInput, 0, true, DUPLICATE_SAME_ACCESS); !ok { - return 0, err + return 0, 0, err } defer CloseHandle(int32(startupInfo.StdInput)) } if len(fd) > 1 && fd[1] > 0 { if ok, err := DuplicateHandle(currentProc, int32(fd[1]), currentProc, &startupInfo.StdOutput, 0, true, DUPLICATE_SAME_ACCESS); !ok { - return 0, err + return 0, 0, err } defer CloseHandle(int32(startupInfo.StdOutput)) } if len(fd) > 2 && fd[2] > 0 { if ok, err := DuplicateHandle(currentProc, int32(fd[2]), currentProc, &startupInfo.StdErr, 0, true, DUPLICATE_SAME_ACCESS); !ok { - return 0, err + return 0, 0, err } defer CloseHandle(int32(startupInfo.StdErr)) } @@ -188,21 +184,12 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri if ok { pid = int(processInfo.ProcessId) - CloseHandle(processInfo.Process) + handle = int(processInfo.Process) CloseHandle(processInfo.Thread) } return } -func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) { - return forkExec(argv0, argv, envv, false, dir, fd) -} - -// PtraceForkExec is like ForkExec, but starts the child in a traced state. -func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) { - return forkExec(argv0, argv, envv, true, dir, fd) -} - // Ordinary exec. func Exec(argv0 string, argv []string, envv []string) (err int) { return EWINDOWS diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go index 267b30647fb..f0b71dd91d3 100644 --- a/src/pkg/syscall/syscall_windows.go +++ b/src/pkg/syscall/syscall_windows.go @@ -136,6 +136,8 @@ func NewCallback(fn interface{}) uintptr //sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int) //sys CancelIo(s uint32) (ok bool, errno int) //sys CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (ok bool, errno int) = CreateProcessW +//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) +//sys GetExitCodeProcess(handle uint32, exitcode *uint32) (ok bool, errno int) //sys GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) = GetStartupInfoW //sys GetCurrentProcess() (pseudoHandle int32, errno int) //sys DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int) @@ -146,8 +148,6 @@ func NewCallback(fn interface{}) uintptr //sys CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) = advapi32.CryptAcquireContextW //sys CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) = advapi32.CryptReleaseContext //sys CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) = advapi32.CryptGenRandom -//sys OpenProcess(da uint32,b int, pid uint32) (handle uint32, errno int) -//sys GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) //sys GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW //sys FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) = kernel32.FreeEnvironmentStringsW //sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW @@ -672,6 +672,32 @@ func WSASendto(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32 return } +// Invented structures to support what package os expects. +type Rusage struct{} + +type WaitStatus struct { + Status uint32 + ExitCode uint32 +} + +func (w WaitStatus) Exited() bool { return true } + +func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) } + +func (w WaitStatus) Signal() int { return -1 } + +func (w WaitStatus) CoreDump() bool { return false } + +func (w WaitStatus) Stopped() bool { return false } + +func (w WaitStatus) Continued() bool { return false } + +func (w WaitStatus) StopSignal() int { return -1 } + +func (w WaitStatus) Signaled() bool { return true } + +func (w WaitStatus) TrapCause() int { return -1 } + // TODO(brainman): fix all needed for net func Accept(fd int) (nfd int, sa Sockaddr, errno int) { return 0, nil, EWINDOWS } @@ -735,67 +761,3 @@ const ( SYS_EXIT SYS_READ ) - -type Rusage struct { - Utime Timeval - Stime Timeval - Maxrss int32 - Ixrss int32 - Idrss int32 - Isrss int32 - Minflt int32 - Majflt int32 - Nswap int32 - Inblock int32 - Oublock int32 - Msgsnd int32 - Msgrcv int32 - Nsignals int32 - Nvcsw int32 - Nivcsw int32 -} - -type WaitStatus struct { - Status uint32 - ExitCode uint32 -} - -func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) { - const da = STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | SYNCHRONIZE - handle, errno := OpenProcess(da, 0, uint32(pid)) - if errno != 0 { - return 0, errno - } - defer CloseHandle(int32(handle)) - e, errno := WaitForSingleObject(int32(handle), INFINITE) - var c uint32 - if ok, errno := GetExitCodeProcess(handle, &c); !ok { - return 0, errno - } - *wstatus = WaitStatus{e, c} - return pid, 0 -} - - -func (w WaitStatus) Exited() bool { return w.Status == WAIT_OBJECT_0 } - -func (w WaitStatus) ExitStatus() int { - if w.Status == WAIT_OBJECT_0 { - return int(w.ExitCode) - } - return -1 -} - -func (WaitStatus) Signal() int { return -1 } - -func (WaitStatus) CoreDump() bool { return false } - -func (WaitStatus) Stopped() bool { return false } - -func (WaitStatus) Continued() bool { return false } - -func (WaitStatus) StopSignal() int { return -1 } - -func (w WaitStatus) Signaled() bool { return w.Status == WAIT_OBJECT_0 } - -func (WaitStatus) TrapCause() int { return -1 } diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go index d5f170fe39a..96c6098ddb2 100644 --- a/src/pkg/syscall/zsyscall_windows_386.go +++ b/src/pkg/syscall/zsyscall_windows_386.go @@ -45,6 +45,8 @@ var ( procGetQueuedCompletionStatus = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus") procCancelIo = getSysProcAddr(modkernel32, "CancelIo") procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW") + procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess") + procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess") procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW") procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess") procDuplicateHandle = getSysProcAddr(modkernel32, "DuplicateHandle") @@ -55,8 +57,6 @@ var ( procCryptAcquireContextW = getSysProcAddr(modadvapi32, "CryptAcquireContextW") procCryptReleaseContext = getSysProcAddr(modadvapi32, "CryptReleaseContext") procCryptGenRandom = getSysProcAddr(modadvapi32, "CryptGenRandom") - procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess") - procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess") procGetEnvironmentStringsW = getSysProcAddr(modkernel32, "GetEnvironmentStringsW") procFreeEnvironmentStringsW = getSysProcAddr(modkernel32, "FreeEnvironmentStringsW") procGetEnvironmentVariableW = getSysProcAddr(modkernel32, "GetEnvironmentVariableW") @@ -550,6 +550,42 @@ func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, thr return } +func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle uint32, errno int) { + var _p0 uint32 + if inheritHandle { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(_p0), uintptr(pid)) + handle = uint32(r0) + if handle == 0 { + if e1 != 0 { + errno = int(e1) + } else { + errno = EINVAL + } + } else { + errno = 0 + } + return +} + +func GetExitCodeProcess(handle uint32, exitcode *uint32) (ok bool, errno int) { + r0, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0) + ok = bool(r0 != 0) + if !ok { + if e1 != 0 { + errno = int(e1) + } else { + errno = EINVAL + } + } else { + errno = 0 + } + return +} + func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) { r0, _, e1 := Syscall(procGetStartupInfoW, 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0) ok = bool(r0 != 0) @@ -706,36 +742,6 @@ func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno return } -func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) { - r0, _, e1 := Syscall(procOpenProcess, 3, uintptr(da), uintptr(b), uintptr(pid)) - handle = uint32(r0) - if handle == 0 { - if e1 != 0 { - errno = int(e1) - } else { - errno = EINVAL - } - } else { - errno = 0 - } - return -} - -func GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) { - r0, _, e1 := Syscall(procGetExitCodeProcess, 2, uintptr(h), uintptr(unsafe.Pointer(c)), 0) - ok = bool(r0 != 0) - if !ok { - if e1 != 0 { - errno = int(e1) - } else { - errno = EINVAL - } - } else { - errno = 0 - } - return -} - func GetEnvironmentStrings() (envs *uint16, errno int) { r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0, 0) envs = (*uint16)(unsafe.Pointer(r0))