From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/unix/thread.c | 25 +++++++++++++++++++++---- server/protocol.def | 6 ++++-- server/thread.c | 28 ++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 60c833b0320..19ce0fb28a3 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1611,19 +1611,36 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, /****************************************************************************** * NtSuspendThread (NTDLL.@) */ -NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) +NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *ret_count ) { - unsigned int ret; + unsigned int ret, count = 0; + HANDLE wait_handle = NULL;
SERVER_START_REQ( suspend_thread ) { req->handle = wine_server_obj_handle( handle ); - if (!(ret = wine_server_call( req ))) + if (!(ret = wine_server_call( req )) || ret == STATUS_PENDING) { - if (count) *count = reply->count; + count = reply->count; + wait_handle = wine_server_ptr_handle( reply->wait_handle ); } } SERVER_END_REQ; + + if (ret == STATUS_PENDING && wait_handle) + { + NtWaitForSingleObject( wait_handle, FALSE, NULL ); + + SERVER_START_REQ( suspend_thread ) + { + req->handle = wine_server_obj_handle( handle ); + req->waited_handle = wine_server_obj_handle( wait_handle ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + } + + if (!ret && ret_count) *ret_count = count; return ret; }
diff --git a/server/protocol.def b/server/protocol.def index 13aea96e796..b26dbc79962 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1107,9 +1107,11 @@ typedef struct
/* Suspend a thread */ @REQ(suspend_thread) - obj_handle_t handle; /* thread handle */ + obj_handle_t handle; /* thread handle */ + obj_handle_t waited_handle; /* handle waited on */ @REPLY - int count; /* new suspend count */ + int count; /* new suspend count */ + obj_handle_t wait_handle; /* handle to wait on */ @END
diff --git a/server/thread.c b/server/thread.c index 56f57cefd8f..c41fd0a02dc 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1550,12 +1550,32 @@ DECL_HANDLER(suspend_thread) { struct thread *thread;
- if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) + if (req->waited_handle) { - if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED ); - else reply->count = suspend_thread( thread ); - release_object( thread ); + struct context *context; + + if (!(context = (struct context *)get_handle_obj( current->process, req->waited_handle, + 0, &context_ops ))) + return; + close_handle( current->process, req->waited_handle ); /* avoid extra server call */ + set_error( context->status ); + release_object( context ); + return; } + + if (!(thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) return; + + if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); + else + { + reply->count = suspend_thread( thread ); + if (!get_error() && thread != current && thread->context && thread->context->status == STATUS_PENDING) + { + set_error( STATUS_PENDING ); + reply->wait_handle = alloc_handle( current->process, thread->context, SYNCHRONIZE, 0 ); + } + } + release_object( thread ); }
/* resume a thread */