From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/info.c | 39 +++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/thread.c | 21 ++++++++++++++++++++- dlls/wow64/process.c | 1 + server/protocol.def | 4 +++- server/thread.c | 6 +++++- 5 files changed, 68 insertions(+), 3 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/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/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()) {