From 70f4e408de566fcb64f1c8649fe05a22958255be Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Tue, 25 Jul 2023 19:17:12 +0000 Subject: [PATCH] unix: retry fetching of lists through sysctl if the size changes On macOS, the SysctlKinfoProcSlice() function may be used to fetch the contents of the process table. As the process table may grow between the first and second call to sysctl(), the second call may fail with ENOMEM. In that case we simply need to retry. Change-Id: I40229653ed383603c33762f37b0dc2e7de47bcb6 GitHub-Last-Rev: b63b6b847122e058977934c5af7841f47485177d GitHub-Pull-Request: golang/sys#169 Reviewed-on: https://go-review.googlesource.com/c/sys/+/513036 Run-TryBot: Ian Lance Taylor Auto-Submit: Ian Lance Taylor TryBot-Result: Gopher Robot Reviewed-by: Matthew Dempsky Run-TryBot: Ian Lance Taylor Reviewed-by: Ian Lance Taylor --- unix/syscall_darwin.go | 50 +++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/unix/syscall_darwin.go b/unix/syscall_darwin.go index 206921504..135cc3cd7 100644 --- a/unix/syscall_darwin.go +++ b/unix/syscall_darwin.go @@ -510,30 +510,36 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) { return nil, err } - // Find size. - n := uintptr(0) - if err := sysctl(mib, nil, &n, nil, 0); err != nil { - return nil, err - } - if n == 0 { - return nil, nil - } - if n%SizeofKinfoProc != 0 { - return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) - } + for { + // Find size. + n := uintptr(0) + if err := sysctl(mib, nil, &n, nil, 0); err != nil { + return nil, err + } + if n == 0 { + return nil, nil + } + if n%SizeofKinfoProc != 0 { + return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) + } - // Read into buffer of that size. - buf := make([]KinfoProc, n/SizeofKinfoProc) - if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil { - return nil, err - } - if n%SizeofKinfoProc != 0 { - return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) - } + // Read into buffer of that size. + buf := make([]KinfoProc, n/SizeofKinfoProc) + if err := sysctl(mib, (*byte)(unsafe.Pointer(&buf[0])), &n, nil, 0); err != nil { + if err == ENOMEM { + // Process table grew. Try again. + continue + } + return nil, err + } + if n%SizeofKinfoProc != 0 { + return nil, fmt.Errorf("sysctl() returned a size of %d, which is not a multiple of %d", n, SizeofKinfoProc) + } - // The actual call may return less than the original reported required - // size so ensure we deal with that. - return buf[:n/SizeofKinfoProc], nil + // The actual call may return less than the original reported required + // size so ensure we deal with that. + return buf[:n/SizeofKinfoProc], nil + } } //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)