Patchwork [1,of,2,V2] win32: add a method to fetch the available pipe data size

login
register
mail settings
Submitter Matt Harbison
Date April 8, 2015, 3:30 a.m.
Message ID <baeeb5f4bd5980f87222.1428463841@Envy>
Download mbox | patch
Permalink /patch/8558/
State Accepted
Headers show

Comments

Matt Harbison - April 8, 2015, 3:30 a.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1428460225 14400
#      Tue Apr 07 22:30:25 2015 -0400
# Node ID baeeb5f4bd5980f8722221156bbee3c3329c448b
# Parent  54e5c239c2d9ad87fc2080fd9be35765cf0ebc9f
win32: add a method to fetch the available pipe data size

This will be used in the next patch to do nonblocking reads from the child
process, like on posix platforms.  See that for why os.fstat() is insufficient.
Yuya Nishihara - April 8, 2015, 12:33 p.m.
On Tue, 07 Apr 2015 23:30:41 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison@yahoo.com>
> # Date 1428460225 14400
> #      Tue Apr 07 22:30:25 2015 -0400
> # Node ID baeeb5f4bd5980f8722221156bbee3c3329c448b
> # Parent  54e5c239c2d9ad87fc2080fd9be35765cf0ebc9f
> win32: add a method to fetch the available pipe data size
> 
> This will be used in the next patch to do nonblocking reads from the child
> process, like on posix platforms.  See that for why os.fstat() is insufficient.
> 
> diff --git a/mercurial/win32.py b/mercurial/win32.py
> --- a/mercurial/win32.py
> +++ b/mercurial/win32.py
> @@ -5,7 +5,7 @@
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>  
> -import ctypes, errno, os, subprocess, random
> +import ctypes, errno, msvcrt, os, subprocess, random
>  
>  _kernel32 = ctypes.windll.kernel32
>  _advapi32 = ctypes.windll.advapi32
> @@ -26,6 +26,7 @@
>  _ERROR_SUCCESS = 0
>  _ERROR_NO_MORE_FILES = 18
>  _ERROR_INVALID_PARAMETER = 87
> +_ERROR_BROKEN_PIPE = 109
>  _ERROR_INSUFFICIENT_BUFFER = 122
>  
>  # WPARAM is defined as UINT_PTR (unsigned type)
> @@ -211,6 +212,10 @@
>  _kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD]
>  _kernel32.CreateToolhelp32Snapshot.restype = _BOOL
>  
> +_kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
> +    ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
> +_kernel32.PeekNamedPipe.restype = _BOOL
> +
>  _kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p]
>  _kernel32.Process32First.restype = _BOOL
>  
> @@ -260,6 +265,22 @@
>      res2 = _getfileinfo(path2)
>      return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
>  
> +def peekpipe(pipe):
> +    handle = msvcrt.get_osfhandle(pipe.fileno())
> +    if handle == -1:
> +        raise ctypes.WinError()

A nit, msvcrt.get_osfhandle() checks the invalid handle value by itself.

https://hg.python.org/cpython/file/v2.7.9/PC/msvcrtmodule.c#l136
Matt Harbison - April 8, 2015, 1:53 p.m.

Patch

diff --git a/mercurial/win32.py b/mercurial/win32.py
--- a/mercurial/win32.py
+++ b/mercurial/win32.py
@@ -5,7 +5,7 @@ 
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import ctypes, errno, os, subprocess, random
+import ctypes, errno, msvcrt, os, subprocess, random
 
 _kernel32 = ctypes.windll.kernel32
 _advapi32 = ctypes.windll.advapi32
@@ -26,6 +26,7 @@ 
 _ERROR_SUCCESS = 0
 _ERROR_NO_MORE_FILES = 18
 _ERROR_INVALID_PARAMETER = 87
+_ERROR_BROKEN_PIPE = 109
 _ERROR_INSUFFICIENT_BUFFER = 122
 
 # WPARAM is defined as UINT_PTR (unsigned type)
@@ -211,6 +212,10 @@ 
 _kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD]
 _kernel32.CreateToolhelp32Snapshot.restype = _BOOL
 
+_kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
+    ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
+_kernel32.PeekNamedPipe.restype = _BOOL
+
 _kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p]
 _kernel32.Process32First.restype = _BOOL
 
@@ -260,6 +265,22 @@ 
     res2 = _getfileinfo(path2)
     return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
 
+def peekpipe(pipe):
+    handle = msvcrt.get_osfhandle(pipe.fileno())
+    if handle == -1:
+        raise ctypes.WinError()
+
+    avail = _DWORD()
+
+    if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
+                                   None):
+        err = _kernel32.GetLastError()
+        if err == _ERROR_BROKEN_PIPE:
+            return 0
+        raise ctypes.WinError(err)
+
+    return avail.value
+
 def testpid(pid):
     '''return True if pid is still running or unable to
     determine, False otherwise'''