1 11
import math
2 11
from . import _timeouts
3 11
import trio
4 11
from ._core._windows_cffi import (
5
    ffi,
6
    kernel32,
7
    ErrorCodes,
8
    raise_winerror,
9
    _handle,
10
)
11

12

13 11
async def WaitForSingleObject(obj):
14
    """Async and cancellable variant of WaitForSingleObject. Windows only.
15

16
    Args:
17
      handle: A Win32 handle, as a Python integer.
18

19
    Raises:
20
      OSError: If the handle is invalid, e.g. when it is already closed.
21

22
    """
23
    # Allow ints or whatever we can convert to a win handle
24 11
    handle = _handle(obj)
25

26
    # Quick check; we might not even need to spawn a thread. The zero
27
    # means a zero timeout; this call never blocks. We also exit here
28
    # if the handle is already closed for some reason.
29 11
    retcode = kernel32.WaitForSingleObject(handle, 0)
30 27
    if retcode == ErrorCodes.WAIT_FAILED:
31 11
        raise_winerror()
32 27
    elif retcode != ErrorCodes.WAIT_TIMEOUT:
33 11
        return
34

35
    # Wait for a thread that waits for two handles: the handle plus a handle
36
    # that we can use to cancel the thread.
37 11
    cancel_handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
38 11
    try:
39 11
        await trio.to_thread.run_sync(
40
            WaitForMultipleObjects_sync,
41
            handle,
42
            cancel_handle,
43
            cancellable=True,
44
            limiter=trio.CapacityLimiter(math.inf),
45
        )
46
    finally:
47
        # Clean up our cancel handle. In case we get here because this task was
48
        # cancelled, we also want to set the cancel_handle to stop the thread.
49 11
        kernel32.SetEvent(cancel_handle)
50 11
        kernel32.CloseHandle(cancel_handle)
51

52

53 11
def WaitForMultipleObjects_sync(*handles):
54
    """Wait for any of the given Windows handles to be signaled."""
55 11
    n = len(handles)
56 11
    handle_arr = ffi.new("HANDLE[{}]".format(n))
57 27
    for i in range(n):
58 11
        handle_arr[i] = handles[i]
59 11
    timeout = 0xFFFFFFFF  # INFINITE
60 11
    retcode = kernel32.WaitForMultipleObjects(n, handle_arr, False, timeout)  # blocking
61 27
    if retcode == ErrorCodes.WAIT_FAILED:
62 11
        raise_winerror()

Read our documentation on viewing source code .

Loading