Fixed Get/SetThreadContext to work properly on suspended threads.
Added a test case.
This commit is contained in:
parent
9f9fd4080b
commit
73c72390f8
|
@ -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)
|
||||||
test_GetThreadTimes();
|
test_GetThreadTimes();
|
||||||
test_thread_processor();
|
test_thread_processor();
|
||||||
test_GetThreadExitCode();
|
test_GetThreadExitCode();
|
||||||
|
#ifdef __i386__
|
||||||
|
test_SetThreadContext();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,6 +142,43 @@ extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_R
|
||||||
PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler);
|
PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler);
|
||||||
#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
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
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 );
|
||||||
*
|
*
|
||||||
* 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 */
|
||||||
|
@ -717,6 +729,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
|
||||||
*
|
*
|
||||||
|
@ -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
|
||||||
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)
|
||||||
* 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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)() )
|
||||||
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)() )
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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
|
||||||
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 )
|
||||||
{
|
{
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
@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
|
||||||
@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 )
|
||||||
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 )
|
||||||
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 )
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
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 )
|
||||||
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
|
||||||
{
|
{
|
||||||
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
|
||||||
{ "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 },
|
||||||
|
|
Loading…
Reference in New Issue