diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-06 17:57:23 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-06 17:57:23 +0000 |
commit | 593f74bbab63d34c7060918088bcbad686c31c66 (patch) | |
tree | 4ce83ca433796a728e9fdd00af105bce158532b5 /libgo/go/os | |
parent | 46402cbe0ba3ea92be9642cf18eedaefe57a414c (diff) | |
download | gcc-593f74bbab63d34c7060918088bcbad686c31c66.zip gcc-593f74bbab63d34c7060918088bcbad686c31c66.tar.gz gcc-593f74bbab63d34c7060918088bcbad686c31c66.tar.bz2 |
libgo: Update to weekly.2012-03-04 release.
From-SVN: r185010
Diffstat (limited to 'libgo/go/os')
-rw-r--r-- | libgo/go/os/doc.go | 72 | ||||
-rw-r--r-- | libgo/go/os/exec.go | 2 | ||||
-rw-r--r-- | libgo/go/os/exec_plan9.go | 44 | ||||
-rw-r--r-- | libgo/go/os/exec_posix.go | 41 | ||||
-rw-r--r-- | libgo/go/os/exec_unix.go | 16 | ||||
-rw-r--r-- | libgo/go/os/exec_windows.go | 40 | ||||
-rw-r--r-- | libgo/go/os/file.go | 2 | ||||
-rw-r--r-- | libgo/go/os/os_test.go | 37 |
8 files changed, 167 insertions, 87 deletions
diff --git a/libgo/go/os/doc.go b/libgo/go/os/doc.go index ef857c0..6a531e0 100644 --- a/libgo/go/os/doc.go +++ b/libgo/go/os/doc.go @@ -4,6 +4,8 @@ package os +import "time" + // 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. @@ -11,6 +13,76 @@ func FindProcess(pid int) (p *Process, err error) { return findProcess(pid) } +// StartProcess starts a new process with the program, arguments and attributes +// specified by name, argv and attr. +// +// StartProcess is a low-level interface. The os/exec package provides +// higher-level interfaces. +// +// If there is an error, it will be of type *PathError. +func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { + return startProcess(name, argv, attr) +} + +// Release releases any resources associated with the Process p, +// rendering it unusable in the future. +// Release only needs to be called if Wait is not. +func (p *Process) Release() error { + return p.release() +} + +// Kill causes the Process to exit immediately. +func (p *Process) Kill() error { + return p.kill() +} + +// Wait waits for the Process to exit, and then returns a +// ProcessState describing its status and an error, if any. +// Wait releases any resources associated with the Process. +func (p *Process) Wait() (*ProcessState, error) { + return p.wait() +} + +// Signal sends a signal to the Process. +func (p *Process) Signal(sig Signal) error { + return p.signal(sig) +} + +// UserTime returns the user CPU time of the exited process and its children. +func (p *ProcessState) UserTime() time.Duration { + return p.userTime() +} + +// SystemTime returns the system CPU time of the exited process and its children. +func (p *ProcessState) SystemTime() time.Duration { + return p.systemTime() +} + +// Exited returns whether the program has exited. +func (p *ProcessState) Exited() bool { + return p.exited() +} + +// Success reports whether the program exited successfully, +// such as with exit status 0 on Unix. +func (p *ProcessState) Success() bool { + return p.success() +} + +// Sys returns system-dependent exit information about +// the process. Convert it to the appropriate underlying +// type, such as syscall.WaitStatus on Unix, to access its contents. +func (p *ProcessState) Sys() interface{} { + return p.sys() +} + +// SysUsage returns system-dependent resource usage information about +// the exited process. Convert it to the appropriate underlying +// type, such as *syscall.Rusage on Unix, to access its contents. +func (p *ProcessState) SysUsage() interface{} { + return p.sysUsage() +} + // Hostname returns the host name reported by the kernel. func Hostname() (name string, err error) { return hostname() diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go index 37a0051..531b87c 100644 --- a/libgo/go/os/exec.go +++ b/libgo/go/os/exec.go @@ -13,7 +13,7 @@ import ( type Process struct { Pid int handle uintptr - done bool // process has been successfuly waited on + done bool // process has been successfully waited on } func newProcess(pid int, handle uintptr) *Process { diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go index 1c9e2b9..41cc8c2 100644 --- a/libgo/go/os/exec_plan9.go +++ b/libgo/go/os/exec_plan9.go @@ -11,10 +11,7 @@ import ( "time" ) -// StartProcess starts a new process with the program, arguments and attributes -// specified by name, argv and attr. -// If there is an error, it will be of type *PathError. -func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { +func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { sysattr := &syscall.ProcAttr{ Dir: attr.Dir, Env: attr.Env, @@ -40,7 +37,7 @@ func (note Plan9Note) String() string { return string(note) } -func (p *Process) Signal(sig Signal) error { +func (p *Process) signal(sig Signal) error { if p.done { return errors.New("os: process already finished") } @@ -54,8 +51,7 @@ func (p *Process) Signal(sig Signal) error { return e } -// Kill causes the Process to exit immediately. -func (p *Process) Kill() error { +func (p *Process) kill() error { f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0) if e != nil { return NewSyscallError("kill", e) @@ -65,9 +61,7 @@ func (p *Process) Kill() error { return e } -// Wait waits for the Process to exit or stop, and then returns a -// ProcessState describing its status and an error, if any. -func (p *Process) Wait() (ps *ProcessState, err error) { +func (p *Process) wait() (ps *ProcessState, err error) { var waitmsg syscall.Waitmsg if p.Pid == -1 { @@ -94,8 +88,7 @@ func (p *Process) Wait() (ps *ProcessState, err error) { return ps, nil } -// Release releases any resources associated with the Process. -func (p *Process) Release() error { +func (p *Process) release() error { // NOOP for Plan 9. p.Pid = -1 // no need for a finalizer anymore @@ -108,7 +101,7 @@ func findProcess(pid int) (p *Process, err error) { return newProcess(pid, 0), nil } -// ProcessState stores information about process as reported by Wait. +// ProcessState stores information about a process, as reported by Wait. type ProcessState struct { pid int // The process's id. status *syscall.Waitmsg // System-dependent status info. @@ -119,40 +112,27 @@ func (p *ProcessState) Pid() int { return p.pid } -// Exited returns whether the program has exited. -func (p *ProcessState) Exited() bool { +func (p *ProcessState) exited() bool { return p.status.Exited() } -// Success reports whether the program exited successfully, -// such as with exit status 0 on Unix. -func (p *ProcessState) Success() bool { +func (p *ProcessState) success() bool { return p.status.ExitStatus() == 0 } -// Sys returns system-dependent exit information about -// the process. Convert it to the appropriate underlying -// type, such as *syscall.Waitmsg on Plan 9, to access its contents. -func (p *ProcessState) Sys() interface{} { +func (p *ProcessState) sys() interface{} { return p.status } -// SysUsage returns system-dependent resource usage information about -// the exited process. Convert it to the appropriate underlying -// type, such as *syscall.Waitmsg on Plan 9, to access its contents. -func (p *ProcessState) SysUsage() interface{} { +func (p *ProcessState) sysUsage() interface{} { return p.status } -// UserTime returns the user CPU time of the exited process and its children. -// It is always reported as 0 on Windows. -func (p *ProcessState) UserTime() time.Duration { +func (p *ProcessState) userTime() time.Duration { return time.Duration(p.status.Time[0]) * time.Millisecond } -// SystemTime returns the system CPU time of the exited process and its children. -// It is always reported as 0 on Windows. -func (p *ProcessState) SystemTime() time.Duration { +func (p *ProcessState) systemTime() time.Duration { return time.Duration(p.status.Time[1]) * time.Millisecond } diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go index 4a75cb67..70351cf 100644 --- a/libgo/go/os/exec_posix.go +++ b/libgo/go/os/exec_posix.go @@ -10,14 +10,17 @@ import ( "syscall" ) -// StartProcess starts a new process with the program, arguments and attributes -// specified by name, argv and attr. -// -// StartProcess is a low-level interface. The os/exec package provides -// higher-level interfaces. -// -// If there is an error, it will be of type *PathError. -func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { +func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { + // Double-check existence of the directory we want + // to chdir into. We can make the error clearer this way. + if attr != nil && attr.Dir != "" { + if _, err := Stat(attr.Dir); err != nil { + pe := err.(*PathError) + pe.Op = "chdir" + return nil, pe + } + } + sysattr := &syscall.ProcAttr{ Dir: attr.Dir, Env: attr.Env, @@ -37,12 +40,11 @@ func StartProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e return newProcess(pid, h), nil } -// Kill causes the Process to exit immediately. -func (p *Process) Kill() error { +func (p *Process) kill() error { return p.Signal(Kill) } -// ProcessState stores information about process as reported by Wait. +// ProcessState stores information about a process, as reported by Wait. type ProcessState struct { pid int // The process's id. status syscall.WaitStatus // System-dependent status info. @@ -54,28 +56,19 @@ func (p *ProcessState) Pid() int { return p.pid } -// Exited returns whether the program has exited. -func (p *ProcessState) Exited() bool { +func (p *ProcessState) exited() bool { return p.status.Exited() } -// Success reports whether the program exited successfully, -// such as with exit status 0 on Unix. -func (p *ProcessState) Success() bool { +func (p *ProcessState) success() bool { return p.status.ExitStatus() == 0 } -// Sys returns system-dependent exit information about -// the process. Convert it to the appropriate underlying -// type, such as syscall.WaitStatus on Unix, to access its contents. -func (p *ProcessState) Sys() interface{} { +func (p *ProcessState) sys() interface{} { return p.status } -// SysUsage returns system-dependent resource usage information about -// the exited process. Convert it to the appropriate underlying -// type, such as *syscall.Rusage on Unix, to access its contents. -func (p *ProcessState) SysUsage() interface{} { +func (p *ProcessState) sysUsage() interface{} { return p.rusage } diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go index 8d000e9..ecfe535 100644 --- a/libgo/go/os/exec_unix.go +++ b/libgo/go/os/exec_unix.go @@ -13,9 +13,7 @@ import ( "time" ) -// Wait waits for the Process to exit or stop, and then returns a -// ProcessState describing its status and an error, if any. -func (p *Process) Wait() (ps *ProcessState, err error) { +func (p *Process) wait() (ps *ProcessState, err error) { if p.Pid == -1 { return nil, syscall.EINVAL } @@ -36,8 +34,7 @@ func (p *Process) Wait() (ps *ProcessState, err error) { return ps, nil } -// Signal sends a signal to the Process. -func (p *Process) Signal(sig Signal) error { +func (p *Process) signal(sig Signal) error { if p.done { return errors.New("os: process already finished") } @@ -51,8 +48,7 @@ func (p *Process) Signal(sig Signal) error { return nil } -// Release releases any resources associated with the Process. -func (p *Process) Release() error { +func (p *Process) release() error { // NOOP for unix. p.Pid = -1 // no need for a finalizer anymore @@ -65,12 +61,10 @@ func findProcess(pid int) (p *Process, err error) { return newProcess(pid, 0), nil } -// UserTime returns the user CPU time of the exited process and its children. -func (p *ProcessState) UserTime() time.Duration { +func (p *ProcessState) userTime() time.Duration { return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond } -// SystemTime returns the system CPU time of the exited process and its children. -func (p *ProcessState) SystemTime() time.Duration { +func (p *ProcessState) systemTime() time.Duration { return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond } diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go index dab0dc9..5beca4a 100644 --- a/libgo/go/os/exec_windows.go +++ b/libgo/go/os/exec_windows.go @@ -12,9 +12,7 @@ import ( "unsafe" ) -// Wait waits for the Process to exit or stop, and then returns a -// ProcessState describing its status and an error, if any. -func (p *Process) Wait() (ps *ProcessState, err error) { +func (p *Process) wait() (ps *ProcessState, err error) { s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE) switch s { case syscall.WAIT_OBJECT_0: @@ -29,12 +27,22 @@ func (p *Process) Wait() (ps *ProcessState, err error) { if e != nil { return nil, NewSyscallError("GetExitCodeProcess", e) } + var u syscall.Rusage + e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime) + if e != nil { + return nil, NewSyscallError("GetProcessTimes", e) + } p.done = true - return &ProcessState{p.Pid, syscall.WaitStatus{Status: s, ExitCode: ec}, new(syscall.Rusage)}, nil + // NOTE(brainman): It seems that sometimes process is not dead + // when WaitForSingleObject returns. But we do not know any + // other way to wait for it. Sleeping for a while seems to do + // the trick sometimes. So we will sleep and smell the roses. + defer time.Sleep(5 * time.Millisecond) + defer p.Release() + return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil } -// Signal sends a signal to the Process. -func (p *Process) Signal(sig Signal) error { +func (p *Process) signal(sig Signal) error { if p.done { return errors.New("os: process already finished") } @@ -46,8 +54,7 @@ func (p *Process) Signal(sig Signal) error { return syscall.Errno(syscall.EWINDOWS) } -// Release releases any resources associated with the Process. -func (p *Process) Release() error { +func (p *Process) release() error { if p.handle == uintptr(syscall.InvalidHandle) { return syscall.EINVAL } @@ -85,14 +92,15 @@ func init() { } } -// UserTime returns the user CPU time of the exited process and its children. -// For now, it is always reported as 0 on Windows. -func (p *ProcessState) UserTime() time.Duration { - return 0 +func ftToDuration(ft *syscall.Filetime) time.Duration { + n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals + return time.Duration(n*100) * time.Nanosecond +} + +func (p *ProcessState) userTime() time.Duration { + return ftToDuration(&p.rusage.UserTime) } -// SystemTime returns the system CPU time of the exited process and its children. -// For now, it is always reported as 0 on Windows. -func (p *ProcessState) SystemTime() time.Duration { - return 0 +func (p *ProcessState) systemTime() time.Duration { + return ftToDuration(&p.rusage.KernelTime) } diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index 1c3d017..4acf35d 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -25,7 +25,7 @@ // open file.go: no such file or directory // // The file's data can then be read into a slice of bytes. Read and -// Write take their byte counts from the length of the artument slice. +// Write take their byte counts from the length of the argument slice. // // data := make([]byte, 100) // count, err := file.Read(data) diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index cff35fc..aa01669 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -528,7 +528,6 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) { if err != nil { t.Fatalf("StartProcess: %v", err) } - defer p.Release() w.Close() var b bytes.Buffer @@ -846,7 +845,6 @@ func run(t *testing.T, cmd []string) string { if err != nil { t.Fatal(err) } - defer p.Release() w.Close() var b bytes.Buffer @@ -1012,3 +1010,38 @@ func TestNilProcessStateString(t *testing.T) { t.Errorf("(*ProcessState)(nil).String() = %q, want %q", s, "<nil>") } } + +func TestSameFile(t *testing.T) { + fa, err := Create("a") + if err != nil { + t.Fatalf("Create(a): %v", err) + } + defer Remove(fa.Name()) + fa.Close() + fb, err := Create("b") + if err != nil { + t.Fatalf("Create(b): %v", err) + } + defer Remove(fb.Name()) + fb.Close() + + ia1, err := Stat("a") + if err != nil { + t.Fatalf("Stat(a): %v", err) + } + ia2, err := Stat("a") + if err != nil { + t.Fatalf("Stat(a): %v", err) + } + if !SameFile(ia1, ia2) { + t.Errorf("files should be same") + } + + ib, err := Stat("b") + if err != nil { + t.Fatalf("Stat(b): %v", err) + } + if SameFile(ia1, ib) { + t.Errorf("files should be different") + } +} |