Skip to content

Commit 6f6f1bd

Browse files
inconshreveablealexbrainman
authored andcommitted
syscall: implement syscall.Getppid() on Windows
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
1 parent f303b49 commit 6f6f1bd

File tree

5 files changed

+163
-2
lines changed

5 files changed

+163
-2
lines changed

src/pkg/os/os_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,32 @@ func TestKillStartProcess(t *testing.T) {
12931293
})
12941294
}
12951295

1296+
func TestGetppid(t *testing.T) {
1297+
if runtime.GOOS == "nacl" {
1298+
t.Skip("skipping on nacl")
1299+
}
1300+
1301+
if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
1302+
fmt.Print(Getppid())
1303+
Exit(0)
1304+
}
1305+
1306+
cmd := osexec.Command(Args[0], "-test.run=TestGetppid")
1307+
cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
1308+
1309+
// verify that Getppid() from the forked process reports our process id
1310+
output, err := cmd.CombinedOutput()
1311+
if err != nil {
1312+
t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
1313+
}
1314+
1315+
childPpid := string(output)
1316+
ourPid := fmt.Sprintf("%d", Getpid())
1317+
if childPpid != ourPid {
1318+
t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
1319+
}
1320+
}
1321+
12961322
func TestKillFindProcess(t *testing.T) {
12971323
testKillProcess(t, func(p *Process) {
12981324
p2, err := FindProcess(p.Pid)

src/pkg/syscall/syscall_windows.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ func NewCallbackCDecl(fn interface{}) uintptr
204204
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
205205
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
206206
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
207+
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
208+
//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
209+
//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
207210

208211
// syscall interface implementation for other packages
209212

@@ -902,9 +905,37 @@ func FindNextFile(handle Handle, data *Win32finddata) (err error) {
902905
return
903906
}
904907

905-
// TODO(brainman): fix all needed for os
906-
func Getppid() (ppid int) { return -1 }
908+
func getProcessEntry(pid int) (*ProcessEntry32, error) {
909+
snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
910+
if err != nil {
911+
return nil, err
912+
}
913+
defer CloseHandle(snapshot)
914+
var procEntry ProcessEntry32
915+
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
916+
if err = Process32First(snapshot, &procEntry); err != nil {
917+
return nil, err
918+
}
919+
for {
920+
if procEntry.ProcessID == uint32(pid) {
921+
return &procEntry, nil
922+
}
923+
err = Process32Next(snapshot, &procEntry)
924+
if err != nil {
925+
return nil, err
926+
}
927+
}
928+
}
929+
930+
func Getppid() (ppid int) {
931+
pe, err := getProcessEntry(Getpid())
932+
if err != nil {
933+
return -1
934+
}
935+
return int(pe.ParentProcessID)
936+
}
907937

938+
// TODO(brainman): fix all needed for os
908939
func Fchdir(fd Handle) (err error) { return EWINDOWS }
909940
func Link(oldpath, newpath string) (err error) { return EWINDOWS }
910941
func Symlink(path, link string) (err error) { return EWINDOWS }

src/pkg/syscall/zsyscall_windows_386.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ var (
108108
procGetConsoleMode = modkernel32.NewProc("GetConsoleMode")
109109
procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
110110
procReadConsoleW = modkernel32.NewProc("ReadConsoleW")
111+
procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
112+
procProcess32FirstW = modkernel32.NewProc("Process32FirstW")
113+
procProcess32NextW = modkernel32.NewProc("Process32NextW")
111114
procWSAStartup = modws2_32.NewProc("WSAStartup")
112115
procWSACleanup = modws2_32.NewProc("WSACleanup")
113116
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
@@ -1254,6 +1257,43 @@ func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, input
12541257
return
12551258
}
12561259

1260+
func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) {
1261+
r0, _, e1 := Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0)
1262+
handle = Handle(r0)
1263+
if handle == InvalidHandle {
1264+
if e1 != 0 {
1265+
err = error(e1)
1266+
} else {
1267+
err = EINVAL
1268+
}
1269+
}
1270+
return
1271+
}
1272+
1273+
func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) {
1274+
r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
1275+
if r1 == 0 {
1276+
if e1 != 0 {
1277+
err = error(e1)
1278+
} else {
1279+
err = EINVAL
1280+
}
1281+
}
1282+
return
1283+
}
1284+
1285+
func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) {
1286+
r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
1287+
if r1 == 0 {
1288+
if e1 != 0 {
1289+
err = error(e1)
1290+
} else {
1291+
err = EINVAL
1292+
}
1293+
}
1294+
return
1295+
}
1296+
12571297
func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
12581298
r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
12591299
if r0 != 0 {

src/pkg/syscall/zsyscall_windows_amd64.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ var (
108108
procGetConsoleMode = modkernel32.NewProc("GetConsoleMode")
109109
procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
110110
procReadConsoleW = modkernel32.NewProc("ReadConsoleW")
111+
procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
112+
procProcess32FirstW = modkernel32.NewProc("Process32FirstW")
113+
procProcess32NextW = modkernel32.NewProc("Process32NextW")
111114
procWSAStartup = modws2_32.NewProc("WSAStartup")
112115
procWSACleanup = modws2_32.NewProc("WSACleanup")
113116
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
@@ -1254,6 +1257,43 @@ func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, input
12541257
return
12551258
}
12561259

1260+
func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) {
1261+
r0, _, e1 := Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0)
1262+
handle = Handle(r0)
1263+
if handle == InvalidHandle {
1264+
if e1 != 0 {
1265+
err = error(e1)
1266+
} else {
1267+
err = EINVAL
1268+
}
1269+
}
1270+
return
1271+
}
1272+
1273+
func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) {
1274+
r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
1275+
if r1 == 0 {
1276+
if e1 != 0 {
1277+
err = error(e1)
1278+
} else {
1279+
err = EINVAL
1280+
}
1281+
}
1282+
return
1283+
}
1284+
1285+
func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) {
1286+
r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
1287+
if r1 == 0 {
1288+
if e1 != 0 {
1289+
err = error(e1)
1290+
} else {
1291+
err = EINVAL
1292+
}
1293+
}
1294+
return
1295+
}
1296+
12571297
func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
12581298
r0, _, _ := Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
12591299
if r0 != 0 {

src/pkg/syscall/ztypes_windows.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,17 @@ const (
175175
CTRL_BREAK_EVENT = 1
176176
)
177177

178+
const (
179+
// flags for CreateToolhelp32Snapshot
180+
TH32CS_SNAPHEAPLIST = 0x01
181+
TH32CS_SNAPPROCESS = 0x02
182+
TH32CS_SNAPTHREAD = 0x04
183+
TH32CS_SNAPMODULE = 0x08
184+
TH32CS_SNAPMODULE32 = 0x10
185+
TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
186+
TH32CS_INHERIT = 0x80000000
187+
)
188+
178189
const (
179190
// do not reorder
180191
FILE_NOTIFY_CHANGE_FILE_NAME = 1 << iota
@@ -462,6 +473,19 @@ type ProcessInformation struct {
462473
ThreadId uint32
463474
}
464475

476+
type ProcessEntry32 struct {
477+
Size uint32
478+
Usage uint32
479+
ProcessID uint32
480+
DefaultHeapID uintptr
481+
ModuleID uint32
482+
Threads uint32
483+
ParentProcessID uint32
484+
PriClassBase int32
485+
Flags uint32
486+
ExeFile [MAX_PATH]uint16
487+
}
488+
465489
type Systemtime struct {
466490
Year uint16
467491
Month uint16

0 commit comments

Comments
 (0)