Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ntdll/thread.c | 52 ++++++++++++++++++++++++++++++++++ include/wine/server_protocol.h | 15 ++++++---- server/protocol.def | 12 +++++--- server/request.h | 1 + server/thread.c | 37 ++++++++++++++++++++++++ server/thread.h | 2 ++ server/trace.c | 3 ++ 7 files changed, 112 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 621aaddfe3..6079a6c195 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -1115,6 +1115,36 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, *(BOOL*)data = FALSE; if (ret_len) *ret_len = sizeof(BOOL); return STATUS_SUCCESS; + case ThreadDescription: + { + THREAD_DESCRIPTION_INFORMATION *info = data; + data_size_t len, desc_len = 0; + WCHAR *ptr; + + len = length >= sizeof(*info) ? length - sizeof(*info) : 0; + ptr = info ? (WCHAR *)(info + 1) : NULL; + + SERVER_START_REQ( get_thread_info ) + { + req->handle = wine_server_obj_handle( handle ); + if (ptr) wine_server_set_reply( req, ptr, len ); + status = wine_server_call( req ); + desc_len = reply->desc_len; + } + SERVER_END_REQ; + + if (!info) + status = STATUS_BUFFER_TOO_SMALL; + else if (status == STATUS_SUCCESS) + { + info->Length = desc_len << 16 | desc_len; + info->Description = ptr; + } + + if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL)) + *ret_len = sizeof(*info) + desc_len; + } + return status; case ThreadPriority: case ThreadBasePriority: case ThreadImpersonationToken: @@ -1270,6 +1300,28 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class, SERVER_END_REQ; } return status; + case ThreadDescription: + { + const THREAD_DESCRIPTION_INFORMATION *info = data; + data_size_t desc_len; + + if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH; + if (!info) return STATUS_ACCESS_VIOLATION; + + desc_len = info->Length & 0xffff; + if (info->Length >> 16 != desc_len) return STATUS_INVALID_PARAMETER; + if (info->Length && !info->Description) return STATUS_ACCESS_VIOLATION; + + SERVER_START_REQ( set_thread_info ) + { + req->handle = wine_server_obj_handle( handle ); + req->mask = SET_THREAD_INFO_DESCRIPTION; + wine_server_add_data( req, info->Description, desc_len ); + status = wine_server_call( req ); + } + SERVER_END_REQ; + } + return status; case ThreadBasicInformation: case ThreadTimes: case ThreadPriority: diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 0712170c80..108701b2bc 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1006,7 +1006,8 @@ struct get_thread_info_reply int exit_code; int priority; int last; - char __pad_52[4]; + data_size_t desc_len; + /* VARARG(desc,unicode_str); */ };
@@ -1034,16 +1035,18 @@ struct set_thread_info_request affinity_t affinity; client_ptr_t entry_point; obj_handle_t token; + /* VARARG(desc,unicode_str); */ char __pad_44[4]; }; struct set_thread_info_reply { struct reply_header __header; }; -#define SET_THREAD_INFO_PRIORITY 0x01 -#define SET_THREAD_INFO_AFFINITY 0x02 -#define SET_THREAD_INFO_TOKEN 0x04 -#define SET_THREAD_INFO_ENTRYPOINT 0x08 +#define SET_THREAD_INFO_PRIORITY 0x01 +#define SET_THREAD_INFO_AFFINITY 0x02 +#define SET_THREAD_INFO_TOKEN 0x04 +#define SET_THREAD_INFO_ENTRYPOINT 0x08 +#define SET_THREAD_INFO_DESCRIPTION 0x10
@@ -6697,6 +6700,6 @@ union generic_reply struct resume_process_reply resume_process_reply; };
-#define SERVER_PROTOCOL_VERSION 591 +#define SERVER_PROTOCOL_VERSION 592
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index c5c15ea1d7..566bc83bb2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -944,6 +944,8 @@ struct rawinput_device int exit_code; /* thread exit code */ int priority; /* thread priority level */ int last; /* last thread in process */ + data_size_t desc_len; /* description length in bytes */ + VARARG(desc,unicode_str); /* description string */ @END
@@ -964,11 +966,13 @@ struct rawinput_device affinity_t affinity; /* affinity mask */ client_ptr_t entry_point; /* thread entry point */ obj_handle_t token; /* impersonation token */ + VARARG(desc,unicode_str); /* description string */ @END -#define SET_THREAD_INFO_PRIORITY 0x01 -#define SET_THREAD_INFO_AFFINITY 0x02 -#define SET_THREAD_INFO_TOKEN 0x04 -#define SET_THREAD_INFO_ENTRYPOINT 0x08 +#define SET_THREAD_INFO_PRIORITY 0x01 +#define SET_THREAD_INFO_AFFINITY 0x02 +#define SET_THREAD_INFO_TOKEN 0x04 +#define SET_THREAD_INFO_ENTRYPOINT 0x08 +#define SET_THREAD_INFO_DESCRIPTION 0x10
/* Retrieve information about a module */ diff --git a/server/request.h b/server/request.h index f0d2003cd7..de7720ae68 100644 --- a/server/request.h +++ b/server/request.h @@ -849,6 +849,7 @@ 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_times_request, handle) == 12 ); C_ASSERT( sizeof(struct get_thread_times_request) == 16 ); diff --git a/server/thread.c b/server/thread.c index e753c8d0dd..1c16b4e467 100644 --- a/server/thread.c +++ b/server/thread.c @@ -51,6 +51,7 @@ #include "request.h" #include "user.h" #include "security.h" +#include "unicode.h"
#ifdef __i386__ @@ -201,6 +202,8 @@ static inline void init_thread_structure( struct thread *thread ) thread->suspend = 0; thread->desktop_users = 0; thread->token = NULL; + thread->desc = NULL; + thread->desc_len = 0;
thread->creation_time = current_time; thread->exit_time = 0; @@ -336,6 +339,7 @@ static void cleanup_thread( struct thread *thread ) thread->inflight[i].client = thread->inflight[i].server = -1; } } + free( thread->desc ); thread->req_data = NULL; thread->reply_data = NULL; thread->request_fd = NULL; @@ -344,6 +348,8 @@ static void cleanup_thread( struct thread *thread ) thread->context = NULL; thread->suspend_context = NULL; thread->desktop = 0; + thread->desc = NULL; + thread->desc_len = 0; }
/* destroy a thread when its refcount is 0 */ @@ -551,6 +557,28 @@ static void set_thread_info( struct thread *thread, security_set_thread_token( thread, req->token ); if (req->mask & SET_THREAD_INFO_ENTRYPOINT) thread->entry_point = req->entry_point; + if (req->mask & SET_THREAD_INFO_DESCRIPTION) + { + WCHAR *desc = NULL; + data_size_t desc_len = get_req_data_size(); + + if (desc_len) + { + if ((desc = mem_alloc( desc_len ))) + { + memcpy( desc, get_req_data(), desc_len ); + free( thread->desc ); + thread->desc = desc; + thread->desc_len = desc_len; + } + } + else + { + free( thread->desc ); + thread->desc = NULL; + thread->desc_len = 0; + } + } }
/* stop a thread (at the Unix level) */ @@ -1436,6 +1464,15 @@ DECL_HANDLER(get_thread_info) reply->priority = thread->priority; reply->affinity = thread->affinity; reply->last = thread->process->running_threads == 1; + reply->desc_len = thread->desc_len; + + if (thread->desc && get_reply_max_size()) + { + if (thread->desc_len <= get_reply_max_size()) + set_reply_data( thread->desc, thread->desc_len ); + else + set_error( STATUS_BUFFER_TOO_SMALL ); + }
release_object( thread ); } diff --git a/server/thread.h b/server/thread.h index e10120dcf6..66e35603d3 100644 --- a/server/thread.h +++ b/server/thread.h @@ -88,6 +88,8 @@ struct thread timeout_t exit_time; /* Thread exit time */ struct token *token; /* security token associated with this thread */ struct list kernel_object; /* list of kernel object pointers */ + data_size_t desc_len; /* thread description length in bytes */ + WCHAR *desc; /* thread description string */ };
struct thread_snapshot diff --git a/server/trace.c b/server/trace.c index 11df768755..d44f67a021 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1423,6 +1423,8 @@ 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, ", desc_len=%u", req->desc_len ); + dump_varargs_unicode_str( ", desc=", cur_size ); }
static void dump_get_thread_times_request( const struct get_thread_times_request *req ) @@ -1444,6 +1446,7 @@ static void dump_set_thread_info_request( const struct set_thread_info_request * dump_uint64( ", affinity=", &req->affinity ); dump_uint64( ", entry_point=", &req->entry_point ); fprintf( stderr, ", token=%04x", req->token ); + dump_varargs_unicode_str( ", desc=", cur_size ); }
static void dump_get_dll_info_request( const struct get_dll_info_request *req )
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- ...api-ms-win-core-processthreads-l1-1-3.spec | 2 +- dlls/kernel32/kernel32.spec | 1 + dlls/kernel32/tests/thread.c | 2 +- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/thread.c | 58 ++++++++++++++++++- 5 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/dlls/api-ms-win-core-processthreads-l1-1-3/api-ms-win-core-processthreads-l1-1-3.spec b/dlls/api-ms-win-core-processthreads-l1-1-3/api-ms-win-core-processthreads-l1-1-3.spec index 6f0c4fa752..9cc853d288 100644 --- a/dlls/api-ms-win-core-processthreads-l1-1-3/api-ms-win-core-processthreads-l1-1-3.spec +++ b/dlls/api-ms-win-core-processthreads-l1-1-3/api-ms-win-core-processthreads-l1-1-3.spec @@ -1,7 +1,7 @@ @ stub GetProcessDefaultCpuSets @ stub GetProcessInformation @ stub GetSystemCpuSetInformation -@ stub GetThreadDescription +@ stdcall GetThreadDescription(long ptr) kernel32.GetThreadDescription @ stub GetThreadSelectedCpuSets @ stub SetProcessDefaultCpuSets @ stub SetProcessInformation diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 367f5d2373..984422d2b4 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -847,6 +847,7 @@ @ stdcall -import GetTempPathA(long ptr) @ stdcall -import GetTempPathW(long ptr) @ stdcall -import GetThreadContext(long ptr) +@ stdcall -import GetThreadDescription(long ptr) @ stdcall -import GetThreadErrorMode() @ stdcall -import GetThreadGroupAffinity(long ptr) @ stdcall -import GetThreadIOPendingFlag(long ptr) diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index 180eed8241..8ff34ba5f3 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -2125,7 +2125,7 @@ static void test_thread_description(void)
if (!pGetThreadDescription) { - skip("Thread description API is not supported.\n"); + win_skip("Thread description API is not supported.\n"); return; }
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 7d20d3b112..6022d4ea37 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -711,7 +711,7 @@ @ stdcall GetTempPathA(long ptr) @ stdcall GetTempPathW(long ptr) @ stdcall GetThreadContext(long ptr) -# @ stub GetThreadDescription +@ stdcall GetThreadDescription(long ptr) @ stdcall GetThreadErrorMode() @ stdcall GetThreadGroupAffinity(long ptr) @ stdcall GetThreadIOPendingFlag(long ptr) diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index 345f44dff7..b8ce4bdb48 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -20,6 +20,7 @@
#include <stdarg.h> #include <string.h> +#include <limits.h>
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -33,6 +34,7 @@ #include "wine/exception.h" #include "wine/asm.h" #include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(thread);
@@ -392,10 +394,62 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetThreadContext( HANDLE thread, const CONTEXT *co */ HRESULT WINAPI /* DECLSPEC_HOTPATCH */ SetThreadDescription( HANDLE thread, PCWSTR description ) { - FIXME( "(%p %s): stub\n", thread, debugstr_w( description )); - return E_NOTIMPL; + THREAD_DESCRIPTION_INFORMATION info; + int length; + + TRACE( "(%p, %s)\n", thread, debugstr_w( description )); + + length = description ? lstrlenW( description ) * sizeof(WCHAR) : 0; + + if (length > USHRT_MAX) + return HRESULT_FROM_NT(STATUS_INVALID_PARAMETER); + + info.Length = length << 16 | length; + info.Description = (WCHAR *)description; + + return HRESULT_FROM_NT(NtSetInformationThread( thread, ThreadDescription, &info, sizeof(info) )); }
+/*********************************************************************** + * GetThreadDescription (kernelbase.@) + */ +HRESULT WINAPI /* DECLSPEC_HOTPATCH */ GetThreadDescription( HANDLE thread, WCHAR **description ) +{ + THREAD_DESCRIPTION_INFORMATION *info; + NTSTATUS status; + ULONG length; + + TRACE( "(%p, %p)\n", thread, description ); + + *description = NULL; + + length = 0; + status = NtQueryInformationThread( thread, ThreadDescription, NULL, 0, &length ); + if (status != STATUS_BUFFER_TOO_SMALL) + return HRESULT_FROM_NT(status); + + if (!(info = heap_alloc( length ))) + return HRESULT_FROM_NT(STATUS_NO_MEMORY); + + status = NtQueryInformationThread( thread, ThreadDescription, info, length, &length ); + if (!status) + { + length = info->Length & 0xffff; + + if (!(*description = LocalAlloc( 0, length + sizeof(WCHAR)))) + status = STATUS_NO_MEMORY; + else + { + if (length) + memcpy(*description, info->Description, length); + (*description)[length / sizeof(WCHAR)] = 0; + } + } + + heap_free(info); + + return HRESULT_FROM_NT(status); +}
/*********************************************************************** * SetThreadErrorMode (kernelbase.@)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=60863
Your paranoid android.
=== debian10 (32 bit WoW report) ===
kernel32: comm.c:918: Test failed: OutQueue should not be empty