[PATCH v4 1/4] ntdll/tests: Test NtPowerInformation() with SystemExecutionState.

Chip Davis cdavis at codeweavers.com
Fri Sep 27 15:30:29 CDT 2019


Test interaction between SetThreadExecutionState(), PowerSetRequest(),
and this parameter.

Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---

Notes:
    v2: Test that, when a thread terminates, its execution state is cleaned up.
    v3: Fix warnings.
    v4: Move to ntdll. Get rid of new test executable.

 dlls/ntdll/tests/info.c | 184 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 184 insertions(+)

diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 93920714f215..91aff16a861a 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -41,6 +41,9 @@ static BOOL     (WINAPI * pGetLogicalProcessorInformationEx)(LOGICAL_PROCESSOR_R
 static DEP_SYSTEM_POLICY_TYPE (WINAPI * pGetSystemDEPPolicy)(void);
 static NTSTATUS (WINAPI * pNtOpenThread)(HANDLE *, ACCESS_MASK, const OBJECT_ATTRIBUTES *, const CLIENT_ID *);
 static NTSTATUS (WINAPI * pNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, void *, ULONG, ULONG *);
+static HANDLE (WINAPI *pPowerCreateRequest)(REASON_CONTEXT *);
+static BOOL (WINAPI *pPowerSetRequest)(HANDLE, POWER_REQUEST_TYPE);
+static BOOL (WINAPI *pPowerClearRequest)(HANDLE, POWER_REQUEST_TYPE);
 
 static BOOL is_wow64;
 
@@ -104,6 +107,10 @@ static BOOL InitFunctionPtrs(void)
 
     pGetLogicalProcessorInformationEx = (void *) GetProcAddress(hkernel32, "GetLogicalProcessorInformationEx");
 
+    pPowerCreateRequest = (void *) GetProcAddress(hkernel32, "PowerCreateRequest");
+    pPowerSetRequest = (void *) GetProcAddress(hkernel32, "PowerSetRequest");
+    pPowerClearRequest = (void *) GetProcAddress(hkernel32, "PowerClearRequest");
+
     return TRUE;
 }
 
@@ -1003,6 +1010,177 @@ static void test_query_processor_power_info(void)
     HeapFree(GetProcessHeap(), 0, ppi);
 }
 
+static void test_system_execution_state(void)
+{
+    EXECUTION_STATE es, old_es;
+    NTSTATUS status;
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+
+    old_es = SetThreadExecutionState(ES_SYSTEM_REQUIRED);
+    todo_wine ok(old_es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", old_es);
+
+    old_es = es;
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(es == old_es, "unexpected execution state 0x%08x vs 0x%08x\n", es, old_es);
+
+    old_es = SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
+    todo_wine ok(old_es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", old_es);
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    todo_wine ok(es & ES_DISPLAY_REQUIRED, "unexpected execution state 0x%08x\n", es);
+
+    old_es = SetThreadExecutionState(ES_CONTINUOUS);
+    ok(old_es == (ES_CONTINUOUS|ES_DISPLAY_REQUIRED), "unexpected execution state 0x%08x\n", old_es);
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+
+    old_es = SetThreadExecutionState(ES_DISPLAY_REQUIRED);
+    ok(old_es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", old_es);
+
+    old_es = es;
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(es == old_es, "unexpected execution state 0x%08x vs 0x%08x\n", es, old_es);
+}
+
+static HANDLE events[2];
+
+static DWORD CALLBACK execution_state_thread(LPVOID param)
+{
+    EXECUTION_STATE old_es;
+
+    SetThreadExecutionState(ES_SYSTEM_REQUIRED);
+    SignalObjectAndWait(events[0], events[1], INFINITE, FALSE);
+
+    old_es = SetThreadExecutionState(ES_DISPLAY_REQUIRED);
+    ok(old_es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", old_es);
+    SignalObjectAndWait(events[0], events[1], INFINITE, FALSE);
+
+    old_es = SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
+    ok(old_es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", old_es);
+    SignalObjectAndWait(events[0], events[1], INFINITE, FALSE);
+
+    old_es = SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
+    ok(old_es == (ES_CONTINUOUS|ES_SYSTEM_REQUIRED), "unexpected execution state 0x%08x\n", old_es);
+    SignalObjectAndWait(events[0], events[1], INFINITE, FALSE);
+
+    return 0;
+}
+
+static void test_system_execution_state_other_thread(void)
+{
+    HANDLE thread;
+    EXECUTION_STATE base_es, es;
+    NTSTATUS status;
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &base_es, sizeof(base_es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    trace("base execution state = 0x%08x\n", base_es);
+
+    events[0] = CreateEventW(NULL, FALSE, FALSE, NULL);
+    events[1] = CreateEventW(NULL, FALSE, FALSE, NULL);
+    thread = CreateThread(NULL, 0, execution_state_thread, NULL, 0, NULL);
+    ok(thread != NULL, "Failed to create thread, err %u\n", GetLastError());
+
+    WaitForSingleObject(events[0], INFINITE);
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(es == base_es, "unexpected execution state 0x%08x\n", es);
+    es = SetThreadExecutionState(0);
+    ok(es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", es);
+    SignalObjectAndWait(events[1], events[0], INFINITE, FALSE);
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(es == base_es, "unexpected execution state 0x%08x\n", es);
+    es = SetThreadExecutionState(0);
+    ok(es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", es);
+    SignalObjectAndWait(events[1], events[0], INFINITE, FALSE);
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    todo_wine ok(es & ES_SYSTEM_REQUIRED, "unexpected execution state 0x%08x\n", es);
+    es = SetThreadExecutionState(0);
+    todo_wine ok(es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", es);
+    SignalObjectAndWait(events[1], events[0], INFINITE, FALSE);
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    todo_wine ok(es & ES_DISPLAY_REQUIRED, "unexpected execution state 0x%08x\n", es);
+    es = SetThreadExecutionState(0);
+    todo_wine ok(es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", es);
+    SignalObjectAndWait(events[1], thread, INFINITE, FALSE);
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(es == base_es, "unexpected execution state 0x%08x\n", es);
+    es = SetThreadExecutionState(0);
+    todo_wine ok(es == ES_CONTINUOUS, "unexpected execution state 0x%08x\n", es);
+
+    CloseHandle(thread);
+    CloseHandle(events[0]);
+    CloseHandle(events[1]);
+}
+
+static void test_system_execution_state_power_request(void)
+{
+    HANDLE req;
+    REASON_CONTEXT reason;
+    BOOL ret;
+    NTSTATUS status;
+    EXECUTION_STATE base_es, es;
+    static WCHAR reasonW[] = {'W', 'i', 'n', 'e', ' ', 't', 'e', 's', 't', 0};
+
+    if (!pPowerCreateRequest)
+    {
+        win_skip("Power request objects unavailable\n");
+        return;
+    }
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &base_es, sizeof(base_es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    trace("base execution state = 0x%08x\n", base_es);
+
+    reason.Version = 0;
+    reason.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
+    reason.Reason.SimpleReasonString = reasonW;
+    req = pPowerCreateRequest(&reason);
+    todo_wine ok(req != INVALID_HANDLE_VALUE, "err %u\n", GetLastError());
+
+    ret = pPowerSetRequest(req, PowerRequestSystemRequired);
+    todo_wine ok(ret, "err %u\n", GetLastError());
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    todo_wine ok(es & ES_SYSTEM_REQUIRED, "unexpected execution state 0x%08x\n", es);
+
+    ret = pPowerClearRequest(req, PowerRequestSystemRequired);
+    todo_wine ok(ret, "err %u\n", GetLastError());
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(!(es & ES_SYSTEM_REQUIRED) || (base_es & ES_SYSTEM_REQUIRED), "unexpected execution state 0x%08x\n", es);
+
+    ret = pPowerSetRequest(req, PowerRequestDisplayRequired);
+    todo_wine ok(ret, "err %u\n", GetLastError());
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    todo_wine ok(es & ES_DISPLAY_REQUIRED, "unexpected execution state 0x%08x\n", es);
+
+    ret = CloseHandle(req);
+    todo_wine ok(ret, "err %u\n", GetLastError());
+
+    status = pNtPowerInformation(SystemExecutionState, NULL, 0, &es, sizeof(es));
+    ok(status == STATUS_SUCCESS, "status %08x\n", status);
+    ok(!(es & ES_DISPLAY_REQUIRED) || (base_es & ES_DISPLAY_REQUIRED), "unexpected execution state 0x%08x\n", es);
+}
+
 static void test_query_process_wow64(void)
 {
     NTSTATUS status;
@@ -2424,6 +2602,12 @@ START_TEST(info)
     trace("Starting test_query_processor_power_info()\n");
     test_query_processor_power_info();
 
+    /* 0x10 SystemExecutionState */
+    trace("Starting test_system_execution_state()\n");
+    test_system_execution_state();
+    test_system_execution_state_other_thread();
+    test_system_execution_state_power_request();
+
     /* NtQueryInformationProcess */
 
     /* 0x0 ProcessBasicInformation */
-- 
2.21.0




More information about the wine-devel mailing list