windows: Implement WaitForMultipleObjects

This is a very classic and highly useful Windows API that I'm surprised
it's still not here.

Change-Id: If54319099cd94dd727126c579dd5a681979321cd
Reviewed-on: https://go-review.googlesource.com/c/160937
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go
index 8a00b71..f72fa55 100644
--- a/windows/syscall_windows.go
+++ b/windows/syscall_windows.go
@@ -172,6 +172,7 @@
 //sys	GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
 //sys	DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
 //sys	WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
+//sys	waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff] = WaitForMultipleObjects
 //sys	GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW
 //sys	CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error)
 //sys	GetFileType(filehandle Handle) (n uint32, err error)
@@ -589,6 +590,18 @@
 	return procSetFileCompletionNotificationModes.Find()
 }
 
+func WaitForMultipleObjects(handles []Handle, waitAll bool, waitMilliseconds uint32) (event uint32, err error) {
+	// Every other win32 array API takes arguments as "pointer, count", except for this function. So we
+	// can't declare it as a usual [] type, because mksyscall will use the opposite order. We therefore
+	// trivially stub this ourselves.
+
+	var handlePtr *Handle
+	if len(handles) > 0 {
+		handlePtr = &handles[0]
+	}
+	return waitForMultipleObjects(uint32(len(handles)), uintptr(unsafe.Pointer(handlePtr)), waitAll, waitMilliseconds)
+}
+
 // net api calls
 
 const socket_error = uintptr(^uint32(0))
diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go
index fc56aec..e4b54e2 100644
--- a/windows/zsyscall_windows.go
+++ b/windows/zsyscall_windows.go
@@ -112,6 +112,7 @@
 	procGetProcessTimes                    = modkernel32.NewProc("GetProcessTimes")
 	procDuplicateHandle                    = modkernel32.NewProc("DuplicateHandle")
 	procWaitForSingleObject                = modkernel32.NewProc("WaitForSingleObject")
+	procWaitForMultipleObjects             = modkernel32.NewProc("WaitForMultipleObjects")
 	procGetTempPathW                       = modkernel32.NewProc("GetTempPathW")
 	procCreatePipe                         = modkernel32.NewProc("CreatePipe")
 	procGetFileType                        = modkernel32.NewProc("GetFileType")
@@ -1084,6 +1085,25 @@
 	return
 }
 
+func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) {
+	var _p0 uint32
+	if waitAll {
+		_p0 = 1
+	} else {
+		_p0 = 0
+	}
+	r0, _, e1 := syscall.Syscall6(procWaitForMultipleObjects.Addr(), 4, uintptr(count), uintptr(handles), uintptr(_p0), uintptr(waitMilliseconds), 0, 0)
+	event = uint32(r0)
+	if event == 0xffffffff {
+		if e1 != 0 {
+			err = errnoErr(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
 func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) {
 	r0, _, e1 := syscall.Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
 	n = uint32(r0)