windows: add TestJobObjectInfo

Add test for CL 251197.

Updates golang/go#41001

Change-Id: I6317678057eb8b18a1f7564842a92682c0c9930f
Reviewed-on: https://go-review.googlesource.com/c/sys/+/253097
Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go
index 62cf70e..2aa29e8 100644
--- a/windows/syscall_windows.go
+++ b/windows/syscall_windows.go
@@ -303,6 +303,7 @@
 //sys	ResumeThread(thread Handle) (ret uint32, err error) [failretval==0xffffffff] = kernel32.ResumeThread
 //sys	SetPriorityClass(process Handle, priorityClass uint32) (err error) = kernel32.SetPriorityClass
 //sys	GetPriorityClass(process Handle) (ret uint32, err error) = kernel32.GetPriorityClass
+//sys	QueryInformationJobObject(job Handle, JobObjectInformationClass int32, JobObjectInformation uintptr, JobObjectInformationLength uint32, retlen *uint32) (err error) = kernel32.QueryInformationJobObject
 //sys	SetInformationJobObject(job Handle, JobObjectInformationClass uint32, JobObjectInformation uintptr, JobObjectInformationLength uint32) (ret int, err error)
 //sys	GenerateConsoleCtrlEvent(ctrlEvent uint32, processGroupID uint32) (err error)
 //sys	GetProcessId(process Handle) (id uint32, err error)
diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go
index 0ee8d2c..2f1513f 100644
--- a/windows/syscall_windows_test.go
+++ b/windows/syscall_windows_test.go
@@ -14,6 +14,7 @@
 	"strings"
 	"syscall"
 	"testing"
+	"unsafe"
 
 	"golang.org/x/sys/windows"
 )
@@ -421,3 +422,39 @@
 		t.Error(err)
 	}
 }
+
+func TestJobObjectInfo(t *testing.T) {
+	jo, err := windows.CreateJobObject(nil, nil)
+	if err != nil {
+		t.Fatalf("CreateJobObject failed: %v", err)
+	}
+	defer windows.CloseHandle(jo)
+
+	var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION
+
+	err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
+		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
+	if err != nil {
+		t.Fatalf("QueryInformationJobObject failed: %v", err)
+	}
+
+	const wantMemLimit = 4 * 1024
+
+	info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY
+	info.ProcessMemoryLimit = wantMemLimit
+	_, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
+		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
+	if err != nil {
+		t.Fatalf("SetInformationJobObject failed: %v", err)
+	}
+
+	err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
+		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
+	if err != nil {
+		t.Fatalf("QueryInformationJobObject failed: %v", err)
+	}
+
+	if have := info.ProcessMemoryLimit; wantMemLimit != have {
+		t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have)
+	}
+}
diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go
index 8a562fe..347f13d 100644
--- a/windows/zsyscall_windows.go
+++ b/windows/zsyscall_windows.go
@@ -212,6 +212,7 @@
 	procResumeThread                                         = modkernel32.NewProc("ResumeThread")
 	procSetPriorityClass                                     = modkernel32.NewProc("SetPriorityClass")
 	procGetPriorityClass                                     = modkernel32.NewProc("GetPriorityClass")
+	procQueryInformationJobObject                            = modkernel32.NewProc("QueryInformationJobObject")
 	procSetInformationJobObject                              = modkernel32.NewProc("SetInformationJobObject")
 	procGenerateConsoleCtrlEvent                             = modkernel32.NewProc("GenerateConsoleCtrlEvent")
 	procGetProcessId                                         = modkernel32.NewProc("GetProcessId")
@@ -2341,6 +2342,18 @@
 	return
 }
 
+func QueryInformationJobObject(job Handle, JobObjectInformationClass int32, JobObjectInformation uintptr, JobObjectInformationLength uint32, retlen *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall6(procQueryInformationJobObject.Addr(), 5, uintptr(job), uintptr(JobObjectInformationClass), uintptr(JobObjectInformation), uintptr(JobObjectInformationLength), uintptr(unsafe.Pointer(retlen)), 0)
+	if r1 == 0 {
+		if e1 != 0 {
+			err = errnoErr(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
 func SetInformationJobObject(job Handle, JobObjectInformationClass uint32, JobObjectInformation uintptr, JobObjectInformationLength uint32) (ret int, err error) {
 	r0, _, e1 := syscall.Syscall6(procSetInformationJobObject.Addr(), 4, uintptr(job), uintptr(JobObjectInformationClass), uintptr(JobObjectInformation), uintptr(JobObjectInformationLength), 0, 0)
 	ret = int(r0)