You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
7.9 KiB
Python
221 lines
7.9 KiB
Python
import os
|
|
|
|
import pytest
|
|
|
|
on_windows = os.name == "nt"
|
|
# Mark all the tests in this file as being windows-only
|
|
pytestmark = pytest.mark.skipif(not on_windows, reason="windows only")
|
|
|
|
from .._core.tests.tutil import slow
|
|
import trio
|
|
from .. import _core
|
|
from .. import _timeouts
|
|
|
|
if on_windows:
|
|
from .._core._windows_cffi import ffi, kernel32
|
|
from .._wait_for_object import (
|
|
WaitForSingleObject,
|
|
WaitForMultipleObjects_sync,
|
|
)
|
|
|
|
|
|
async def test_WaitForMultipleObjects_sync():
|
|
# This does a series of tests where we set/close the handle before
|
|
# initiating the waiting for it.
|
|
#
|
|
# Note that closing the handle (not signaling) will cause the
|
|
# *initiation* of a wait to return immediately. But closing a handle
|
|
# that is already being waited on will not stop whatever is waiting
|
|
# for it.
|
|
|
|
# One handle
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.SetEvent(handle1)
|
|
WaitForMultipleObjects_sync(handle1)
|
|
kernel32.CloseHandle(handle1)
|
|
print("test_WaitForMultipleObjects_sync one OK")
|
|
|
|
# Two handles, signal first
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle2 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.SetEvent(handle1)
|
|
WaitForMultipleObjects_sync(handle1, handle2)
|
|
kernel32.CloseHandle(handle1)
|
|
kernel32.CloseHandle(handle2)
|
|
print("test_WaitForMultipleObjects_sync set first OK")
|
|
|
|
# Two handles, signal second
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle2 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.SetEvent(handle2)
|
|
WaitForMultipleObjects_sync(handle1, handle2)
|
|
kernel32.CloseHandle(handle1)
|
|
kernel32.CloseHandle(handle2)
|
|
print("test_WaitForMultipleObjects_sync set second OK")
|
|
|
|
# Two handles, close first
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle2 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.CloseHandle(handle1)
|
|
with pytest.raises(OSError):
|
|
WaitForMultipleObjects_sync(handle1, handle2)
|
|
kernel32.CloseHandle(handle2)
|
|
print("test_WaitForMultipleObjects_sync close first OK")
|
|
|
|
# Two handles, close second
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle2 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.CloseHandle(handle2)
|
|
with pytest.raises(OSError):
|
|
WaitForMultipleObjects_sync(handle1, handle2)
|
|
kernel32.CloseHandle(handle1)
|
|
print("test_WaitForMultipleObjects_sync close second OK")
|
|
|
|
|
|
@slow
|
|
async def test_WaitForMultipleObjects_sync_slow():
|
|
# This does a series of test in which the main thread sync-waits for
|
|
# handles, while we spawn a thread to set the handles after a short while.
|
|
|
|
TIMEOUT = 0.3
|
|
|
|
# One handle
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
t0 = _core.current_time()
|
|
async with _core.open_nursery() as nursery:
|
|
nursery.start_soon(
|
|
trio.to_thread.run_sync, WaitForMultipleObjects_sync, handle1
|
|
)
|
|
await _timeouts.sleep(TIMEOUT)
|
|
# If we would comment the line below, the above thread will be stuck,
|
|
# and Trio won't exit this scope
|
|
kernel32.SetEvent(handle1)
|
|
t1 = _core.current_time()
|
|
assert TIMEOUT <= (t1 - t0) < 2.0 * TIMEOUT
|
|
kernel32.CloseHandle(handle1)
|
|
print("test_WaitForMultipleObjects_sync_slow one OK")
|
|
|
|
# Two handles, signal first
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle2 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
t0 = _core.current_time()
|
|
async with _core.open_nursery() as nursery:
|
|
nursery.start_soon(
|
|
trio.to_thread.run_sync, WaitForMultipleObjects_sync, handle1, handle2
|
|
)
|
|
await _timeouts.sleep(TIMEOUT)
|
|
kernel32.SetEvent(handle1)
|
|
t1 = _core.current_time()
|
|
assert TIMEOUT <= (t1 - t0) < 2.0 * TIMEOUT
|
|
kernel32.CloseHandle(handle1)
|
|
kernel32.CloseHandle(handle2)
|
|
print("test_WaitForMultipleObjects_sync_slow thread-set first OK")
|
|
|
|
# Two handles, signal second
|
|
handle1 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle2 = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
t0 = _core.current_time()
|
|
async with _core.open_nursery() as nursery:
|
|
nursery.start_soon(
|
|
trio.to_thread.run_sync, WaitForMultipleObjects_sync, handle1, handle2
|
|
)
|
|
await _timeouts.sleep(TIMEOUT)
|
|
kernel32.SetEvent(handle2)
|
|
t1 = _core.current_time()
|
|
assert TIMEOUT <= (t1 - t0) < 2.0 * TIMEOUT
|
|
kernel32.CloseHandle(handle1)
|
|
kernel32.CloseHandle(handle2)
|
|
print("test_WaitForMultipleObjects_sync_slow thread-set second OK")
|
|
|
|
|
|
async def test_WaitForSingleObject():
|
|
# This does a series of test for setting/closing the handle before
|
|
# initiating the wait.
|
|
|
|
# Test already set
|
|
handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.SetEvent(handle)
|
|
await WaitForSingleObject(handle) # should return at once
|
|
kernel32.CloseHandle(handle)
|
|
print("test_WaitForSingleObject already set OK")
|
|
|
|
# Test already set, as int
|
|
handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle_int = int(ffi.cast("intptr_t", handle))
|
|
kernel32.SetEvent(handle)
|
|
await WaitForSingleObject(handle_int) # should return at once
|
|
kernel32.CloseHandle(handle)
|
|
print("test_WaitForSingleObject already set OK")
|
|
|
|
# Test already closed
|
|
handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
kernel32.CloseHandle(handle)
|
|
with pytest.raises(OSError):
|
|
await WaitForSingleObject(handle) # should return at once
|
|
print("test_WaitForSingleObject already closed OK")
|
|
|
|
# Not a handle
|
|
with pytest.raises(TypeError):
|
|
await WaitForSingleObject("not a handle") # Wrong type
|
|
# with pytest.raises(OSError):
|
|
# await WaitForSingleObject(99) # If you're unlucky, it actually IS a handle :(
|
|
print("test_WaitForSingleObject not a handle OK")
|
|
|
|
|
|
@slow
|
|
async def test_WaitForSingleObject_slow():
|
|
# This does a series of test for setting the handle in another task,
|
|
# and cancelling the wait task.
|
|
|
|
# Set the timeout used in the tests. We test the waiting time against
|
|
# the timeout with a certain margin.
|
|
TIMEOUT = 0.3
|
|
|
|
async def signal_soon_async(handle):
|
|
await _timeouts.sleep(TIMEOUT)
|
|
kernel32.SetEvent(handle)
|
|
|
|
# Test handle is SET after TIMEOUT in separate coroutine
|
|
|
|
handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
t0 = _core.current_time()
|
|
|
|
async with _core.open_nursery() as nursery:
|
|
nursery.start_soon(WaitForSingleObject, handle)
|
|
nursery.start_soon(signal_soon_async, handle)
|
|
|
|
kernel32.CloseHandle(handle)
|
|
t1 = _core.current_time()
|
|
assert TIMEOUT <= (t1 - t0) < 2.0 * TIMEOUT
|
|
print("test_WaitForSingleObject_slow set from task OK")
|
|
|
|
# Test handle is SET after TIMEOUT in separate coroutine, as int
|
|
|
|
handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
handle_int = int(ffi.cast("intptr_t", handle))
|
|
t0 = _core.current_time()
|
|
|
|
async with _core.open_nursery() as nursery:
|
|
nursery.start_soon(WaitForSingleObject, handle_int)
|
|
nursery.start_soon(signal_soon_async, handle)
|
|
|
|
kernel32.CloseHandle(handle)
|
|
t1 = _core.current_time()
|
|
assert TIMEOUT <= (t1 - t0) < 2.0 * TIMEOUT
|
|
print("test_WaitForSingleObject_slow set from task as int OK")
|
|
|
|
# Test handle is CLOSED after 1 sec - NOPE see comment above
|
|
|
|
# Test cancellation
|
|
|
|
handle = kernel32.CreateEventA(ffi.NULL, True, False, ffi.NULL)
|
|
t0 = _core.current_time()
|
|
|
|
with _timeouts.move_on_after(TIMEOUT):
|
|
await WaitForSingleObject(handle)
|
|
|
|
kernel32.CloseHandle(handle)
|
|
t1 = _core.current_time()
|
|
assert TIMEOUT <= (t1 - t0) < 2.0 * TIMEOUT
|
|
print("test_WaitForSingleObject_slow cancellation OK")
|