]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: implement syscall.Getppid() on Windows
authorAlan Shreve <alan@inconshreveable.com>
Sat, 14 Jun 2014 05:51:00 +0000 (15:51 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Sat, 14 Jun 2014 05:51:00 +0000 (15:51 +1000)
Also added a test to verify os.Getppid() works across all platforms

LGTM=alex.brainman
R=golang-codereviews, alex.brainman, shreveal, iant
CC=golang-codereviews
https://golang.org/cl/102320044

src/pkg/os/os_test.go
src/pkg/syscall/syscall_windows.go
src/pkg/syscall/zsyscall_windows_386.go
src/pkg/syscall/zsyscall_windows_amd64.go
src/pkg/syscall/ztypes_windows.go

index 16d5984e964881016b8449e542fcbf3262d9c26d..baf913c2f0dea58c200df284f6071c3adacf8201 100644 (file)
@@ -1293,6 +1293,32 @@ func TestKillStartProcess(t *testing.T) {
        })
 }
 
+func TestGetppid(t *testing.T) {
+       if runtime.GOOS == "nacl" {
+               t.Skip("skipping on nacl")
+       }
+
+       if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+               fmt.Print(Getppid())
+               Exit(0)
+       }
+
+       cmd := osexec.Command(Args[0], "-test.run=TestGetppid")
+       cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
+
+       // verify that Getppid() from the forked process reports our process id
+       output, err := cmd.CombinedOutput()
+       if err != nil {
+               t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
+       }
+
+       childPpid := string(output)
+       ourPid := fmt.Sprintf("%d", Getpid())
+       if childPpid != ourPid {
+               t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
+       }
+}
+
 func TestKillFindProcess(t *testing.T) {
        testKillProcess(t, func(p *Process) {
                p2, err := FindProcess(p.Pid)
index f9733f6cee55fe485e959d08faa7f749ed1df546..79db1d1f6e70cdc960973f730fdc460c6918a346 100644 (file)
@@ -204,6 +204,9 @@ func NewCallbackCDecl(fn interface{}) uintptr
 //sys  GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
 //sys  WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
 //sys  ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
+//sys  CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
+//sys  Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
+//sys  Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
 
 // syscall interface implementation for other packages
 
@@ -902,9 +905,37 @@ func FindNextFile(handle Handle, data *Win32finddata) (err error) {
        return
 }
 
-// TODO(brainman): fix all needed for os
-func Getppid() (ppid int) { return -1 }
+func getProcessEntry(pid int) (*ProcessEntry32, error) {
+       snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
+       if err != nil {
+               return nil, err
+       }
+       defer CloseHandle(snapshot)
+       var procEntry ProcessEntry32
+       procEntry.Size = uint32(unsafe.Sizeof(procEntry))
+       if err = Process32First(snapshot, &procEntry); err != nil {
+               return nil, err
+       }
+       for {
+               if procEntry.ProcessID == uint32(pid) {
+                       return &procEntry, nil
+               }
+               err = Process32Next(snapshot, &procEntry)
+               if err != nil {
+                       return nil, err
+               }
+       }
+}
+
+func Getppid() (ppid int) {
+       pe, err := getProcessEntry(Getpid())
+       if err != nil {
+               return -1
+       }
+       return int(pe.ParentProcessID)
+}
 
+// TODO(brainman): fix all needed for os
 func Fchdir(fd Handle) (err error)                        { return EWINDOWS }
 func Link(oldpath, newpath string) (err error)            { return EWINDOWS }
 func Symlink(path, link string) (err error)               { return EWINDOWS }
index 132adafeff4916540559bafeb84e081673f92eca..23bb448df675c65947569f4322221be83b18c556 100644 (file)
@@ -108,6 +108,9 @@ var (
        procGetConsoleMode                     = modkernel32.NewProc("GetConsoleMode")
        procWriteConsoleW                      = modkernel32.NewProc("WriteConsoleW")
        procReadConsoleW                       = modkernel32.NewProc("ReadConsoleW")
+       procCreateToolhelp32Snapshot           = modkernel32.NewProc("CreateToolhelp32Snapshot")
+       procProcess32FirstW                    = modkernel32.NewProc("Process32FirstW")
+       procProcess32NextW                     = modkernel32.NewProc("Process32NextW")
        procWSAStartup                         = modws2_32.NewProc("WSAStartup")
        procWSACleanup                         = modws2_32.NewProc("WSACleanup")
        procWSAIoctl                           = modws2_32.NewProc("WSAIoctl")
@@ -1254,6 +1257,43 @@ func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, input
        return
 }
 
+func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) {
+       r0, _, e1 := Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0)
+       handle = Handle(r0)
+       if handle == InvalidHandle {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
+func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) {
+       r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
+func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) {
+       r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
 func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
        r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
        if r0 != 0 {
index 353a6fd9804268ee67bbb586f44cb355d20c9d9c..2ddf81b97c46bdde2ac84999fe55bed9080d80b7 100644 (file)
@@ -108,6 +108,9 @@ var (
        procGetConsoleMode                     = modkernel32.NewProc("GetConsoleMode")
        procWriteConsoleW                      = modkernel32.NewProc("WriteConsoleW")
        procReadConsoleW                       = modkernel32.NewProc("ReadConsoleW")
+       procCreateToolhelp32Snapshot           = modkernel32.NewProc("CreateToolhelp32Snapshot")
+       procProcess32FirstW                    = modkernel32.NewProc("Process32FirstW")
+       procProcess32NextW                     = modkernel32.NewProc("Process32NextW")
        procWSAStartup                         = modws2_32.NewProc("WSAStartup")
        procWSACleanup                         = modws2_32.NewProc("WSACleanup")
        procWSAIoctl                           = modws2_32.NewProc("WSAIoctl")
@@ -1254,6 +1257,43 @@ func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, input
        return
 }
 
+func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) {
+       r0, _, e1 := Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0)
+       handle = Handle(r0)
+       if handle == InvalidHandle {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
+func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) {
+       r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
+func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) {
+       r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
+       if r1 == 0 {
+               if e1 != 0 {
+                       err = error(e1)
+               } else {
+                       err = EINVAL
+               }
+       }
+       return
+}
+
 func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
        r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
        if r0 != 0 {
index a1d77e0b54243fe46857cd79a623eea424cb06b1..dacb2a3dc06ca771e39bd87add64db6156f77a03 100644 (file)
@@ -175,6 +175,17 @@ const (
        CTRL_BREAK_EVENT = 1
 )
 
+const (
+       // flags for CreateToolhelp32Snapshot
+       TH32CS_SNAPHEAPLIST = 0x01
+       TH32CS_SNAPPROCESS  = 0x02
+       TH32CS_SNAPTHREAD   = 0x04
+       TH32CS_SNAPMODULE   = 0x08
+       TH32CS_SNAPMODULE32 = 0x10
+       TH32CS_SNAPALL      = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
+       TH32CS_INHERIT      = 0x80000000
+)
+
 const (
        // do not reorder
        FILE_NOTIFY_CHANGE_FILE_NAME = 1 << iota
@@ -462,6 +473,19 @@ type ProcessInformation struct {
        ThreadId  uint32
 }
 
+type ProcessEntry32 struct {
+       Size            uint32
+       Usage           uint32
+       ProcessID       uint32
+       DefaultHeapID   uintptr
+       ModuleID        uint32
+       Threads         uint32
+       ParentProcessID uint32
+       PriClassBase    int32
+       Flags           uint32
+       ExeFile         [MAX_PATH]uint16
+}
+
 type Systemtime struct {
        Year         uint16
        Month        uint16