ntdll: Use KiUserApcDispatcher() to call user APCs.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2020-08-06 19:31:24 +02:00
parent 2a08e0e290
commit 7a71f98640
8 changed files with 121 additions and 42 deletions

View File

@ -96,6 +96,7 @@ extern IMAGE_NT_HEADERS __wine_spec_nt_header;
void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) = NULL; void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) = NULL;
void (WINAPI *pKiRaiseUserExceptionDispatcher)(void) = NULL; void (WINAPI *pKiRaiseUserExceptionDispatcher)(void) = NULL;
void (WINAPI *pKiUserApcDispatcher)(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR,PNTAPCFUNC) = NULL;
NTSTATUS (WINAPI *pKiUserExceptionDispatcher)(EXCEPTION_RECORD*,CONTEXT*) = NULL; NTSTATUS (WINAPI *pKiUserExceptionDispatcher)(EXCEPTION_RECORD*,CONTEXT*) = NULL;
void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PTR) = NULL; void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PTR) = NULL;
void (WINAPI *pRtlUserThreadStart)( PRTL_THREAD_START_ROUTINE entry, void *arg ) = NULL; void (WINAPI *pRtlUserThreadStart)( PRTL_THREAD_START_ROUTINE entry, void *arg ) = NULL;
@ -841,6 +842,7 @@ static void fixup_ntdll_imports( const IMAGE_NT_HEADERS *nt )
GET_FUNC( DbgUiRemoteBreakin ); GET_FUNC( DbgUiRemoteBreakin );
GET_FUNC( KiRaiseUserExceptionDispatcher ); GET_FUNC( KiRaiseUserExceptionDispatcher );
GET_FUNC( KiUserExceptionDispatcher ); GET_FUNC( KiUserExceptionDispatcher );
GET_FUNC( KiUserApcDispatcher );
GET_FUNC( LdrInitializeThunk ); GET_FUNC( LdrInitializeThunk );
GET_FUNC( RtlUserThreadStart ); GET_FUNC( RtlUserThreadStart );
GET_FUNC( __wine_set_unix_funcs ); GET_FUNC( __wine_set_unix_funcs );

View File

@ -349,23 +349,19 @@ static int wait_select_reply( void *cookie )
} }
static void invoke_apc( const user_apc_t *apc ) static void invoke_apc( CONTEXT *context, const user_apc_t *apc )
{ {
switch( apc->type ) switch( apc->type )
{ {
case APC_USER: case APC_USER:
{ call_user_apc( context, apc->user.args[0], apc->user.args[1], apc->user.args[2],
void (WINAPI *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR) = wine_server_get_ptr( apc->user.func ); wine_server_get_ptr( apc->user.func ));
func( apc->user.args[0], apc->user.args[1], apc->user.args[2] );
break; break;
}
case APC_TIMER: case APC_TIMER:
{ call_user_apc( context, (ULONG_PTR)wine_server_get_ptr( apc->user.args[1] ),
void (WINAPI *func)(void*, unsigned int, unsigned int) = wine_server_get_ptr( apc->user.func ); (DWORD)apc->timer.time, (DWORD)(apc->timer.time >> 32),
func( wine_server_get_ptr( apc->user.args[1] ), wine_server_get_ptr( apc->user.func ));
(DWORD)apc->timer.time, (DWORD)(apc->timer.time >> 32) );
break; break;
}
default: default:
server_protocol_error( "get_apc_request: bad type %d\n", apc->type ); server_protocol_error( "get_apc_request: bad type %d\n", apc->type );
break; break;
@ -672,7 +668,6 @@ unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT f
const LARGE_INTEGER *timeout ) const LARGE_INTEGER *timeout )
{ {
timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE; timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
BOOL user_apc = FALSE;
unsigned int ret; unsigned int ret;
user_apc_t apc; user_apc_t apc;
@ -684,33 +679,31 @@ unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT f
abs_timeout -= now.QuadPart; abs_timeout -= now.QuadPart;
} }
for (;;) ret = server_select( select_op, size, flags, abs_timeout, NULL, NULL, &apc );
{ if (ret == STATUS_USER_APC) invoke_apc( NULL, &apc );
ret = server_select( select_op, size, flags, abs_timeout, NULL, NULL, &apc );
if (ret != STATUS_USER_APC) break;
invoke_apc( &apc );
/* if we ran a user apc we have to check once more if additional apcs are queued,
* but we don't want to wait */
abs_timeout = 0;
user_apc = TRUE;
size = 0;
/* don't signal multiple times */
if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT)
size = offsetof( select_op_t, signal_and_wait.signal );
}
if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC;
/* A test on Windows 2000 shows that Windows always yields during /* A test on Windows 2000 shows that Windows always yields during
a wait, but a wait that is hit by an event gets a priority a wait, but a wait that is hit by an event gets a priority
boost as well. This seems to model that behavior the closest. */ boost as well. This seems to model that behavior the closest. */
if (ret == STATUS_TIMEOUT) NtYieldExecution(); if (ret == STATUS_TIMEOUT) NtYieldExecution();
return ret; return ret;
} }
/***********************************************************************
* NtContinue (NTDLL.@)
*/
NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable )
{
user_apc_t apc;
NTSTATUS status;
status = server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, 0, NULL, NULL, &apc );
if (status == STATUS_USER_APC) invoke_apc( context, &apc );
return NtSetContextThread( GetCurrentThread(), context );
}
/*********************************************************************** /***********************************************************************
* server_queue_process_apc * server_queue_process_apc
*/ */

View File

@ -575,6 +575,29 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
REGn_sig(2, sigcontext) = (DWORD)pKiUserExceptionDispatcher; REGn_sig(2, sigcontext) = (DWORD)pKiUserExceptionDispatcher;
} }
/***********************************************************************
* call_user_apc
*/
void WINAPI call_user_apc( CONTEXT *context_ptr, ULONG_PTR ctx, ULONG_PTR arg1,
ULONG_PTR arg2, PNTAPCFUNC func )
{
CONTEXT context;
if (!context_ptr)
{
context.ContextFlags = CONTEXT_FULL;
NtGetContextThread( GetCurrentThread(), &context );
context.R0 = STATUS_USER_APC;
context_ptr = &context;
}
pKiUserApcDispatcher( context_ptr, ctx, arg1, arg2, func );
}
/***********************************************************************
* call_user_exception_dispatcher
*/
void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context, void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) )
{ {

View File

@ -579,6 +579,29 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb(); REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb();
} }
/***********************************************************************
* call_user_apc
*/
void WINAPI call_user_apc( CONTEXT *context_ptr, ULONG_PTR ctx, ULONG_PTR arg1,
ULONG_PTR arg2, PNTAPCFUNC func )
{
CONTEXT context;
if (!context_ptr)
{
context.ContextFlags = CONTEXT_FULL;
NtGetContextThread( GetCurrentThread(), &context );
context.u.s.X0 = STATUS_USER_APC;
context_ptr = &context;
}
pKiUserApcDispatcher( context_ptr, ctx, arg1, arg2, func );
}
/***********************************************************************
* call_user_exception_dispatcher
*/
void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context, void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) )
{ {

View File

@ -1181,7 +1181,7 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
} }
if (needed_flags & CONTEXT_CONTROL) if (needed_flags & CONTEXT_CONTROL)
{ {
context->Esp = (DWORD)&frame->thunk_addr; context->Esp = (DWORD)&frame->ret_addr;
context->Ebp = frame->ebp; context->Ebp = frame->ebp;
context->Eip = frame->thunk_addr; context->Eip = frame->thunk_addr;
context->EFlags = 0x202; context->EFlags = 0x202;
@ -1535,6 +1535,29 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
setup_raise_exception( sigcontext, stack, rec, &context ); setup_raise_exception( sigcontext, stack, rec, &context );
} }
/***********************************************************************
* call_user_apc
*/
void WINAPI call_user_apc( CONTEXT *context_ptr, ULONG_PTR ctx, ULONG_PTR arg1,
ULONG_PTR arg2, PNTAPCFUNC func )
{
CONTEXT context;
if (!context_ptr)
{
context.ContextFlags = CONTEXT_FULL;
NtGetContextThread( GetCurrentThread(), &context );
context.Eax = STATUS_USER_APC;
context_ptr = &context;
}
pKiUserApcDispatcher( context_ptr, ctx, arg1, arg2, func );
}
/***********************************************************************
* call_user_exception_dispatcher
*/
__ASM_GLOBAL_FUNC( call_user_exception_dispatcher, __ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
"add $4,%esp\n\t" "add $4,%esp\n\t"
"movl (%esp),%eax\n\t" /* rec */ "movl (%esp),%eax\n\t" /* rec */

View File

@ -1887,6 +1887,30 @@ static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
setup_raise_exception( sigcontext, rec, &context ); setup_raise_exception( sigcontext, rec, &context );
} }
/***********************************************************************
* call_user_apc
*/
void WINAPI call_user_apc( CONTEXT *context_ptr, ULONG_PTR ctx, ULONG_PTR arg1,
ULONG_PTR arg2, PNTAPCFUNC func )
{
CONTEXT context;
if (!context_ptr)
{
context.ContextFlags = CONTEXT_FULL;
NtGetContextThread( GetCurrentThread(), &context );
context.Rax = STATUS_USER_APC;
context_ptr = &context;
}
pKiUserApcDispatcher( context_ptr, ctx, arg1, arg2, func );
}
/***********************************************************************
* call_user_exception_dispatcher
*/
extern void WINAPI user_exception_dispatcher_trampoline( struct stack_layout *stack, extern void WINAPI user_exception_dispatcher_trampoline( struct stack_layout *stack,
void *pKiUserExceptionDispatcher ); void *pKiUserExceptionDispatcher );

View File

@ -519,18 +519,6 @@ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
} }
/***********************************************************************
* NtContinue (NTDLL.@)
*/
NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable )
{
static const LARGE_INTEGER zero_timeout;
if (alertable) server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero_timeout );
return NtSetContextThread( GetCurrentThread(), context );
}
/****************************************************************************** /******************************************************************************
* NtQueueApcThread (NTDLL.@) * NtQueueApcThread (NTDLL.@)
*/ */

View File

@ -85,6 +85,7 @@ static const SIZE_T signal_stack_size = 0x10000 - 0x3000;
/* callbacks to PE ntdll from the Unix side */ /* callbacks to PE ntdll from the Unix side */
extern void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) DECLSPEC_HIDDEN; extern void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) DECLSPEC_HIDDEN;
extern void (WINAPI *pKiRaiseUserExceptionDispatcher)(void) DECLSPEC_HIDDEN; extern void (WINAPI *pKiRaiseUserExceptionDispatcher)(void) DECLSPEC_HIDDEN;
extern void (WINAPI *pKiUserApcDispatcher)(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR,PNTAPCFUNC) DECLSPEC_HIDDEN;
extern NTSTATUS (WINAPI *pKiUserExceptionDispatcher)(EXCEPTION_RECORD*,CONTEXT*) DECLSPEC_HIDDEN; extern NTSTATUS (WINAPI *pKiUserExceptionDispatcher)(EXCEPTION_RECORD*,CONTEXT*) DECLSPEC_HIDDEN;
extern void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PTR) DECLSPEC_HIDDEN; extern void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PTR) DECLSPEC_HIDDEN;
extern void (WINAPI *pRtlUserThreadStart)( PRTL_THREAD_START_ROUTINE entry, void *arg ) DECLSPEC_HIDDEN; extern void (WINAPI *pRtlUserThreadStart)( PRTL_THREAD_START_ROUTINE entry, void *arg ) DECLSPEC_HIDDEN;
@ -257,6 +258,8 @@ extern void init_cpu_info(void) DECLSPEC_HIDDEN;
extern void dbg_init(void) DECLSPEC_HIDDEN; extern void dbg_init(void) DECLSPEC_HIDDEN;
extern void WINAPI call_user_apc( CONTEXT *context_ptr, ULONG_PTR ctx, ULONG_PTR arg1,
ULONG_PTR arg2, PNTAPCFUNC func ) DECLSPEC_HIDDEN;
extern void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context, extern void WINAPI call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context,
NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) DECLSPEC_HIDDEN; NTSTATUS (WINAPI *dispatcher)(EXCEPTION_RECORD*,CONTEXT*) ) DECLSPEC_HIDDEN;