ntdll: Add support for querying thread suspend count.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7082ebc608
commit
b0951ba860
|
@ -50,6 +50,7 @@ static ULONG (WINAPI *pRtlRemoveVectoredContinueHandler)(PVOID handler);
|
|||
static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*);
|
||||
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
|
||||
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
|
||||
static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE, THREADINFOCLASS, PVOID, ULONG, PULONG);
|
||||
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
|
||||
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
|
||||
static NTSTATUS (WINAPI *pNtClose)(HANDLE);
|
||||
|
@ -3163,11 +3164,34 @@ static DWORD WINAPI suspend_thread_test( void *arg )
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void test_suspend_thread(void)
|
||||
static void test_suspend_count(HANDLE hthread, ULONG expected_count, int line)
|
||||
{
|
||||
HANDLE thread, event;
|
||||
static BOOL supported = TRUE;
|
||||
NTSTATUS status;
|
||||
ULONG count;
|
||||
|
||||
if (!supported)
|
||||
return;
|
||||
|
||||
count = ~0u;
|
||||
status = pNtQueryInformationThread(hthread, ThreadSuspendCount, &count, sizeof(count), NULL);
|
||||
if (status)
|
||||
{
|
||||
win_skip("ThreadSuspendCount is not supported.\n");
|
||||
supported = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
ok_(__FILE__, line)(!status, "Failed to get suspend count, status %#x.\n", status);
|
||||
ok_(__FILE__, line)(count == expected_count, "Unexpected suspend count %u.\n", count);
|
||||
}
|
||||
|
||||
static void test_suspend_thread(void)
|
||||
{
|
||||
#define TEST_SUSPEND_COUNT(thread, count) test_suspend_count((thread), (count), __LINE__)
|
||||
HANDLE thread, event;
|
||||
ULONG count, len;
|
||||
NTSTATUS status;
|
||||
DWORD ret;
|
||||
|
||||
status = NtSuspendThread(0, NULL);
|
||||
|
@ -3184,6 +3208,31 @@ static void test_suspend_thread(void)
|
|||
ret = WaitForSingleObject(thread, 0);
|
||||
ok(ret == WAIT_TIMEOUT, "Unexpected status %d.\n", ret);
|
||||
|
||||
status = pNtQueryInformationThread(thread, ThreadSuspendCount, &count, sizeof(count), NULL);
|
||||
if (!status)
|
||||
{
|
||||
status = pNtQueryInformationThread(thread, ThreadSuspendCount, NULL, sizeof(count), NULL);
|
||||
ok(status == STATUS_ACCESS_VIOLATION, "Unexpected status %#x.\n", status);
|
||||
|
||||
status = pNtQueryInformationThread(thread, ThreadSuspendCount, &count, sizeof(count) / 2, NULL);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#x.\n", status);
|
||||
|
||||
len = 123;
|
||||
status = pNtQueryInformationThread(thread, ThreadSuspendCount, &count, sizeof(count) / 2, &len);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#x.\n", status);
|
||||
ok(len == 123, "Unexpected info length %u.\n", len);
|
||||
|
||||
len = 123;
|
||||
status = pNtQueryInformationThread(thread, ThreadSuspendCount, NULL, 0, &len);
|
||||
ok(status == STATUS_INFO_LENGTH_MISMATCH, "Unexpected status %#x.\n", status);
|
||||
ok(len == 123, "Unexpected info length %u.\n", len);
|
||||
|
||||
count = 10;
|
||||
status = pNtQueryInformationThread(0, ThreadSuspendCount, &count, sizeof(count), NULL);
|
||||
ok(status, "Unexpected status %#x.\n", status);
|
||||
ok(count == 10, "Unexpected suspend count %u.\n", count);
|
||||
}
|
||||
|
||||
status = NtResumeThread(thread, NULL);
|
||||
ok(!status, "Unexpected status %#x.\n", status);
|
||||
|
||||
|
@ -3191,24 +3240,35 @@ static void test_suspend_thread(void)
|
|||
ok(!status, "Unexpected status %#x.\n", status);
|
||||
ok(count == 0, "Unexpected suspended count %u.\n", count);
|
||||
|
||||
TEST_SUSPEND_COUNT(thread, 0);
|
||||
|
||||
status = NtSuspendThread(thread, NULL);
|
||||
ok(!status, "Failed to suspend a thread, status %#x.\n", status);
|
||||
|
||||
TEST_SUSPEND_COUNT(thread, 1);
|
||||
|
||||
status = NtSuspendThread(thread, &count);
|
||||
ok(!status, "Failed to suspend a thread, status %#x.\n", status);
|
||||
ok(count == 1, "Unexpected suspended count %u.\n", count);
|
||||
|
||||
TEST_SUSPEND_COUNT(thread, 2);
|
||||
|
||||
status = NtResumeThread(thread, &count);
|
||||
ok(!status, "Failed to resume a thread, status %#x.\n", status);
|
||||
ok(count == 2, "Unexpected suspended count %u.\n", count);
|
||||
|
||||
TEST_SUSPEND_COUNT(thread, 1);
|
||||
|
||||
status = NtResumeThread(thread, NULL);
|
||||
ok(!status, "Failed to resume a thread, status %#x.\n", status);
|
||||
|
||||
TEST_SUSPEND_COUNT(thread, 0);
|
||||
|
||||
SetEvent(event);
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
|
||||
CloseHandle(thread);
|
||||
#undef TEST_SUSPEND_COUNT
|
||||
}
|
||||
|
||||
static const char *suspend_process_event_name = "suspend_process_event";
|
||||
|
@ -3418,6 +3478,7 @@ START_TEST(exception)
|
|||
X(RtlAddVectoredContinueHandler);
|
||||
X(RtlRemoveVectoredContinueHandler);
|
||||
X(NtQueryInformationProcess);
|
||||
X(NtQueryInformationThread);
|
||||
X(NtSetInformationProcess);
|
||||
X(NtSuspendProcess);
|
||||
X(NtResumeProcess);
|
||||
|
|
|
@ -1115,6 +1115,27 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
|
|||
*(BOOL*)data = FALSE;
|
||||
if (ret_len) *ret_len = sizeof(BOOL);
|
||||
return STATUS_SUCCESS;
|
||||
case ThreadSuspendCount:
|
||||
{
|
||||
ULONG count = 0;
|
||||
|
||||
if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (!data) return STATUS_ACCESS_VIOLATION;
|
||||
|
||||
SERVER_START_REQ( get_thread_info )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
req->tid_in = 0;
|
||||
if (!(status = wine_server_call( req )))
|
||||
count = reply->suspend_count;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!status)
|
||||
*(ULONG *)data = count;
|
||||
|
||||
return status;
|
||||
}
|
||||
case ThreadDescription:
|
||||
{
|
||||
THREAD_DESCRIPTION_INFORMATION *info = data;
|
||||
|
|
|
@ -1006,8 +1006,10 @@ struct get_thread_info_reply
|
|||
int exit_code;
|
||||
int priority;
|
||||
int last;
|
||||
int suspend_count;
|
||||
data_size_t desc_len;
|
||||
/* VARARG(desc,unicode_str); */
|
||||
char __pad_60[4];
|
||||
};
|
||||
|
||||
|
||||
|
@ -6700,6 +6702,6 @@ union generic_reply
|
|||
struct resume_process_reply resume_process_reply;
|
||||
};
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 592
|
||||
#define SERVER_PROTOCOL_VERSION 593
|
||||
|
||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||
|
|
|
@ -1008,6 +1008,7 @@ typedef enum _THREADINFOCLASS {
|
|||
ThreadUmsInformation,
|
||||
ThreadCounterProfiling,
|
||||
ThreadIdealProcessorEx,
|
||||
ThreadSuspendCount = 35,
|
||||
ThreadDescription = 38,
|
||||
MaxThreadInfoClass
|
||||
} THREADINFOCLASS;
|
||||
|
|
|
@ -944,6 +944,7 @@ struct rawinput_device
|
|||
int exit_code; /* thread exit code */
|
||||
int priority; /* thread priority level */
|
||||
int last; /* last thread in process */
|
||||
int suspend_count; /* thread suspend count */
|
||||
data_size_t desc_len; /* description length in bytes */
|
||||
VARARG(desc,unicode_str); /* description string */
|
||||
@END
|
||||
|
|
|
@ -849,8 +849,9 @@ C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, affinity) == 32 );
|
|||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, exit_code) == 40 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, priority) == 44 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, last) == 48 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, desc_len) == 52 );
|
||||
C_ASSERT( sizeof(struct get_thread_info_reply) == 56 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, suspend_count) == 52 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, desc_len) == 56 );
|
||||
C_ASSERT( sizeof(struct get_thread_info_reply) == 64 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_times_request, handle) == 12 );
|
||||
C_ASSERT( sizeof(struct get_thread_times_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_thread_times_reply, creation_time) == 8 );
|
||||
|
|
|
@ -1463,6 +1463,7 @@ DECL_HANDLER(get_thread_info)
|
|||
reply->priority = thread->priority;
|
||||
reply->affinity = thread->affinity;
|
||||
reply->last = thread->process->running_threads == 1;
|
||||
reply->suspend_count = thread->suspend;
|
||||
reply->desc_len = thread->desc_len;
|
||||
|
||||
if (thread->desc && get_reply_max_size())
|
||||
|
|
|
@ -1423,6 +1423,7 @@ static void dump_get_thread_info_reply( const struct get_thread_info_reply *req
|
|||
fprintf( stderr, ", exit_code=%d", req->exit_code );
|
||||
fprintf( stderr, ", priority=%d", req->priority );
|
||||
fprintf( stderr, ", last=%d", req->last );
|
||||
fprintf( stderr, ", suspend_count=%d", req->suspend_count );
|
||||
fprintf( stderr, ", desc_len=%u", req->desc_len );
|
||||
dump_varargs_unicode_str( ", desc=", cur_size );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue