Module: wine Branch: master Commit: 4c9b39964cbc8d034265249d3af2212fea657304 URL: https://gitlab.winehq.org/wine/wine/-/commit/4c9b39964cbc8d034265249d3af2212...
Author: Paul Gofman pgofman@codeweavers.com Date: Tue Nov 28 17:21:17 2023 -0600
ntdll: Implement NtQueryInformationThread(ThreadIsTerminated).
---
dlls/ntdll/tests/info.c | 39 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/thread.c | 21 ++++++++++++++++++++- dlls/wow64/process.c | 1 + include/wine/server_protocol.h | 6 ++++-- server/protocol.def | 4 +++- server/request.h | 2 +- server/thread.c | 6 +++++- server/trace.c | 2 +- 8 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 3cedca0d6ef..68a9f165bfd 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -3697,6 +3697,44 @@ static void test_debuggee_dbgport(int argc, char **argv) winetest_pop_context(); }
+static DWORD WINAPI test_ThreadIsTerminated_thread( void *stop_event ) +{ + WaitForSingleObject( stop_event, INFINITE ); + return STATUS_PENDING; +} + +static void test_ThreadIsTerminated(void) +{ + HANDLE thread, stop_event; + ULONG terminated; + NTSTATUS status; + + stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + thread = CreateThread( NULL, 0, test_ThreadIsTerminated_thread, stop_event, 0, NULL ); + ok( thread != INVALID_HANDLE_VALUE, "failed, error %ld\n", GetLastError() ); + + status = pNtQueryInformationThread( thread, ThreadIsTerminated, &terminated, sizeof(terminated) * 2, NULL ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "got %#lx.\n", status ); + + terminated = 0xdeadbeef; + status = pNtQueryInformationThread( thread, ThreadIsTerminated, &terminated, sizeof(terminated), NULL ); + ok( !status, "got %#lx.\n", status ); + ok( !terminated, "got %lu.\n", terminated ); + + SetEvent( stop_event ); + WaitForSingleObject( thread, INFINITE ); + + status = pNtQueryInformationThread( thread, ThreadIsTerminated, &terminated, sizeof(terminated), NULL ); + ok( !status, "got %#lx.\n", status ); + ok( terminated == 1, "got %lu.\n", terminated ); + + CloseHandle(stop_event); + CloseHandle(thread); + + status = pNtQueryInformationThread( thread, ThreadIsTerminated, &terminated, sizeof(terminated), NULL ); + ok( status == STATUS_INVALID_HANDLE, "got %#lx.\n", status ); +} + START_TEST(info) { char **argv; @@ -3760,6 +3798,7 @@ START_TEST(info) test_thread_start_address(); test_thread_lookup(); test_thread_ideal_processor(); + test_ThreadIsTerminated();
test_affinity(); test_debug_object(); diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index c4653c6a769..9e84ec3cc96 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -2143,6 +2143,25 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, if (ret_len) *ret_len = sizeof(BOOL); return STATUS_SUCCESS;
+ case ThreadIsTerminated: + { + ULONG terminated; + + if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH; + SERVER_START_REQ( get_thread_info ) + { + req->handle = wine_server_obj_handle( handle ); + if (!(status = wine_server_call( req ))) terminated = !!(reply->flags & GET_THREAD_INFO_FLAG_TERMINATED); + } + SERVER_END_REQ; + if (!status) + { + *(ULONG *)data = terminated; + if (ret_len) *ret_len = sizeof(ULONG); + } + return status; + } + case ThreadSuspendCount: if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH; if (!data) return STATUS_ACCESS_VIOLATION; @@ -2196,7 +2215,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, req->handle = wine_server_obj_handle( handle ); req->access = THREAD_QUERY_INFORMATION; if ((status = wine_server_call( req ))) return status; - *(BOOLEAN*)data = reply->dbg_hidden; + *(BOOLEAN*)data = !!(reply->flags & GET_THREAD_INFO_FLAG_DBG_HIDDEN); } SERVER_END_REQ; if (ret_len) *ret_len = sizeof(BOOLEAN); diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index c144af7743c..817926d0f13 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -688,6 +688,7 @@ NTSTATUS WINAPI wow64_NtQueryInformationThread( UINT *args ) case ThreadEnableAlignmentFaultFixup: /* set only */ case ThreadAmILastThread: /* ULONG */ case ThreadIsIoPending: /* ULONG */ + case ThreadIsTerminated: /* ULONG */ case ThreadHideFromDebugger: /* BOOLEAN */ case ThreadSuspendCount: /* ULONG */ case ThreadPriorityBoost: /* ULONG */ diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index a392b532f4e..15156a12353 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1162,10 +1162,12 @@ struct get_thread_info_reply int priority; int last; int suspend_count; - int dbg_hidden; + unsigned int flags; data_size_t desc_len; /* VARARG(desc,unicode_str); */ }; +#define GET_THREAD_INFO_FLAG_DBG_HIDDEN 0x01 +#define GET_THREAD_INFO_FLAG_TERMINATED 0x02
@@ -6504,7 +6506,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 784 +#define SERVER_PROTOCOL_VERSION 785
/* ### protocol_version end ### */
diff --git a/server/protocol.def b/server/protocol.def index e9195df6b65..b4d6d74d6fc 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1085,10 +1085,12 @@ typedef struct int priority; /* thread priority level */ int last; /* last thread in process */ int suspend_count; /* thread suspend count */ - int dbg_hidden; /* thread hidden from debugger */ + unsigned int flags; /* GET_THREAD_INFO_FLAG_ flags */ data_size_t desc_len; /* description length in bytes */ VARARG(desc,unicode_str); /* description string */ @END +#define GET_THREAD_INFO_FLAG_DBG_HIDDEN 0x01 +#define GET_THREAD_INFO_FLAG_TERMINATED 0x02
/* Retrieve information about thread times */ diff --git a/server/request.h b/server/request.h index d6043c5fdc3..89d5a621b16 100644 --- a/server/request.h +++ b/server/request.h @@ -860,7 +860,7 @@ 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, suspend_count) == 52 ); -C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, dbg_hidden) == 56 ); +C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, flags) == 56 ); C_ASSERT( FIELD_OFFSET(struct get_thread_info_reply, desc_len) == 60 ); C_ASSERT( sizeof(struct get_thread_info_reply) == 64 ); C_ASSERT( FIELD_OFFSET(struct get_thread_times_request, handle) == 12 ); diff --git a/server/thread.c b/server/thread.c index 83ae381d5c5..50eddabe8eb 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1496,8 +1496,12 @@ DECL_HANDLER(get_thread_info) reply->affinity = thread->affinity; reply->last = thread->process->running_threads == 1; reply->suspend_count = thread->suspend; - reply->dbg_hidden = thread->dbg_hidden; reply->desc_len = thread->desc_len; + reply->flags = 0; + if (thread->dbg_hidden) + reply->flags |= GET_THREAD_INFO_FLAG_DBG_HIDDEN; + if (thread->state == TERMINATED) + reply->flags |= GET_THREAD_INFO_FLAG_TERMINATED;
if (thread->desc && get_reply_max_size()) { diff --git a/server/trace.c b/server/trace.c index 55ccefa1746..1b65d2b977e 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1604,7 +1604,7 @@ static void dump_get_thread_info_reply( const struct get_thread_info_reply *req fprintf( stderr, ", priority=%d", req->priority ); fprintf( stderr, ", last=%d", req->last ); fprintf( stderr, ", suspend_count=%d", req->suspend_count ); - fprintf( stderr, ", dbg_hidden=%d", req->dbg_hidden ); + fprintf( stderr, ", flags=%08x", req->flags ); fprintf( stderr, ", desc_len=%u", req->desc_len ); dump_varargs_unicode_str( ", desc=", cur_size ); }