Commit 73c72390 authored by Alexandre Julliard's avatar Alexandre Julliard

Fixed Get/SetThreadContext to work properly on suspended threads.

Added a test case.
parent 9f9fd408
...@@ -607,6 +607,44 @@ static VOID test_GetThreadExitCode(void) ...@@ -607,6 +607,44 @@ static VOID test_GetThreadExitCode(void)
ok(CloseHandle(thread)!=0,"Error closing thread handle\n"); ok(CloseHandle(thread)!=0,"Error closing thread handle\n");
} }
#ifdef __i386__
static int test_value = 0;
static void set_test_val( int val )
{
test_value += val;
}
static DWORD WINAPI threadFunc6(LPVOID p)
{
test_value *= (int)p;
return 0;
}
static void test_SetThreadContext(void)
{
CONTEXT ctx;
int *stack;
HANDLE thread = CreateThread( NULL, 0, threadFunc6, (void *)2, CREATE_SUSPENDED, NULL );
ctx.ContextFlags = CONTEXT_FULL;
ok( GetThreadContext( thread, &ctx ), "GetThreadContext failed\n" );
/* simulate a call to set_test_val(10) */
stack = (int *)ctx.Esp;
stack[-1] = 10;
stack[-2] = ctx.Eip;
ctx.Esp -= 2 * sizeof(int *);
ctx.Eip = (DWORD)set_test_val;
ok( SetThreadContext( thread, &ctx ), "SetThreadContext failed\n" );
ResumeThread( thread );
WaitForSingleObject( thread, INFINITE );
ok( test_value == 20, "test_value %d instead of 20\n", test_value );
}
#endif /* __i386__ */
START_TEST(thread) START_TEST(thread)
{ {
HINSTANCE lib; HINSTANCE lib;
...@@ -628,4 +666,7 @@ START_TEST(thread) ...@@ -628,4 +666,7 @@ START_TEST(thread)
test_GetThreadTimes(); test_GetThreadTimes();
test_thread_processor(); test_thread_processor();
test_GetThreadExitCode(); test_GetThreadExitCode();
#ifdef __i386__
test_SetThreadContext();
#endif
} }
...@@ -143,6 +143,43 @@ extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_R ...@@ -143,6 +143,43 @@ extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_R
#endif #endif
/********************************************************************** /**********************************************************************
* wait_suspend
*
* Wait until the thread is no longer suspended.
*/
void wait_suspend( CONTEXT *context )
{
LARGE_INTEGER timeout;
/* store the context we got at suspend time */
SERVER_START_REQ( set_thread_context )
{
req->handle = GetCurrentThread();
req->flags = CONTEXT_FULL;
req->suspend = 1;
wine_server_add_data( req, context, sizeof(*context) );
wine_server_call( req );
}
SERVER_END_REQ;
/* wait with 0 timeout, will only return once the thread is no longer suspended */
timeout.QuadPart = 0;
NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 );
/* retrieve the new context */
SERVER_START_REQ( get_thread_context )
{
req->handle = GetCurrentThread();
req->flags = CONTEXT_FULL;
req->suspend = 1;
wine_server_set_reply( req, context, sizeof(*context) );
wine_server_call( req );
}
SERVER_END_REQ;
}
/**********************************************************************
* send_debug_event * send_debug_event
* *
* Send an EXCEPTION_DEBUG_EVENT event to the debugger. * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#define MAX_NT_PATH_LENGTH 277 #define MAX_NT_PATH_LENGTH 277
/* exceptions */
extern void wait_suspend( CONTEXT *context );
extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT ); extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
/* debug helper */ /* debug helper */
......
...@@ -85,7 +85,7 @@ typedef struct ...@@ -85,7 +85,7 @@ typedef struct
unsigned long i387; unsigned long i387;
unsigned long oldmask; unsigned long oldmask;
unsigned long cr2; unsigned long cr2;
} SIGCONTEXT; } volatile SIGCONTEXT;
#define HANDLER_DEF(name) void name( int __signal, SIGCONTEXT __context ) #define HANDLER_DEF(name) void name( int __signal, SIGCONTEXT __context )
#define HANDLER_CONTEXT (&__context) #define HANDLER_CONTEXT (&__context)
...@@ -641,12 +641,24 @@ typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); ...@@ -641,12 +641,24 @@ typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
* *
* Handler initialization when the full context is not needed. * Handler initialization when the full context is not needed.
*/ */
static void *init_handler( const SIGCONTEXT *sigcontext ) inline static void *init_handler( const SIGCONTEXT *sigcontext, WORD *fs, WORD *gs )
{ {
void *stack = (void *)ESP_sig(sigcontext); void *stack = (void *)ESP_sig(sigcontext);
TEB *teb = get_current_teb(); TEB *teb = get_current_teb();
struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2; struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
/* get %fs and %gs at time of the fault */
#ifdef FS_sig
*fs = LOWORD(FS_sig(sigcontext));
#else
*fs = wine_get_fs();
#endif
#ifdef GS_sig
*gs = LOWORD(GS_sig(sigcontext));
#else
*gs = wine_get_gs();
#endif
wine_set_fs( thread_data->teb_sel ); wine_set_fs( thread_data->teb_sel );
/* now restore a proper %gs for the fault handler */ /* now restore a proper %gs for the fault handler */
...@@ -718,6 +730,67 @@ inline static void restore_fpu( CONTEXT *context ) ...@@ -718,6 +730,67 @@ inline static void restore_fpu( CONTEXT *context )
/*********************************************************************** /***********************************************************************
* save_context
*
* Build a context structure from the signal info.
*/
inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
{
context->ContextFlags = CONTEXT_FULL;
context->Eax = EAX_sig(sigcontext);
context->Ebx = EBX_sig(sigcontext);
context->Ecx = ECX_sig(sigcontext);
context->Edx = EDX_sig(sigcontext);
context->Esi = ESI_sig(sigcontext);
context->Edi = EDI_sig(sigcontext);
context->Ebp = EBP_sig(sigcontext);
context->EFlags = EFL_sig(sigcontext);
context->Eip = EIP_sig(sigcontext);
context->Esp = ESP_sig(sigcontext);
context->SegCs = LOWORD(CS_sig(sigcontext));
context->SegDs = LOWORD(DS_sig(sigcontext));
context->SegEs = LOWORD(ES_sig(sigcontext));
context->SegFs = fs;
context->SegGs = gs;
context->SegSs = LOWORD(SS_sig(sigcontext));
}
/***********************************************************************
* restore_context
*
* Restore the signal info from the context.
*/
inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
{
EAX_sig(sigcontext) = context->Eax;
EBX_sig(sigcontext) = context->Ebx;
ECX_sig(sigcontext) = context->Ecx;
EDX_sig(sigcontext) = context->Edx;
ESI_sig(sigcontext) = context->Esi;
EDI_sig(sigcontext) = context->Edi;
EBP_sig(sigcontext) = context->Ebp;
EFL_sig(sigcontext) = context->EFlags;
EIP_sig(sigcontext) = context->Eip;
ESP_sig(sigcontext) = context->Esp;
CS_sig(sigcontext) = context->SegCs;
DS_sig(sigcontext) = context->SegDs;
ES_sig(sigcontext) = context->SegEs;
SS_sig(sigcontext) = context->SegSs;
#ifdef GS_sig
GS_sig(sigcontext) = context->SegGs;
#else
wine_set_gs( context->SegGs );
#endif
#ifdef FS_sig
FS_sig(sigcontext) = context->SegFs;
#else
wine_set_fs( context->SegFs );
#endif
}
/***********************************************************************
* setup_exception * setup_exception
* *
* Setup a proper stack frame for the raise function, and modify the * Setup a proper stack frame for the raise function, and modify the
...@@ -740,19 +813,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun ...@@ -740,19 +813,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
WORD fs, gs; WORD fs, gs;
/* get %fs and %gs at time of the fault */ stack = init_handler( sigcontext, &fs, &gs );
#ifdef FS_sig
fs = LOWORD(FS_sig(sigcontext));
#else
fs = wine_get_fs();
#endif
#ifdef GS_sig
gs = LOWORD(GS_sig(sigcontext));
#else
gs = wine_get_gs();
#endif
stack = init_handler( sigcontext );
/* stack sanity checks */ /* stack sanity checks */
...@@ -792,23 +853,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun ...@@ -792,23 +853,7 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext); stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext);
stack->rec.NumberParameters = 0; stack->rec.NumberParameters = 0;
stack->context.ContextFlags = CONTEXT_FULL; save_context( &stack->context, sigcontext, fs, gs );
stack->context.Eax = EAX_sig(sigcontext);
stack->context.Ebx = EBX_sig(sigcontext);
stack->context.Ecx = ECX_sig(sigcontext);
stack->context.Edx = EDX_sig(sigcontext);
stack->context.Esi = ESI_sig(sigcontext);
stack->context.Edi = EDI_sig(sigcontext);
stack->context.Ebp = EBP_sig(sigcontext);
stack->context.EFlags = EFL_sig(sigcontext);
stack->context.Eip = EIP_sig(sigcontext);
stack->context.Esp = ESP_sig(sigcontext);
stack->context.SegCs = LOWORD(CS_sig(sigcontext));
stack->context.SegDs = LOWORD(DS_sig(sigcontext));
stack->context.SegEs = LOWORD(ES_sig(sigcontext));
stack->context.SegFs = fs;
stack->context.SegGs = gs;
stack->context.SegSs = LOWORD(SS_sig(sigcontext));
/* now modify the sigcontext to return to the raise function */ /* now modify the sigcontext to return to the raise function */
ESP_sig(sigcontext) = (DWORD)stack; ESP_sig(sigcontext) = (DWORD)stack;
...@@ -1108,10 +1153,13 @@ static HANDLER_DEF(fpe_handler) ...@@ -1108,10 +1153,13 @@ static HANDLER_DEF(fpe_handler)
* int_handler * int_handler
* *
* Handler for SIGINT. * Handler for SIGINT.
*
* FIXME: should not be calling external functions on the signal stack.
*/ */
static HANDLER_DEF(int_handler) static HANDLER_DEF(int_handler)
{ {
init_handler( HANDLER_CONTEXT ); WORD fs, gs;
init_handler( HANDLER_CONTEXT, &fs, &gs );
if (!dispatch_signal(SIGINT)) if (!dispatch_signal(SIGINT))
{ {
EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, __regs_RtlRaiseException ); EXCEPTION_RECORD *rec = setup_exception( HANDLER_CONTEXT, __regs_RtlRaiseException );
...@@ -1139,7 +1187,8 @@ static HANDLER_DEF(abrt_handler) ...@@ -1139,7 +1187,8 @@ static HANDLER_DEF(abrt_handler)
*/ */
static HANDLER_DEF(term_handler) static HANDLER_DEF(term_handler)
{ {
init_handler( HANDLER_CONTEXT ); WORD fs, gs;
init_handler( HANDLER_CONTEXT, &fs, &gs );
server_abort_thread(0); server_abort_thread(0);
} }
...@@ -1151,12 +1200,13 @@ static HANDLER_DEF(term_handler) ...@@ -1151,12 +1200,13 @@ static HANDLER_DEF(term_handler)
*/ */
static HANDLER_DEF(usr1_handler) static HANDLER_DEF(usr1_handler)
{ {
LARGE_INTEGER timeout; WORD fs, gs;
CONTEXT context;
init_handler( HANDLER_CONTEXT ); init_handler( HANDLER_CONTEXT, &fs, &gs );
/* wait with 0 timeout, will only return once the thread is no longer suspended */ save_context( &context, HANDLER_CONTEXT, fs, gs );
timeout.QuadPart = 0; wait_suspend( &context );
NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); restore_context( &context, HANDLER_CONTEXT );
} }
...@@ -1198,6 +1248,7 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() ) ...@@ -1198,6 +1248,7 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() )
sig_act.ksa_handler = func; sig_act.ksa_handler = func;
sig_act.ksa_flags = SA_RESTART; sig_act.ksa_flags = SA_RESTART;
sig_act.ksa_mask = (1 << (SIGINT-1)) | sig_act.ksa_mask = (1 << (SIGINT-1)) |
(1 << (SIGUSR1-1)) |
(1 << (SIGUSR2-1)); (1 << (SIGUSR2-1));
/* point to the top of the signal stack */ /* point to the top of the signal stack */
sig_act.ksa_restorer = (char *)get_signal_stack() + signal_stack_size; sig_act.ksa_restorer = (char *)get_signal_stack() + signal_stack_size;
...@@ -1207,6 +1258,7 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() ) ...@@ -1207,6 +1258,7 @@ static int set_handler( int sig, int have_sigaltstack, void (*func)() )
sig_act.sa_handler = func; sig_act.sa_handler = func;
sigemptyset( &sig_act.sa_mask ); sigemptyset( &sig_act.sa_mask );
sigaddset( &sig_act.sa_mask, SIGINT ); sigaddset( &sig_act.sa_mask, SIGINT );
sigaddset( &sig_act.sa_mask, SIGUSR1 );
sigaddset( &sig_act.sa_mask, SIGUSR2 ); sigaddset( &sig_act.sa_mask, SIGUSR2 );
#if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
......
...@@ -577,11 +577,11 @@ static HANDLER_DEF(term_handler) ...@@ -577,11 +577,11 @@ static HANDLER_DEF(term_handler)
*/ */
static HANDLER_DEF(usr1_handler) static HANDLER_DEF(usr1_handler)
{ {
LARGE_INTEGER timeout; CONTEXT context;
/* wait with 0 timeout, will only return once the thread is no longer suspended */ save_context( &context, HANDLER_CONTEXT );
timeout.QuadPart = 0; wait_suspend( &context );
NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); restore_context( &context, HANDLER_CONTEXT );
} }
......
...@@ -384,11 +384,11 @@ static HANDLER_DEF(term_handler) ...@@ -384,11 +384,11 @@ static HANDLER_DEF(term_handler)
*/ */
static HANDLER_DEF(usr1_handler) static HANDLER_DEF(usr1_handler)
{ {
LARGE_INTEGER timeout; CONTEXT context;
/* wait with 0 timeout, will only return once the thread is no longer suspended */ save_context( &context, HANDLER_CONTEXT );
timeout.QuadPart = 0; wait_suspend( &context );
NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); restore_context( &context, HANDLER_CONTEXT );
} }
......
...@@ -408,11 +408,11 @@ static HANDLER_DEF(term_handler) ...@@ -408,11 +408,11 @@ static HANDLER_DEF(term_handler)
*/ */
static HANDLER_DEF(usr1_handler) static HANDLER_DEF(usr1_handler)
{ {
LARGE_INTEGER timeout; CONTEXT context;
/* wait with 0 timeout, will only return once the thread is no longer suspended */ save_context( &context, HANDLER_CONTEXT );
timeout.QuadPart = 0; wait_suspend( &context );
NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); restore_context( &context, HANDLER_CONTEXT );
} }
......
...@@ -485,15 +485,41 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1 ...@@ -485,15 +485,41 @@ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{ {
NTSTATUS ret; NTSTATUS ret;
DWORD dummy, i;
SERVER_START_REQ( set_thread_context ) SERVER_START_REQ( set_thread_context )
{ {
req->handle = handle; req->handle = handle;
req->flags = context->ContextFlags; req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_add_data( req, context, sizeof(*context) ); wine_server_add_data( req, context, sizeof(*context) );
ret = wine_server_call( req ); ret = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
if (ret == STATUS_PENDING)
{
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
{
for (i = 0; i < 100; i++)
{
SERVER_START_REQ( set_thread_context )
{
req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_add_data( req, context, sizeof(*context) );
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (ret != STATUS_PENDING) break;
NtYieldExecution();
}
NtResumeThread( handle, &dummy );
}
}
if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
return ret; return ret;
} }
...@@ -731,16 +757,42 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) ...@@ -731,16 +757,42 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
{ {
NTSTATUS ret; NTSTATUS ret;
CONTEXT ctx; CONTEXT ctx;
DWORD dummy, i;
SERVER_START_REQ( get_thread_context ) SERVER_START_REQ( get_thread_context )
{ {
req->handle = handle; req->handle = handle;
req->flags = context->ContextFlags; req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) ); wine_server_set_reply( req, &ctx, sizeof(ctx) );
ret = wine_server_call( req ); ret = wine_server_call( req );
} }
SERVER_END_REQ; SERVER_END_REQ;
if (ret == STATUS_PENDING)
{
if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
{
for (i = 0; i < 100; i++)
{
SERVER_START_REQ( get_thread_context )
{
req->handle = handle;
req->flags = context->ContextFlags;
req->suspend = 0;
wine_server_set_reply( req, &ctx, sizeof(ctx) );
ret = wine_server_call( req );
}
SERVER_END_REQ;
if (ret != STATUS_PENDING) break;
NtYieldExecution();
}
NtResumeThread( handle, &dummy );
}
}
if (ret == STATUS_SUCCESS) copy_context( context, &ctx, context->ContextFlags ); if (ret == STATUS_SUCCESS) copy_context( context, &ctx, context->ContextFlags );
else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
return ret; return ret;
} }
......
...@@ -1572,7 +1572,6 @@ struct get_exception_status_request ...@@ -1572,7 +1572,6 @@ struct get_exception_status_request
struct get_exception_status_reply struct get_exception_status_reply
{ {
struct reply_header __header; struct reply_header __header;
int status;
/* VARARG(context,context); */ /* VARARG(context,context); */
}; };
...@@ -1952,6 +1951,7 @@ struct get_thread_context_request ...@@ -1952,6 +1951,7 @@ struct get_thread_context_request
struct request_header __header; struct request_header __header;
obj_handle_t handle; obj_handle_t handle;
unsigned int flags; unsigned int flags;
int suspend;
}; };
struct get_thread_context_reply struct get_thread_context_reply
{ {
...@@ -1966,6 +1966,7 @@ struct set_thread_context_request ...@@ -1966,6 +1966,7 @@ struct set_thread_context_request
struct request_header __header; struct request_header __header;
obj_handle_t handle; obj_handle_t handle;
unsigned int flags; unsigned int flags;
int suspend;
/* VARARG(context,context); */ /* VARARG(context,context); */
}; };
struct set_thread_context_reply struct set_thread_context_reply
...@@ -4207,6 +4208,6 @@ union generic_reply ...@@ -4207,6 +4208,6 @@ union generic_reply
struct set_mailslot_info_reply set_mailslot_info_reply; struct set_mailslot_info_reply set_mailslot_info_reply;
}; };
#define SERVER_PROTOCOL_VERSION 196 #define SERVER_PROTOCOL_VERSION 197
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */ #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
...@@ -1401,6 +1401,7 @@ enum char_info_mode ...@@ -1401,6 +1401,7 @@ enum char_info_mode
@REQ(get_thread_context) @REQ(get_thread_context)
obj_handle_t handle; /* thread handle */ obj_handle_t handle; /* thread handle */
unsigned int flags; /* context flags */ unsigned int flags; /* context flags */
int suspend; /* if getting context during suspend */
@REPLY @REPLY
VARARG(context,context); /* thread context */ VARARG(context,context); /* thread context */
@END @END
...@@ -1410,6 +1411,7 @@ enum char_info_mode ...@@ -1410,6 +1411,7 @@ enum char_info_mode
@REQ(set_thread_context) @REQ(set_thread_context)
obj_handle_t handle; /* thread handle */ obj_handle_t handle; /* thread handle */
unsigned int flags; /* context flags */ unsigned int flags; /* context flags */
int suspend; /* if setting context during suspend */
VARARG(context,context); /* thread context */ VARARG(context,context); /* thread context */
@END @END
......
...@@ -118,6 +118,7 @@ inline static void init_thread_structure( struct thread *thread ) ...@@ -118,6 +118,7 @@ inline static void init_thread_structure( struct thread *thread )
thread->unix_pid = -1; /* not known yet */ thread->unix_pid = -1; /* not known yet */
thread->unix_tid = -1; /* not known yet */ thread->unix_tid = -1; /* not known yet */
thread->context = NULL; thread->context = NULL;
thread->suspend_context = NULL;
thread->teb = NULL; thread->teb = NULL;
thread->debug_ctx = NULL; thread->debug_ctx = NULL;
thread->debug_event = NULL; thread->debug_event = NULL;
...@@ -212,6 +213,7 @@ static void cleanup_thread( struct thread *thread ) ...@@ -212,6 +213,7 @@ static void cleanup_thread( struct thread *thread )
if (thread->request_fd) release_object( thread->request_fd ); if (thread->request_fd) release_object( thread->request_fd );
if (thread->reply_fd) release_object( thread->reply_fd ); if (thread->reply_fd) release_object( thread->reply_fd );
if (thread->wait_fd) release_object( thread->wait_fd ); if (thread->wait_fd) release_object( thread->wait_fd );
if (thread->suspend_context) free( thread->suspend_context );
free_msg_queue( thread ); free_msg_queue( thread );
cleanup_clipboard_thread(thread); cleanup_clipboard_thread(thread);
destroy_thread_windows( thread ); destroy_thread_windows( thread );
...@@ -229,19 +231,19 @@ static void cleanup_thread( struct thread *thread ) ...@@ -229,19 +231,19 @@ static void cleanup_thread( struct thread *thread )
thread->request_fd = NULL; thread->request_fd = NULL;
thread->reply_fd = NULL; thread->reply_fd = NULL;
thread->wait_fd = NULL; thread->wait_fd = NULL;
thread->context = NULL;
thread->suspend_context = NULL;
thread->desktop = 0; thread->desktop = 0;
} }
/* destroy a thread when its refcount is 0 */ /* destroy a thread when its refcount is 0 */
static void destroy_thread( struct object *obj ) static void destroy_thread( struct object *obj )
{ {
struct thread_apc *apc;
struct thread *thread = (struct thread *)obj; struct thread *thread = (struct thread *)obj;
assert( obj->ops == &thread_ops ); assert( obj->ops == &thread_ops );
assert( !thread->debug_ctx ); /* cannot still be debugging something */ assert( !thread->debug_ctx ); /* cannot still be debugging something */
list_remove( &thread->entry ); list_remove( &thread->entry );
while ((apc = thread_dequeue_apc( thread, 0 ))) free( apc );
cleanup_thread( thread ); cleanup_thread( thread );
release_object( thread->process ); release_object( thread->process );
if (thread->id) free_ptid( thread->id ); if (thread->id) free_ptid( thread->id );
...@@ -1053,7 +1055,27 @@ DECL_HANDLER(get_thread_context) ...@@ -1053,7 +1055,27 @@ DECL_HANDLER(get_thread_context)
} }
if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return; if (!(thread = get_thread_from_handle( req->handle, THREAD_GET_CONTEXT ))) return;
if ((data = set_reply_data_size( sizeof(CONTEXT) ))) if (req->suspend)
{
if (thread != current || !thread->suspend_context)
{
/* not suspended, shouldn't happen */
set_error( STATUS_INVALID_PARAMETER );
}
else
{
if (thread->context == thread->suspend_context) thread->context = NULL;
set_reply_data_ptr( thread->suspend_context, sizeof(CONTEXT) );
thread->suspend_context = NULL;
}
}
else if (thread != current && !thread->context)
{
/* thread is not suspended, retry (if it's still running) */
if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
else set_error( STATUS_PENDING );
}
else if ((data = set_reply_data_size( sizeof(CONTEXT) )))
{ {
memset( data, 0, sizeof(CONTEXT) ); memset( data, 0, sizeof(CONTEXT) );
get_thread_context( thread, data, req->flags ); get_thread_context( thread, data, req->flags );
...@@ -1071,11 +1093,32 @@ DECL_HANDLER(set_thread_context) ...@@ -1071,11 +1093,32 @@ DECL_HANDLER(set_thread_context)
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
return; return;
} }
if ((thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) if (!(thread = get_thread_from_handle( req->handle, THREAD_SET_CONTEXT ))) return;
if (req->suspend)
{
if (thread != current || thread->context)
{
/* nested suspend or exception, shouldn't happen */
set_error( STATUS_INVALID_PARAMETER );
}
else if ((thread->suspend_context = mem_alloc( sizeof(CONTEXT) )))
{
memcpy( thread->suspend_context, get_req_data(), sizeof(CONTEXT) );
thread->context = thread->suspend_context;
}
}
else if (thread != current && !thread->context)
{
/* thread is not suspended, retry (if it's still running) */
if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED );
else set_error( STATUS_PENDING );
}
else
{ {
set_thread_context( thread, get_req_data(), req->flags ); set_thread_context( thread, get_req_data(), req->flags );
release_object( thread );
} }
release_object( thread );
} }
/* fetch a selector entry for a thread */ /* fetch a selector entry for a thread */
......
...@@ -78,6 +78,7 @@ struct thread ...@@ -78,6 +78,7 @@ struct thread
int unix_pid; /* Unix pid of client */ int unix_pid; /* Unix pid of client */
int unix_tid; /* Unix tid of client */ int unix_tid; /* Unix tid of client */
CONTEXT *context; /* current context if in an exception handler */ CONTEXT *context; /* current context if in an exception handler */
CONTEXT *suspend_context; /* current context if suspended */
void *teb; /* TEB address (in client address space) */ void *teb; /* TEB address (in client address space) */
int priority; /* priority level */ int priority; /* priority level */
int affinity; /* affinity mask */ int affinity; /* affinity mask */
......
...@@ -1577,7 +1577,6 @@ static void dump_get_exception_status_request( const struct get_exception_status ...@@ -1577,7 +1577,6 @@ static void dump_get_exception_status_request( const struct get_exception_status
static void dump_get_exception_status_reply( const struct get_exception_status_reply *req ) static void dump_get_exception_status_reply( const struct get_exception_status_reply *req )
{ {
fprintf( stderr, " status=%d,", req->status );
fprintf( stderr, " context=" ); fprintf( stderr, " context=" );
dump_varargs_context( cur_size ); dump_varargs_context( cur_size );
} }
...@@ -1856,7 +1855,8 @@ static void dump_get_timer_info_reply( const struct get_timer_info_reply *req ) ...@@ -1856,7 +1855,8 @@ static void dump_get_timer_info_reply( const struct get_timer_info_reply *req )
static void dump_get_thread_context_request( const struct get_thread_context_request *req ) static void dump_get_thread_context_request( const struct get_thread_context_request *req )
{ {
fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " handle=%p,", req->handle );
fprintf( stderr, " flags=%08x", req->flags ); fprintf( stderr, " flags=%08x,", req->flags );
fprintf( stderr, " suspend=%d", req->suspend );
} }
static void dump_get_thread_context_reply( const struct get_thread_context_reply *req ) static void dump_get_thread_context_reply( const struct get_thread_context_reply *req )
...@@ -1869,6 +1869,7 @@ static void dump_set_thread_context_request( const struct set_thread_context_req ...@@ -1869,6 +1869,7 @@ static void dump_set_thread_context_request( const struct set_thread_context_req
{ {
fprintf( stderr, " handle=%p,", req->handle ); fprintf( stderr, " handle=%p,", req->handle );
fprintf( stderr, " flags=%08x,", req->flags ); fprintf( stderr, " flags=%08x,", req->flags );
fprintf( stderr, " suspend=%d,", req->suspend );
fprintf( stderr, " context=" ); fprintf( stderr, " context=" );
dump_varargs_context( cur_size ); dump_varargs_context( cur_size );
} }
...@@ -3740,6 +3741,7 @@ static const struct ...@@ -3740,6 +3741,7 @@ static const struct
{ "FILE_IS_A_DIRECTORY", STATUS_FILE_IS_A_DIRECTORY }, { "FILE_IS_A_DIRECTORY", STATUS_FILE_IS_A_DIRECTORY },
{ "FILE_LOCK_CONFLICT", STATUS_FILE_LOCK_CONFLICT }, { "FILE_LOCK_CONFLICT", STATUS_FILE_LOCK_CONFLICT },
{ "HANDLE_NOT_CLOSABLE", STATUS_HANDLE_NOT_CLOSABLE }, { "HANDLE_NOT_CLOSABLE", STATUS_HANDLE_NOT_CLOSABLE },
{ "INSTANCE_NOT_AVAILABLE", STATUS_INSTANCE_NOT_AVAILABLE },
{ "INVALID_CID", STATUS_INVALID_CID }, { "INVALID_CID", STATUS_INVALID_CID },
{ "INVALID_FILE_FOR_SECTION", STATUS_INVALID_FILE_FOR_SECTION }, { "INVALID_FILE_FOR_SECTION", STATUS_INVALID_FILE_FOR_SECTION },
{ "INVALID_HANDLE", STATUS_INVALID_HANDLE }, { "INVALID_HANDLE", STATUS_INVALID_HANDLE },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment