ntdll: Move server wait functions to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
b925dd78b8
commit
c0319e0eab
|
@ -232,7 +232,7 @@ static inline NTSTATUS wait_semaphore( RTL_CRITICAL_SECTION *crit, int timeout )
|
|||
time.QuadPart = timeout * (LONGLONG)-10000000;
|
||||
select_op.wait.op = SELECT_WAIT;
|
||||
select_op.wait.handles[0] = wine_server_obj_handle( sem );
|
||||
ret = server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time );
|
||||
ret = unix_funcs->server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &time );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ void wait_suspend( CONTEXT *context )
|
|||
int saved_errno = errno;
|
||||
|
||||
/* wait with 0 timeout, will only return once the thread is no longer suspended */
|
||||
server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, context, NULL, NULL );
|
||||
unix_funcs->server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, context, NULL, NULL );
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *con
|
|||
{
|
||||
select_op.wait.op = SELECT_WAIT;
|
||||
select_op.wait.handles[0] = handle;
|
||||
server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, TIMEOUT_INFINITE, &exception_context, NULL, NULL );
|
||||
unix_funcs->server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, TIMEOUT_INFINITE, &exception_context, NULL, NULL );
|
||||
|
||||
SERVER_START_REQ( get_exception_status )
|
||||
{
|
||||
|
|
|
@ -1797,7 +1797,7 @@ NTSTATUS WINAPI DbgUiIssueRemoteBreakin( HANDLE process )
|
|||
memset( &call, 0, sizeof(call) );
|
||||
|
||||
call.type = APC_BREAK_PROCESS;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status) return status;
|
||||
return result.break_process.status;
|
||||
}
|
||||
|
|
|
@ -116,32 +116,6 @@ timeout_t server_start_time = 0; /* time of server startup */
|
|||
|
||||
sigset_t server_block_set; /* signals to block during server calls */
|
||||
|
||||
/***********************************************************************
|
||||
* server_protocol_error
|
||||
*/
|
||||
static DECLSPEC_NORETURN void server_protocol_error( const char *err, ... )
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start( args, err );
|
||||
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
|
||||
vfprintf( stderr, err, args );
|
||||
va_end( args );
|
||||
for (;;) unix_funcs->abort_thread(1);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_protocol_perror
|
||||
*/
|
||||
static DECLSPEC_NORETURN void server_protocol_perror( const char *err )
|
||||
{
|
||||
fprintf( stderr, "wine client error:%x: ", GetCurrentThreadId() );
|
||||
perror( err );
|
||||
for (;;) unix_funcs->abort_thread(1);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_server_call (NTDLL.@)
|
||||
*
|
||||
|
@ -190,429 +164,6 @@ void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sig
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wait_select_reply
|
||||
*
|
||||
* Wait for a reply on the waiting pipe of the current thread.
|
||||
*/
|
||||
static int wait_select_reply( void *cookie )
|
||||
{
|
||||
int signaled;
|
||||
struct wake_up_reply reply;
|
||||
for (;;)
|
||||
{
|
||||
int ret;
|
||||
ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) );
|
||||
if (ret == sizeof(reply))
|
||||
{
|
||||
if (!reply.cookie) unix_funcs->abort_thread( reply.signaled ); /* thread got killed */
|
||||
if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled;
|
||||
/* we stole another reply, wait for the real one */
|
||||
signaled = wait_select_reply( cookie );
|
||||
/* and now put the wrong one back in the pipe */
|
||||
for (;;)
|
||||
{
|
||||
ret = write( ntdll_get_thread_data()->wait_fd[1], &reply, sizeof(reply) );
|
||||
if (ret == sizeof(reply)) break;
|
||||
if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
|
||||
if (errno == EINTR) continue;
|
||||
server_protocol_perror("wakeup write");
|
||||
}
|
||||
return signaled;
|
||||
}
|
||||
if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
|
||||
if (errno == EINTR) continue;
|
||||
server_protocol_perror("wakeup read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void invoke_apc( const user_apc_t *apc )
|
||||
{
|
||||
switch( apc->type )
|
||||
{
|
||||
case APC_USER:
|
||||
{
|
||||
void (WINAPI *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR) = wine_server_get_ptr( apc->user.func );
|
||||
func( apc->user.args[0], apc->user.args[1], apc->user.args[2] );
|
||||
break;
|
||||
}
|
||||
case APC_TIMER:
|
||||
{
|
||||
void (WINAPI *func)(void*, unsigned int, unsigned int) = wine_server_get_ptr( apc->user.func );
|
||||
func( wine_server_get_ptr( apc->user.args[1] ),
|
||||
(DWORD)apc->timer.time, (DWORD)(apc->timer.time >> 32) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", apc->type );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* invoke_apc
|
||||
*
|
||||
* Invoke a single APC.
|
||||
*
|
||||
*/
|
||||
static void invoke_system_apc( const apc_call_t *call, apc_result_t *result )
|
||||
{
|
||||
SIZE_T size, bits;
|
||||
void *addr;
|
||||
|
||||
memset( result, 0, sizeof(*result) );
|
||||
|
||||
switch (call->type)
|
||||
{
|
||||
case APC_NONE:
|
||||
break;
|
||||
case APC_ASYNC_IO:
|
||||
{
|
||||
IO_STATUS_BLOCK *iosb = wine_server_get_ptr( call->async_io.sb );
|
||||
NTSTATUS (**user)(void *, IO_STATUS_BLOCK *, NTSTATUS) = wine_server_get_ptr( call->async_io.user );
|
||||
result->type = call->type;
|
||||
result->async_io.status = (*user)( user, iosb, call->async_io.status );
|
||||
if (result->async_io.status != STATUS_PENDING)
|
||||
result->async_io.total = iosb->Information;
|
||||
break;
|
||||
}
|
||||
case APC_VIRTUAL_ALLOC:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_alloc.addr );
|
||||
size = call->virtual_alloc.size;
|
||||
bits = call->virtual_alloc.zero_bits;
|
||||
if ((ULONG_PTR)addr == call->virtual_alloc.addr && size == call->virtual_alloc.size &&
|
||||
bits == call->virtual_alloc.zero_bits)
|
||||
{
|
||||
result->virtual_alloc.status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, bits, &size,
|
||||
call->virtual_alloc.op_type,
|
||||
call->virtual_alloc.prot );
|
||||
result->virtual_alloc.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_alloc.size = size;
|
||||
}
|
||||
else result->virtual_alloc.status = STATUS_WORKING_SET_LIMIT_RANGE;
|
||||
break;
|
||||
case APC_VIRTUAL_FREE:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_free.addr );
|
||||
size = call->virtual_free.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_free.addr && size == call->virtual_free.size)
|
||||
{
|
||||
result->virtual_free.status = NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size,
|
||||
call->virtual_free.op_type );
|
||||
result->virtual_free.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_free.size = size;
|
||||
}
|
||||
else result->virtual_free.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_QUERY:
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_query.addr );
|
||||
if ((ULONG_PTR)addr == call->virtual_query.addr)
|
||||
result->virtual_query.status = NtQueryVirtualMemory( NtCurrentProcess(),
|
||||
addr, MemoryBasicInformation, &info,
|
||||
sizeof(info), NULL );
|
||||
else
|
||||
result->virtual_query.status = STATUS_WORKING_SET_LIMIT_RANGE;
|
||||
|
||||
if (result->virtual_query.status == STATUS_SUCCESS)
|
||||
{
|
||||
result->virtual_query.base = wine_server_client_ptr( info.BaseAddress );
|
||||
result->virtual_query.alloc_base = wine_server_client_ptr( info.AllocationBase );
|
||||
result->virtual_query.size = info.RegionSize;
|
||||
result->virtual_query.prot = info.Protect;
|
||||
result->virtual_query.alloc_prot = info.AllocationProtect;
|
||||
result->virtual_query.state = info.State >> 12;
|
||||
result->virtual_query.alloc_type = info.Type >> 16;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APC_VIRTUAL_PROTECT:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_protect.addr );
|
||||
size = call->virtual_protect.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_protect.addr && size == call->virtual_protect.size)
|
||||
{
|
||||
result->virtual_protect.status = NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size,
|
||||
call->virtual_protect.prot,
|
||||
&result->virtual_protect.prot );
|
||||
result->virtual_protect.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_protect.size = size;
|
||||
}
|
||||
else result->virtual_protect.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_FLUSH:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_flush.addr );
|
||||
size = call->virtual_flush.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_flush.addr && size == call->virtual_flush.size)
|
||||
{
|
||||
result->virtual_flush.status = NtFlushVirtualMemory( NtCurrentProcess(),
|
||||
(const void **)&addr, &size, 0 );
|
||||
result->virtual_flush.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_flush.size = size;
|
||||
}
|
||||
else result->virtual_flush.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_LOCK:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_lock.addr );
|
||||
size = call->virtual_lock.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_lock.addr && size == call->virtual_lock.size)
|
||||
{
|
||||
result->virtual_lock.status = NtLockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 );
|
||||
result->virtual_lock.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_lock.size = size;
|
||||
}
|
||||
else result->virtual_lock.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_UNLOCK:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_unlock.addr );
|
||||
size = call->virtual_unlock.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_unlock.addr && size == call->virtual_unlock.size)
|
||||
{
|
||||
result->virtual_unlock.status = NtUnlockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 );
|
||||
result->virtual_unlock.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_unlock.size = size;
|
||||
}
|
||||
else result->virtual_unlock.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_MAP_VIEW:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->map_view.addr );
|
||||
size = call->map_view.size;
|
||||
bits = call->map_view.zero_bits;
|
||||
if ((ULONG_PTR)addr == call->map_view.addr && size == call->map_view.size &&
|
||||
bits == call->map_view.zero_bits)
|
||||
{
|
||||
LARGE_INTEGER offset;
|
||||
offset.QuadPart = call->map_view.offset;
|
||||
result->map_view.status = NtMapViewOfSection( wine_server_ptr_handle(call->map_view.handle),
|
||||
NtCurrentProcess(),
|
||||
&addr, bits, 0, &offset, &size, 0,
|
||||
call->map_view.alloc_type, call->map_view.prot );
|
||||
result->map_view.addr = wine_server_client_ptr( addr );
|
||||
result->map_view.size = size;
|
||||
}
|
||||
else result->map_view.status = STATUS_INVALID_PARAMETER;
|
||||
NtClose( wine_server_ptr_handle(call->map_view.handle) );
|
||||
break;
|
||||
case APC_UNMAP_VIEW:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->unmap_view.addr );
|
||||
if ((ULONG_PTR)addr == call->unmap_view.addr)
|
||||
result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr );
|
||||
else
|
||||
result->unmap_view.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_CREATE_THREAD:
|
||||
{
|
||||
CLIENT_ID id;
|
||||
HANDLE handle;
|
||||
SIZE_T reserve = call->create_thread.reserve;
|
||||
SIZE_T commit = call->create_thread.commit;
|
||||
void *func = wine_server_get_ptr( call->create_thread.func );
|
||||
void *arg = wine_server_get_ptr( call->create_thread.arg );
|
||||
|
||||
result->type = call->type;
|
||||
if (reserve == call->create_thread.reserve && commit == call->create_thread.commit &&
|
||||
(ULONG_PTR)func == call->create_thread.func && (ULONG_PTR)arg == call->create_thread.arg)
|
||||
{
|
||||
result->create_thread.status = RtlCreateUserThread( NtCurrentProcess(), NULL,
|
||||
call->create_thread.suspend, NULL,
|
||||
reserve, commit, func, arg, &handle, &id );
|
||||
result->create_thread.handle = wine_server_obj_handle( handle );
|
||||
result->create_thread.tid = HandleToULong(id.UniqueThread);
|
||||
}
|
||||
else result->create_thread.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
case APC_BREAK_PROCESS:
|
||||
result->type = APC_BREAK_PROCESS;
|
||||
result->break_process.status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0,
|
||||
DbgUiRemoteBreakin, NULL, NULL, NULL );
|
||||
break;
|
||||
default:
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", call->type );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_select
|
||||
*/
|
||||
unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, user_apc_t *user_apc )
|
||||
{
|
||||
unsigned int ret;
|
||||
int cookie;
|
||||
obj_handle_t apc_handle = 0;
|
||||
context_t server_context;
|
||||
BOOL suspend_context = FALSE;
|
||||
apc_call_t call;
|
||||
apc_result_t result;
|
||||
sigset_t old_set;
|
||||
|
||||
memset( &result, 0, sizeof(result) );
|
||||
if (context)
|
||||
{
|
||||
suspend_context = TRUE;
|
||||
context_to_server( &server_context, context );
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
|
||||
for (;;)
|
||||
{
|
||||
SERVER_START_REQ( select )
|
||||
{
|
||||
req->flags = flags;
|
||||
req->cookie = wine_server_client_ptr( &cookie );
|
||||
req->prev_apc = apc_handle;
|
||||
req->timeout = abs_timeout;
|
||||
req->size = size;
|
||||
wine_server_add_data( req, &result, sizeof(result) );
|
||||
wine_server_add_data( req, select_op, size );
|
||||
if (suspend_context)
|
||||
{
|
||||
wine_server_add_data( req, &server_context, sizeof(server_context) );
|
||||
suspend_context = FALSE; /* server owns the context now */
|
||||
}
|
||||
if (context) wine_server_set_reply( req, &server_context, sizeof(server_context) );
|
||||
ret = unix_funcs->server_call_unlocked( req );
|
||||
apc_handle = reply->apc_handle;
|
||||
call = reply->call;
|
||||
if (wine_server_reply_size( reply ))
|
||||
{
|
||||
DWORD context_flags = context->ContextFlags; /* unchanged registers are still available */
|
||||
context_from_server( context, &server_context );
|
||||
context->ContextFlags |= context_flags;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret != STATUS_KERNEL_APC) break;
|
||||
invoke_system_apc( &call, &result );
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
pthread_sigmask( SIG_SETMASK, &old_set, NULL );
|
||||
if (cs)
|
||||
{
|
||||
RtlLeaveCriticalSection( cs );
|
||||
cs = NULL;
|
||||
}
|
||||
if (ret != STATUS_PENDING) break;
|
||||
|
||||
ret = wait_select_reply( &cookie );
|
||||
}
|
||||
while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC);
|
||||
|
||||
if (ret == STATUS_USER_APC) *user_apc = call.user;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_wait
|
||||
*/
|
||||
unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
const LARGE_INTEGER *timeout )
|
||||
{
|
||||
timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
|
||||
BOOL user_apc = FALSE;
|
||||
unsigned int ret;
|
||||
user_apc_t apc;
|
||||
|
||||
if (abs_timeout < 0)
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
|
||||
RtlQueryPerformanceCounter(&now);
|
||||
abs_timeout -= now.QuadPart;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
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 wait, but a wait that is hit by an event gets a priority
|
||||
boost as well. This seems to model that behavior the closest. */
|
||||
if (ret == STATUS_TIMEOUT) NtYieldExecution();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_queue_process_apc
|
||||
*/
|
||||
unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result )
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
unsigned int ret;
|
||||
HANDLE handle = 0;
|
||||
BOOL self = FALSE;
|
||||
|
||||
SERVER_START_REQ( queue_apc )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( process );
|
||||
req->call = *call;
|
||||
if (!(ret = wine_server_call( req )))
|
||||
{
|
||||
handle = wine_server_ptr_handle( reply->handle );
|
||||
self = reply->self;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (ret != STATUS_SUCCESS) return ret;
|
||||
|
||||
if (self)
|
||||
{
|
||||
invoke_system_apc( call, result );
|
||||
}
|
||||
else
|
||||
{
|
||||
NtWaitForSingleObject( handle, FALSE, NULL );
|
||||
|
||||
SERVER_START_REQ( get_apc_result )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
if (!(ret = wine_server_call( req ))) *result = reply->result;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!ret && result->type == APC_NONE) continue; /* APC didn't run, try again */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wine_server_send_fd (NTDLL.@)
|
||||
*
|
||||
|
|
|
@ -1101,7 +1101,7 @@ static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
|
|||
if (alertable) flags |= SELECT_ALERTABLE;
|
||||
select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
|
||||
for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
|
||||
return server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
|
||||
return unix_funcs->server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1140,7 +1140,7 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWa
|
|||
select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
|
||||
select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
|
||||
select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
|
||||
return server_wait( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
|
||||
return unix_funcs->server_wait( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1165,7 +1165,7 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou
|
|||
{
|
||||
/* if alertable, we need to query the server */
|
||||
if (alertable)
|
||||
return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
|
||||
return unix_funcs->server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
|
||||
|
||||
if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
|
||||
{
|
||||
|
@ -1264,7 +1264,7 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
|
|||
select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
|
||||
select_op.keyed_event.handle = wine_server_obj_handle( handle );
|
||||
select_op.keyed_event.key = wine_server_client_ptr( key );
|
||||
return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
|
||||
return unix_funcs->server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -1282,7 +1282,7 @@ NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
|
|||
select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
|
||||
select_op.keyed_event.handle = wine_server_obj_handle( handle );
|
||||
select_op.keyed_event.key = wine_server_client_ptr( key );
|
||||
return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
|
||||
return unix_funcs->server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
@ -2579,7 +2579,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
|
|||
select_op.keyed_event.handle = wine_server_obj_handle( keyed_event );
|
||||
select_op.keyed_event.key = wine_server_client_ptr( addr );
|
||||
|
||||
return server_select( &select_op, sizeof(select_op.keyed_event), SELECT_INTERRUPTIBLE, abs_timeout, NULL, &addr_section, NULL );
|
||||
return unix_funcs->server_select( &select_op, sizeof(select_op.keyed_event), SELECT_INTERRUPTIBLE, abs_timeout, NULL, &addr_section, NULL );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -413,7 +413,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
|
|||
call.create_thread.reserve = stack_reserve;
|
||||
call.create_thread.commit = stack_commit;
|
||||
call.create_thread.suspend = suspended;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.create_thread.status == STATUS_SUCCESS)
|
||||
|
|
|
@ -1010,6 +1010,9 @@ static struct unix_funcs unix_funcs =
|
|||
get_thread_ldt_entry,
|
||||
server_call_unlocked,
|
||||
wine_server_call,
|
||||
server_select,
|
||||
server_wait,
|
||||
server_queue_process_apc,
|
||||
server_send_fd,
|
||||
server_get_unix_fd,
|
||||
server_fd_to_handle,
|
||||
|
|
|
@ -334,6 +334,430 @@ void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sig
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wait_select_reply
|
||||
*
|
||||
* Wait for a reply on the waiting pipe of the current thread.
|
||||
*/
|
||||
static int wait_select_reply( void *cookie )
|
||||
{
|
||||
int signaled;
|
||||
struct wake_up_reply reply;
|
||||
for (;;)
|
||||
{
|
||||
int ret;
|
||||
ret = read( ntdll_get_thread_data()->wait_fd[0], &reply, sizeof(reply) );
|
||||
if (ret == sizeof(reply))
|
||||
{
|
||||
if (!reply.cookie) abort_thread( reply.signaled ); /* thread got killed */
|
||||
if (wine_server_get_ptr(reply.cookie) == cookie) return reply.signaled;
|
||||
/* we stole another reply, wait for the real one */
|
||||
signaled = wait_select_reply( cookie );
|
||||
/* and now put the wrong one back in the pipe */
|
||||
for (;;)
|
||||
{
|
||||
ret = write( ntdll_get_thread_data()->wait_fd[1], &reply, sizeof(reply) );
|
||||
if (ret == sizeof(reply)) break;
|
||||
if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
|
||||
if (errno == EINTR) continue;
|
||||
server_protocol_perror("wakeup write");
|
||||
}
|
||||
return signaled;
|
||||
}
|
||||
if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
|
||||
if (errno == EINTR) continue;
|
||||
server_protocol_perror("wakeup read");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void invoke_apc( const user_apc_t *apc )
|
||||
{
|
||||
switch( apc->type )
|
||||
{
|
||||
case APC_USER:
|
||||
{
|
||||
void (WINAPI *func)(ULONG_PTR,ULONG_PTR,ULONG_PTR) = wine_server_get_ptr( apc->user.func );
|
||||
func( apc->user.args[0], apc->user.args[1], apc->user.args[2] );
|
||||
break;
|
||||
}
|
||||
case APC_TIMER:
|
||||
{
|
||||
void (WINAPI *func)(void*, unsigned int, unsigned int) = wine_server_get_ptr( apc->user.func );
|
||||
func( wine_server_get_ptr( apc->user.args[1] ),
|
||||
(DWORD)apc->timer.time, (DWORD)(apc->timer.time >> 32) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", apc->type );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* invoke_apc
|
||||
*
|
||||
* Invoke a single APC.
|
||||
*
|
||||
*/
|
||||
static void invoke_system_apc( const apc_call_t *call, apc_result_t *result )
|
||||
{
|
||||
SIZE_T size, bits;
|
||||
void *addr;
|
||||
|
||||
memset( result, 0, sizeof(*result) );
|
||||
|
||||
switch (call->type)
|
||||
{
|
||||
case APC_NONE:
|
||||
break;
|
||||
case APC_ASYNC_IO:
|
||||
{
|
||||
IO_STATUS_BLOCK *iosb = wine_server_get_ptr( call->async_io.sb );
|
||||
NTSTATUS (**user)(void *, IO_STATUS_BLOCK *, NTSTATUS) = wine_server_get_ptr( call->async_io.user );
|
||||
result->type = call->type;
|
||||
result->async_io.status = (*user)( user, iosb, call->async_io.status );
|
||||
if (result->async_io.status != STATUS_PENDING)
|
||||
result->async_io.total = iosb->Information;
|
||||
break;
|
||||
}
|
||||
case APC_VIRTUAL_ALLOC:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_alloc.addr );
|
||||
size = call->virtual_alloc.size;
|
||||
bits = call->virtual_alloc.zero_bits;
|
||||
if ((ULONG_PTR)addr == call->virtual_alloc.addr && size == call->virtual_alloc.size &&
|
||||
bits == call->virtual_alloc.zero_bits)
|
||||
{
|
||||
result->virtual_alloc.status = NtAllocateVirtualMemory( NtCurrentProcess(), &addr, bits, &size,
|
||||
call->virtual_alloc.op_type,
|
||||
call->virtual_alloc.prot );
|
||||
result->virtual_alloc.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_alloc.size = size;
|
||||
}
|
||||
else result->virtual_alloc.status = STATUS_WORKING_SET_LIMIT_RANGE;
|
||||
break;
|
||||
case APC_VIRTUAL_FREE:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_free.addr );
|
||||
size = call->virtual_free.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_free.addr && size == call->virtual_free.size)
|
||||
{
|
||||
result->virtual_free.status = NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size,
|
||||
call->virtual_free.op_type );
|
||||
result->virtual_free.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_free.size = size;
|
||||
}
|
||||
else result->virtual_free.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_QUERY:
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_query.addr );
|
||||
if ((ULONG_PTR)addr == call->virtual_query.addr)
|
||||
result->virtual_query.status = NtQueryVirtualMemory( NtCurrentProcess(),
|
||||
addr, MemoryBasicInformation, &info,
|
||||
sizeof(info), NULL );
|
||||
else
|
||||
result->virtual_query.status = STATUS_WORKING_SET_LIMIT_RANGE;
|
||||
|
||||
if (result->virtual_query.status == STATUS_SUCCESS)
|
||||
{
|
||||
result->virtual_query.base = wine_server_client_ptr( info.BaseAddress );
|
||||
result->virtual_query.alloc_base = wine_server_client_ptr( info.AllocationBase );
|
||||
result->virtual_query.size = info.RegionSize;
|
||||
result->virtual_query.prot = info.Protect;
|
||||
result->virtual_query.alloc_prot = info.AllocationProtect;
|
||||
result->virtual_query.state = info.State >> 12;
|
||||
result->virtual_query.alloc_type = info.Type >> 16;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APC_VIRTUAL_PROTECT:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_protect.addr );
|
||||
size = call->virtual_protect.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_protect.addr && size == call->virtual_protect.size)
|
||||
{
|
||||
result->virtual_protect.status = NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size,
|
||||
call->virtual_protect.prot,
|
||||
&result->virtual_protect.prot );
|
||||
result->virtual_protect.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_protect.size = size;
|
||||
}
|
||||
else result->virtual_protect.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_FLUSH:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_flush.addr );
|
||||
size = call->virtual_flush.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_flush.addr && size == call->virtual_flush.size)
|
||||
{
|
||||
result->virtual_flush.status = NtFlushVirtualMemory( NtCurrentProcess(),
|
||||
(const void **)&addr, &size, 0 );
|
||||
result->virtual_flush.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_flush.size = size;
|
||||
}
|
||||
else result->virtual_flush.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_LOCK:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_lock.addr );
|
||||
size = call->virtual_lock.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_lock.addr && size == call->virtual_lock.size)
|
||||
{
|
||||
result->virtual_lock.status = NtLockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 );
|
||||
result->virtual_lock.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_lock.size = size;
|
||||
}
|
||||
else result->virtual_lock.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_VIRTUAL_UNLOCK:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->virtual_unlock.addr );
|
||||
size = call->virtual_unlock.size;
|
||||
if ((ULONG_PTR)addr == call->virtual_unlock.addr && size == call->virtual_unlock.size)
|
||||
{
|
||||
result->virtual_unlock.status = NtUnlockVirtualMemory( NtCurrentProcess(), &addr, &size, 0 );
|
||||
result->virtual_unlock.addr = wine_server_client_ptr( addr );
|
||||
result->virtual_unlock.size = size;
|
||||
}
|
||||
else result->virtual_unlock.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_MAP_VIEW:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->map_view.addr );
|
||||
size = call->map_view.size;
|
||||
bits = call->map_view.zero_bits;
|
||||
if ((ULONG_PTR)addr == call->map_view.addr && size == call->map_view.size &&
|
||||
bits == call->map_view.zero_bits)
|
||||
{
|
||||
LARGE_INTEGER offset;
|
||||
offset.QuadPart = call->map_view.offset;
|
||||
result->map_view.status = NtMapViewOfSection( wine_server_ptr_handle(call->map_view.handle),
|
||||
NtCurrentProcess(),
|
||||
&addr, bits, 0, &offset, &size, 0,
|
||||
call->map_view.alloc_type, call->map_view.prot );
|
||||
result->map_view.addr = wine_server_client_ptr( addr );
|
||||
result->map_view.size = size;
|
||||
}
|
||||
else result->map_view.status = STATUS_INVALID_PARAMETER;
|
||||
NtClose( wine_server_ptr_handle(call->map_view.handle) );
|
||||
break;
|
||||
case APC_UNMAP_VIEW:
|
||||
result->type = call->type;
|
||||
addr = wine_server_get_ptr( call->unmap_view.addr );
|
||||
if ((ULONG_PTR)addr == call->unmap_view.addr)
|
||||
result->unmap_view.status = NtUnmapViewOfSection( NtCurrentProcess(), addr );
|
||||
else
|
||||
result->unmap_view.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
case APC_CREATE_THREAD:
|
||||
{
|
||||
CLIENT_ID id;
|
||||
HANDLE handle;
|
||||
SIZE_T reserve = call->create_thread.reserve;
|
||||
SIZE_T commit = call->create_thread.commit;
|
||||
void *func = wine_server_get_ptr( call->create_thread.func );
|
||||
void *arg = wine_server_get_ptr( call->create_thread.arg );
|
||||
|
||||
result->type = call->type;
|
||||
if (reserve == call->create_thread.reserve && commit == call->create_thread.commit &&
|
||||
(ULONG_PTR)func == call->create_thread.func && (ULONG_PTR)arg == call->create_thread.arg)
|
||||
{
|
||||
result->create_thread.status = RtlCreateUserThread( NtCurrentProcess(), NULL,
|
||||
call->create_thread.suspend, NULL,
|
||||
reserve, commit, func, arg, &handle, &id );
|
||||
result->create_thread.handle = wine_server_obj_handle( handle );
|
||||
result->create_thread.tid = HandleToULong(id.UniqueThread);
|
||||
}
|
||||
else result->create_thread.status = STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
case APC_BREAK_PROCESS:
|
||||
result->type = APC_BREAK_PROCESS;
|
||||
result->break_process.status = RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0,
|
||||
DbgUiRemoteBreakin, NULL, NULL, NULL );
|
||||
break;
|
||||
default:
|
||||
server_protocol_error( "get_apc_request: bad type %d\n", call->type );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_select
|
||||
*/
|
||||
unsigned int CDECL server_select( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs,
|
||||
user_apc_t *user_apc )
|
||||
{
|
||||
unsigned int ret;
|
||||
int cookie;
|
||||
obj_handle_t apc_handle = 0;
|
||||
context_t server_context;
|
||||
BOOL suspend_context = FALSE;
|
||||
apc_call_t call;
|
||||
apc_result_t result;
|
||||
sigset_t old_set;
|
||||
|
||||
memset( &result, 0, sizeof(result) );
|
||||
if (context)
|
||||
{
|
||||
suspend_context = TRUE;
|
||||
context_to_server( &server_context, context );
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
|
||||
for (;;)
|
||||
{
|
||||
SERVER_START_REQ( select )
|
||||
{
|
||||
req->flags = flags;
|
||||
req->cookie = wine_server_client_ptr( &cookie );
|
||||
req->prev_apc = apc_handle;
|
||||
req->timeout = abs_timeout;
|
||||
req->size = size;
|
||||
wine_server_add_data( req, &result, sizeof(result) );
|
||||
wine_server_add_data( req, select_op, size );
|
||||
if (suspend_context)
|
||||
{
|
||||
wine_server_add_data( req, &server_context, sizeof(server_context) );
|
||||
suspend_context = FALSE; /* server owns the context now */
|
||||
}
|
||||
if (context) wine_server_set_reply( req, &server_context, sizeof(server_context) );
|
||||
ret = server_call_unlocked( req );
|
||||
apc_handle = reply->apc_handle;
|
||||
call = reply->call;
|
||||
if (wine_server_reply_size( reply ))
|
||||
{
|
||||
DWORD context_flags = context->ContextFlags; /* unchanged registers are still available */
|
||||
context_from_server( context, &server_context );
|
||||
context->ContextFlags |= context_flags;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (ret != STATUS_KERNEL_APC) break;
|
||||
invoke_system_apc( &call, &result );
|
||||
|
||||
/* 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 );
|
||||
}
|
||||
pthread_sigmask( SIG_SETMASK, &old_set, NULL );
|
||||
if (cs)
|
||||
{
|
||||
RtlLeaveCriticalSection( cs );
|
||||
cs = NULL;
|
||||
}
|
||||
if (ret != STATUS_PENDING) break;
|
||||
|
||||
ret = wait_select_reply( &cookie );
|
||||
}
|
||||
while (ret == STATUS_USER_APC || ret == STATUS_KERNEL_APC);
|
||||
|
||||
if (ret == STATUS_USER_APC) *user_apc = call.user;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_wait
|
||||
*/
|
||||
unsigned int CDECL server_wait( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
const LARGE_INTEGER *timeout )
|
||||
{
|
||||
timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
|
||||
BOOL user_apc = FALSE;
|
||||
unsigned int ret;
|
||||
user_apc_t apc;
|
||||
|
||||
if (abs_timeout < 0)
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
|
||||
RtlQueryPerformanceCounter(&now);
|
||||
abs_timeout -= now.QuadPart;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
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 wait, but a wait that is hit by an event gets a priority
|
||||
boost as well. This seems to model that behavior the closest. */
|
||||
if (ret == STATUS_TIMEOUT) NtYieldExecution();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_queue_process_apc
|
||||
*/
|
||||
unsigned int CDECL server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result )
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
unsigned int ret;
|
||||
HANDLE handle = 0;
|
||||
BOOL self = FALSE;
|
||||
|
||||
SERVER_START_REQ( queue_apc )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( process );
|
||||
req->call = *call;
|
||||
if (!(ret = wine_server_call( req )))
|
||||
{
|
||||
handle = wine_server_ptr_handle( reply->handle );
|
||||
self = reply->self;
|
||||
}
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
if (ret != STATUS_SUCCESS) return ret;
|
||||
|
||||
if (self)
|
||||
{
|
||||
invoke_system_apc( call, result );
|
||||
}
|
||||
else
|
||||
{
|
||||
NtWaitForSingleObject( handle, FALSE, NULL );
|
||||
|
||||
SERVER_START_REQ( get_apc_result )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( handle );
|
||||
if (!(ret = wine_server_call( req ))) *result = reply->result;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!ret && result->type == APC_NONE) continue; /* APC didn't run, try again */
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* server_send_fd
|
||||
*
|
||||
|
|
|
@ -69,6 +69,116 @@
|
|||
static pthread_key_t teb_key;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
* Convert a register context to the server format.
|
||||
*/
|
||||
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
|
||||
{
|
||||
DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
|
||||
|
||||
memset( to, 0, sizeof(*to) );
|
||||
to->cpu = CPU_ARM;
|
||||
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->flags |= SERVER_CTX_CONTROL;
|
||||
to->ctl.arm_regs.sp = from->Sp;
|
||||
to->ctl.arm_regs.lr = from->Lr;
|
||||
to->ctl.arm_regs.pc = from->Pc;
|
||||
to->ctl.arm_regs.cpsr = from->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->flags |= SERVER_CTX_INTEGER;
|
||||
to->integer.arm_regs.r[0] = from->R0;
|
||||
to->integer.arm_regs.r[1] = from->R1;
|
||||
to->integer.arm_regs.r[2] = from->R2;
|
||||
to->integer.arm_regs.r[3] = from->R3;
|
||||
to->integer.arm_regs.r[4] = from->R4;
|
||||
to->integer.arm_regs.r[5] = from->R5;
|
||||
to->integer.arm_regs.r[6] = from->R6;
|
||||
to->integer.arm_regs.r[7] = from->R7;
|
||||
to->integer.arm_regs.r[8] = from->R8;
|
||||
to->integer.arm_regs.r[9] = from->R9;
|
||||
to->integer.arm_regs.r[10] = from->R10;
|
||||
to->integer.arm_regs.r[11] = from->R11;
|
||||
to->integer.arm_regs.r[12] = from->R12;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->flags |= SERVER_CTX_FLOATING_POINT;
|
||||
for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i];
|
||||
to->fp.arm_regs.fpscr = from->Fpscr;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
|
||||
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
|
||||
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
|
||||
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_ARM;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Sp = from->ctl.arm_regs.sp;
|
||||
to->Lr = from->ctl.arm_regs.lr;
|
||||
to->Pc = from->ctl.arm_regs.pc;
|
||||
to->Cpsr = from->ctl.arm_regs.cpsr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->R0 = from->integer.arm_regs.r[0];
|
||||
to->R1 = from->integer.arm_regs.r[1];
|
||||
to->R2 = from->integer.arm_regs.r[2];
|
||||
to->R3 = from->integer.arm_regs.r[3];
|
||||
to->R4 = from->integer.arm_regs.r[4];
|
||||
to->R5 = from->integer.arm_regs.r[5];
|
||||
to->R6 = from->integer.arm_regs.r[6];
|
||||
to->R7 = from->integer.arm_regs.r[7];
|
||||
to->R8 = from->integer.arm_regs.r[8];
|
||||
to->R9 = from->integer.arm_regs.r[9];
|
||||
to->R10 = from->integer.arm_regs.r[10];
|
||||
to->R11 = from->integer.arm_regs.r[11];
|
||||
to->R12 = from->integer.arm_regs.r[12];
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i];
|
||||
to->Fpscr = from->fp.arm_regs.fpscr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
|
||||
for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
|
||||
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
|
||||
for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -74,6 +74,104 @@ static pthread_key_t teb_key;
|
|||
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
* Convert a register context to the server format.
|
||||
*/
|
||||
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
|
||||
{
|
||||
DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM64; /* get rid of CPU id */
|
||||
|
||||
memset( to, 0, sizeof(*to) );
|
||||
to->cpu = CPU_ARM64;
|
||||
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->flags |= SERVER_CTX_CONTROL;
|
||||
to->integer.arm64_regs.x[29] = from->u.s.Fp;
|
||||
to->integer.arm64_regs.x[30] = from->u.s.Lr;
|
||||
to->ctl.arm64_regs.sp = from->Sp;
|
||||
to->ctl.arm64_regs.pc = from->Pc;
|
||||
to->ctl.arm64_regs.pstate = from->Cpsr;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->flags |= SERVER_CTX_INTEGER;
|
||||
for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->u.X[i];
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->flags |= SERVER_CTX_FLOATING_POINT;
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
to->fp.arm64_regs.q[i].low = from->V[i].s.Low;
|
||||
to->fp.arm64_regs.q[i].high = from->V[i].s.High;
|
||||
}
|
||||
to->fp.arm64_regs.fpcr = from->Fpcr;
|
||||
to->fp.arm64_regs.fpsr = from->Fpsr;
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i];
|
||||
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i];
|
||||
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i];
|
||||
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
DWORD i;
|
||||
|
||||
if (from->cpu != CPU_ARM64) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_ARM64;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->u.s.Fp = from->integer.arm64_regs.x[29];
|
||||
to->u.s.Lr = from->integer.arm64_regs.x[30];
|
||||
to->Sp = from->ctl.arm64_regs.sp;
|
||||
to->Pc = from->ctl.arm64_regs.pc;
|
||||
to->Cpsr = from->ctl.arm64_regs.pstate;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
for (i = 0; i <= 28; i++) to->u.X[i] = from->integer.arm64_regs.x[i];
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
to->V[i].s.Low = from->fp.arm64_regs.q[i].low;
|
||||
to->V[i].s.High = from->fp.arm64_regs.q[i].high;
|
||||
}
|
||||
to->Fpcr = from->fp.arm64_regs.fpcr;
|
||||
to->Fpsr = from->fp.arm64_regs.fpsr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i];
|
||||
for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i];
|
||||
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i];
|
||||
for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i];
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -168,6 +168,148 @@ static inline int is_gdt_sel( WORD sel )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
* Convert a register context to the server format.
|
||||
*/
|
||||
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
|
||||
{
|
||||
DWORD flags = from->ContextFlags & ~CONTEXT_i386; /* get rid of CPU id */
|
||||
|
||||
memset( to, 0, sizeof(*to) );
|
||||
to->cpu = CPU_x86;
|
||||
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->flags |= SERVER_CTX_CONTROL;
|
||||
to->ctl.i386_regs.ebp = from->Ebp;
|
||||
to->ctl.i386_regs.esp = from->Esp;
|
||||
to->ctl.i386_regs.eip = from->Eip;
|
||||
to->ctl.i386_regs.cs = from->SegCs;
|
||||
to->ctl.i386_regs.ss = from->SegSs;
|
||||
to->ctl.i386_regs.eflags = from->EFlags;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->flags |= SERVER_CTX_INTEGER;
|
||||
to->integer.i386_regs.eax = from->Eax;
|
||||
to->integer.i386_regs.ebx = from->Ebx;
|
||||
to->integer.i386_regs.ecx = from->Ecx;
|
||||
to->integer.i386_regs.edx = from->Edx;
|
||||
to->integer.i386_regs.esi = from->Esi;
|
||||
to->integer.i386_regs.edi = from->Edi;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_SEGMENTS;
|
||||
to->seg.i386_regs.ds = from->SegDs;
|
||||
to->seg.i386_regs.es = from->SegEs;
|
||||
to->seg.i386_regs.fs = from->SegFs;
|
||||
to->seg.i386_regs.gs = from->SegGs;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->flags |= SERVER_CTX_FLOATING_POINT;
|
||||
to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
|
||||
to->fp.i386_regs.status = from->FloatSave.StatusWord;
|
||||
to->fp.i386_regs.tag = from->FloatSave.TagWord;
|
||||
to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
|
||||
to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
|
||||
to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
|
||||
to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
|
||||
to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
|
||||
memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
to->debug.i386_regs.dr0 = from->Dr0;
|
||||
to->debug.i386_regs.dr1 = from->Dr1;
|
||||
to->debug.i386_regs.dr2 = from->Dr2;
|
||||
to->debug.i386_regs.dr3 = from->Dr3;
|
||||
to->debug.i386_regs.dr6 = from->Dr6;
|
||||
to->debug.i386_regs.dr7 = from->Dr7;
|
||||
}
|
||||
if (flags & CONTEXT_EXTENDED_REGISTERS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
|
||||
memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
if (from->cpu != CPU_x86) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_i386;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Ebp = from->ctl.i386_regs.ebp;
|
||||
to->Esp = from->ctl.i386_regs.esp;
|
||||
to->Eip = from->ctl.i386_regs.eip;
|
||||
to->SegCs = from->ctl.i386_regs.cs;
|
||||
to->SegSs = from->ctl.i386_regs.ss;
|
||||
to->EFlags = from->ctl.i386_regs.eflags;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->Eax = from->integer.i386_regs.eax;
|
||||
to->Ebx = from->integer.i386_regs.ebx;
|
||||
to->Ecx = from->integer.i386_regs.ecx;
|
||||
to->Edx = from->integer.i386_regs.edx;
|
||||
to->Esi = from->integer.i386_regs.esi;
|
||||
to->Edi = from->integer.i386_regs.edi;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_SEGMENTS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_SEGMENTS;
|
||||
to->SegDs = from->seg.i386_regs.ds;
|
||||
to->SegEs = from->seg.i386_regs.es;
|
||||
to->SegFs = from->seg.i386_regs.fs;
|
||||
to->SegGs = from->seg.i386_regs.gs;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
|
||||
to->FloatSave.StatusWord = from->fp.i386_regs.status;
|
||||
to->FloatSave.TagWord = from->fp.i386_regs.tag;
|
||||
to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
|
||||
to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
|
||||
to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
|
||||
to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
|
||||
to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
|
||||
memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
to->Dr0 = from->debug.i386_regs.dr0;
|
||||
to->Dr1 = from->debug.i386_regs.dr1;
|
||||
to->Dr2 = from->debug.i386_regs.dr2;
|
||||
to->Dr3 = from->debug.i386_regs.dr3;
|
||||
to->Dr6 = from->debug.i386_regs.dr6;
|
||||
to->Dr7 = from->debug.i386_regs.dr7;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_EXTENDED_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
|
||||
memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* LDT support
|
||||
*/
|
||||
|
|
|
@ -66,6 +66,208 @@
|
|||
static pthread_key_t teb_key;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
* Convert a register context to the server format.
|
||||
*/
|
||||
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
|
||||
{
|
||||
DWORD flags = from->ContextFlags; /* no CPU id? */
|
||||
|
||||
memset( to, 0, sizeof(*to) );
|
||||
to->cpu = CPU_POWERPC;
|
||||
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->flags |= SERVER_CTX_CONTROL;
|
||||
to->ctl.powerpc_regs.iar = from->Iar;
|
||||
to->ctl.powerpc_regs.msr = from->Msr;
|
||||
to->ctl.powerpc_regs.ctr = from->Ctr;
|
||||
to->ctl.powerpc_regs.lr = from->Lr;
|
||||
to->ctl.powerpc_regs.dar = from->Dar;
|
||||
to->ctl.powerpc_regs.dsisr = from->Dsisr;
|
||||
to->ctl.powerpc_regs.trap = from->Trap;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->flags |= SERVER_CTX_INTEGER;
|
||||
to->integer.powerpc_regs.gpr[0] = from->Gpr0;
|
||||
to->integer.powerpc_regs.gpr[1] = from->Gpr1;
|
||||
to->integer.powerpc_regs.gpr[2] = from->Gpr2;
|
||||
to->integer.powerpc_regs.gpr[3] = from->Gpr3;
|
||||
to->integer.powerpc_regs.gpr[4] = from->Gpr4;
|
||||
to->integer.powerpc_regs.gpr[5] = from->Gpr5;
|
||||
to->integer.powerpc_regs.gpr[6] = from->Gpr6;
|
||||
to->integer.powerpc_regs.gpr[7] = from->Gpr7;
|
||||
to->integer.powerpc_regs.gpr[8] = from->Gpr8;
|
||||
to->integer.powerpc_regs.gpr[9] = from->Gpr9;
|
||||
to->integer.powerpc_regs.gpr[10] = from->Gpr10;
|
||||
to->integer.powerpc_regs.gpr[11] = from->Gpr11;
|
||||
to->integer.powerpc_regs.gpr[12] = from->Gpr12;
|
||||
to->integer.powerpc_regs.gpr[13] = from->Gpr13;
|
||||
to->integer.powerpc_regs.gpr[14] = from->Gpr14;
|
||||
to->integer.powerpc_regs.gpr[15] = from->Gpr15;
|
||||
to->integer.powerpc_regs.gpr[16] = from->Gpr16;
|
||||
to->integer.powerpc_regs.gpr[17] = from->Gpr17;
|
||||
to->integer.powerpc_regs.gpr[18] = from->Gpr18;
|
||||
to->integer.powerpc_regs.gpr[19] = from->Gpr19;
|
||||
to->integer.powerpc_regs.gpr[20] = from->Gpr20;
|
||||
to->integer.powerpc_regs.gpr[21] = from->Gpr21;
|
||||
to->integer.powerpc_regs.gpr[22] = from->Gpr22;
|
||||
to->integer.powerpc_regs.gpr[23] = from->Gpr23;
|
||||
to->integer.powerpc_regs.gpr[24] = from->Gpr24;
|
||||
to->integer.powerpc_regs.gpr[25] = from->Gpr25;
|
||||
to->integer.powerpc_regs.gpr[26] = from->Gpr26;
|
||||
to->integer.powerpc_regs.gpr[27] = from->Gpr27;
|
||||
to->integer.powerpc_regs.gpr[28] = from->Gpr28;
|
||||
to->integer.powerpc_regs.gpr[29] = from->Gpr29;
|
||||
to->integer.powerpc_regs.gpr[30] = from->Gpr30;
|
||||
to->integer.powerpc_regs.gpr[31] = from->Gpr31;
|
||||
to->integer.powerpc_regs.xer = from->Xer;
|
||||
to->integer.powerpc_regs.cr = from->Cr;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->flags |= SERVER_CTX_FLOATING_POINT;
|
||||
to->fp.powerpc_regs.fpr[0] = from->Fpr0;
|
||||
to->fp.powerpc_regs.fpr[1] = from->Fpr1;
|
||||
to->fp.powerpc_regs.fpr[2] = from->Fpr2;
|
||||
to->fp.powerpc_regs.fpr[3] = from->Fpr3;
|
||||
to->fp.powerpc_regs.fpr[4] = from->Fpr4;
|
||||
to->fp.powerpc_regs.fpr[5] = from->Fpr5;
|
||||
to->fp.powerpc_regs.fpr[6] = from->Fpr6;
|
||||
to->fp.powerpc_regs.fpr[7] = from->Fpr7;
|
||||
to->fp.powerpc_regs.fpr[8] = from->Fpr8;
|
||||
to->fp.powerpc_regs.fpr[9] = from->Fpr9;
|
||||
to->fp.powerpc_regs.fpr[10] = from->Fpr10;
|
||||
to->fp.powerpc_regs.fpr[11] = from->Fpr11;
|
||||
to->fp.powerpc_regs.fpr[12] = from->Fpr12;
|
||||
to->fp.powerpc_regs.fpr[13] = from->Fpr13;
|
||||
to->fp.powerpc_regs.fpr[14] = from->Fpr14;
|
||||
to->fp.powerpc_regs.fpr[15] = from->Fpr15;
|
||||
to->fp.powerpc_regs.fpr[16] = from->Fpr16;
|
||||
to->fp.powerpc_regs.fpr[17] = from->Fpr17;
|
||||
to->fp.powerpc_regs.fpr[18] = from->Fpr18;
|
||||
to->fp.powerpc_regs.fpr[19] = from->Fpr19;
|
||||
to->fp.powerpc_regs.fpr[20] = from->Fpr20;
|
||||
to->fp.powerpc_regs.fpr[21] = from->Fpr21;
|
||||
to->fp.powerpc_regs.fpr[22] = from->Fpr22;
|
||||
to->fp.powerpc_regs.fpr[23] = from->Fpr23;
|
||||
to->fp.powerpc_regs.fpr[24] = from->Fpr24;
|
||||
to->fp.powerpc_regs.fpr[25] = from->Fpr25;
|
||||
to->fp.powerpc_regs.fpr[26] = from->Fpr26;
|
||||
to->fp.powerpc_regs.fpr[27] = from->Fpr27;
|
||||
to->fp.powerpc_regs.fpr[28] = from->Fpr28;
|
||||
to->fp.powerpc_regs.fpr[29] = from->Fpr29;
|
||||
to->fp.powerpc_regs.fpr[30] = from->Fpr30;
|
||||
to->fp.powerpc_regs.fpr[31] = from->Fpr31;
|
||||
to->fp.powerpc_regs.fpscr = from->Fpscr;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
if (from->cpu != CPU_POWERPC) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = 0; /* no CPU id? */
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Msr = from->ctl.powerpc_regs.msr;
|
||||
to->Ctr = from->ctl.powerpc_regs.ctr;
|
||||
to->Iar = from->ctl.powerpc_regs.iar;
|
||||
to->Lr = from->ctl.powerpc_regs.lr;
|
||||
to->Dar = from->ctl.powerpc_regs.dar;
|
||||
to->Dsisr = from->ctl.powerpc_regs.dsisr;
|
||||
to->Trap = from->ctl.powerpc_regs.trap;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->Gpr0 = from->integer.powerpc_regs.gpr[0];
|
||||
to->Gpr1 = from->integer.powerpc_regs.gpr[1];
|
||||
to->Gpr2 = from->integer.powerpc_regs.gpr[2];
|
||||
to->Gpr3 = from->integer.powerpc_regs.gpr[3];
|
||||
to->Gpr4 = from->integer.powerpc_regs.gpr[4];
|
||||
to->Gpr5 = from->integer.powerpc_regs.gpr[5];
|
||||
to->Gpr6 = from->integer.powerpc_regs.gpr[6];
|
||||
to->Gpr7 = from->integer.powerpc_regs.gpr[7];
|
||||
to->Gpr8 = from->integer.powerpc_regs.gpr[8];
|
||||
to->Gpr9 = from->integer.powerpc_regs.gpr[9];
|
||||
to->Gpr10 = from->integer.powerpc_regs.gpr[10];
|
||||
to->Gpr11 = from->integer.powerpc_regs.gpr[11];
|
||||
to->Gpr12 = from->integer.powerpc_regs.gpr[12];
|
||||
to->Gpr13 = from->integer.powerpc_regs.gpr[13];
|
||||
to->Gpr14 = from->integer.powerpc_regs.gpr[14];
|
||||
to->Gpr15 = from->integer.powerpc_regs.gpr[15];
|
||||
to->Gpr16 = from->integer.powerpc_regs.gpr[16];
|
||||
to->Gpr17 = from->integer.powerpc_regs.gpr[17];
|
||||
to->Gpr18 = from->integer.powerpc_regs.gpr[18];
|
||||
to->Gpr19 = from->integer.powerpc_regs.gpr[19];
|
||||
to->Gpr20 = from->integer.powerpc_regs.gpr[20];
|
||||
to->Gpr21 = from->integer.powerpc_regs.gpr[21];
|
||||
to->Gpr22 = from->integer.powerpc_regs.gpr[22];
|
||||
to->Gpr23 = from->integer.powerpc_regs.gpr[23];
|
||||
to->Gpr24 = from->integer.powerpc_regs.gpr[24];
|
||||
to->Gpr25 = from->integer.powerpc_regs.gpr[25];
|
||||
to->Gpr26 = from->integer.powerpc_regs.gpr[26];
|
||||
to->Gpr27 = from->integer.powerpc_regs.gpr[27];
|
||||
to->Gpr28 = from->integer.powerpc_regs.gpr[28];
|
||||
to->Gpr29 = from->integer.powerpc_regs.gpr[29];
|
||||
to->Gpr30 = from->integer.powerpc_regs.gpr[30];
|
||||
to->Gpr31 = from->integer.powerpc_regs.gpr[31];
|
||||
to->Xer = from->integer.powerpc_regs.xer;
|
||||
to->Cr = from->integer.powerpc_regs.cr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
to->Fpr0 = from->fp.powerpc_regs.fpr[0];
|
||||
to->Fpr1 = from->fp.powerpc_regs.fpr[1];
|
||||
to->Fpr2 = from->fp.powerpc_regs.fpr[2];
|
||||
to->Fpr3 = from->fp.powerpc_regs.fpr[3];
|
||||
to->Fpr4 = from->fp.powerpc_regs.fpr[4];
|
||||
to->Fpr5 = from->fp.powerpc_regs.fpr[5];
|
||||
to->Fpr6 = from->fp.powerpc_regs.fpr[6];
|
||||
to->Fpr7 = from->fp.powerpc_regs.fpr[7];
|
||||
to->Fpr8 = from->fp.powerpc_regs.fpr[8];
|
||||
to->Fpr9 = from->fp.powerpc_regs.fpr[9];
|
||||
to->Fpr10 = from->fp.powerpc_regs.fpr[10];
|
||||
to->Fpr11 = from->fp.powerpc_regs.fpr[11];
|
||||
to->Fpr12 = from->fp.powerpc_regs.fpr[12];
|
||||
to->Fpr13 = from->fp.powerpc_regs.fpr[13];
|
||||
to->Fpr14 = from->fp.powerpc_regs.fpr[14];
|
||||
to->Fpr15 = from->fp.powerpc_regs.fpr[15];
|
||||
to->Fpr16 = from->fp.powerpc_regs.fpr[16];
|
||||
to->Fpr17 = from->fp.powerpc_regs.fpr[17];
|
||||
to->Fpr18 = from->fp.powerpc_regs.fpr[18];
|
||||
to->Fpr19 = from->fp.powerpc_regs.fpr[19];
|
||||
to->Fpr20 = from->fp.powerpc_regs.fpr[20];
|
||||
to->Fpr21 = from->fp.powerpc_regs.fpr[21];
|
||||
to->Fpr22 = from->fp.powerpc_regs.fpr[22];
|
||||
to->Fpr23 = from->fp.powerpc_regs.fpr[23];
|
||||
to->Fpr24 = from->fp.powerpc_regs.fpr[24];
|
||||
to->Fpr25 = from->fp.powerpc_regs.fpr[25];
|
||||
to->Fpr26 = from->fp.powerpc_regs.fpr[26];
|
||||
to->Fpr27 = from->fp.powerpc_regs.fpr[27];
|
||||
to->Fpr28 = from->fp.powerpc_regs.fpr[28];
|
||||
to->Fpr29 = from->fp.powerpc_regs.fpr[29];
|
||||
to->Fpr30 = from->fp.powerpc_regs.fpr[30];
|
||||
to->Fpr31 = from->fp.powerpc_regs.fpr[31];
|
||||
to->Fpscr = from->fp.powerpc_regs.fpscr;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -113,6 +113,140 @@ enum i386_trap_code
|
|||
static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_to_server
|
||||
*
|
||||
* Convert a register context to the server format.
|
||||
*/
|
||||
NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
|
||||
{
|
||||
DWORD flags = from->ContextFlags & ~CONTEXT_AMD64; /* get rid of CPU id */
|
||||
|
||||
memset( to, 0, sizeof(*to) );
|
||||
to->cpu = CPU_x86_64;
|
||||
|
||||
if (flags & CONTEXT_CONTROL)
|
||||
{
|
||||
to->flags |= SERVER_CTX_CONTROL;
|
||||
to->ctl.x86_64_regs.rbp = from->Rbp;
|
||||
to->ctl.x86_64_regs.rip = from->Rip;
|
||||
to->ctl.x86_64_regs.rsp = from->Rsp;
|
||||
to->ctl.x86_64_regs.cs = from->SegCs;
|
||||
to->ctl.x86_64_regs.ss = from->SegSs;
|
||||
to->ctl.x86_64_regs.flags = from->EFlags;
|
||||
}
|
||||
if (flags & CONTEXT_INTEGER)
|
||||
{
|
||||
to->flags |= SERVER_CTX_INTEGER;
|
||||
to->integer.x86_64_regs.rax = from->Rax;
|
||||
to->integer.x86_64_regs.rcx = from->Rcx;
|
||||
to->integer.x86_64_regs.rdx = from->Rdx;
|
||||
to->integer.x86_64_regs.rbx = from->Rbx;
|
||||
to->integer.x86_64_regs.rsi = from->Rsi;
|
||||
to->integer.x86_64_regs.rdi = from->Rdi;
|
||||
to->integer.x86_64_regs.r8 = from->R8;
|
||||
to->integer.x86_64_regs.r9 = from->R9;
|
||||
to->integer.x86_64_regs.r10 = from->R10;
|
||||
to->integer.x86_64_regs.r11 = from->R11;
|
||||
to->integer.x86_64_regs.r12 = from->R12;
|
||||
to->integer.x86_64_regs.r13 = from->R13;
|
||||
to->integer.x86_64_regs.r14 = from->R14;
|
||||
to->integer.x86_64_regs.r15 = from->R15;
|
||||
}
|
||||
if (flags & CONTEXT_SEGMENTS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_SEGMENTS;
|
||||
to->seg.x86_64_regs.ds = from->SegDs;
|
||||
to->seg.x86_64_regs.es = from->SegEs;
|
||||
to->seg.x86_64_regs.fs = from->SegFs;
|
||||
to->seg.x86_64_regs.gs = from->SegGs;
|
||||
}
|
||||
if (flags & CONTEXT_FLOATING_POINT)
|
||||
{
|
||||
to->flags |= SERVER_CTX_FLOATING_POINT;
|
||||
memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
|
||||
}
|
||||
if (flags & CONTEXT_DEBUG_REGISTERS)
|
||||
{
|
||||
to->flags |= SERVER_CTX_DEBUG_REGISTERS;
|
||||
to->debug.x86_64_regs.dr0 = from->Dr0;
|
||||
to->debug.x86_64_regs.dr1 = from->Dr1;
|
||||
to->debug.x86_64_regs.dr2 = from->Dr2;
|
||||
to->debug.x86_64_regs.dr3 = from->Dr3;
|
||||
to->debug.x86_64_regs.dr6 = from->Dr6;
|
||||
to->debug.x86_64_regs.dr7 = from->Dr7;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* context_from_server
|
||||
*
|
||||
* Convert a register context from the server format.
|
||||
*/
|
||||
NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
|
||||
{
|
||||
if (from->cpu != CPU_x86_64) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
to->ContextFlags = CONTEXT_AMD64;
|
||||
if (from->flags & SERVER_CTX_CONTROL)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_CONTROL;
|
||||
to->Rbp = from->ctl.x86_64_regs.rbp;
|
||||
to->Rip = from->ctl.x86_64_regs.rip;
|
||||
to->Rsp = from->ctl.x86_64_regs.rsp;
|
||||
to->SegCs = from->ctl.x86_64_regs.cs;
|
||||
to->SegSs = from->ctl.x86_64_regs.ss;
|
||||
to->EFlags = from->ctl.x86_64_regs.flags;
|
||||
}
|
||||
|
||||
if (from->flags & SERVER_CTX_INTEGER)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_INTEGER;
|
||||
to->Rax = from->integer.x86_64_regs.rax;
|
||||
to->Rcx = from->integer.x86_64_regs.rcx;
|
||||
to->Rdx = from->integer.x86_64_regs.rdx;
|
||||
to->Rbx = from->integer.x86_64_regs.rbx;
|
||||
to->Rsi = from->integer.x86_64_regs.rsi;
|
||||
to->Rdi = from->integer.x86_64_regs.rdi;
|
||||
to->R8 = from->integer.x86_64_regs.r8;
|
||||
to->R9 = from->integer.x86_64_regs.r9;
|
||||
to->R10 = from->integer.x86_64_regs.r10;
|
||||
to->R11 = from->integer.x86_64_regs.r11;
|
||||
to->R12 = from->integer.x86_64_regs.r12;
|
||||
to->R13 = from->integer.x86_64_regs.r13;
|
||||
to->R14 = from->integer.x86_64_regs.r14;
|
||||
to->R15 = from->integer.x86_64_regs.r15;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_SEGMENTS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_SEGMENTS;
|
||||
to->SegDs = from->seg.x86_64_regs.ds;
|
||||
to->SegEs = from->seg.x86_64_regs.es;
|
||||
to->SegFs = from->seg.x86_64_regs.fs;
|
||||
to->SegGs = from->seg.x86_64_regs.gs;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_FLOATING_POINT)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_FLOATING_POINT;
|
||||
memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
|
||||
to->MxCsr = to->u.FltSave.MxCsr;
|
||||
}
|
||||
if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
|
||||
{
|
||||
to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
|
||||
to->Dr0 = from->debug.x86_64_regs.dr0;
|
||||
to->Dr1 = from->debug.x86_64_regs.dr1;
|
||||
to->Dr2 = from->debug.x86_64_regs.dr2;
|
||||
to->Dr3 = from->debug.x86_64_regs.dr3;
|
||||
to->Dr6 = from->debug.x86_64_regs.dr6;
|
||||
to->Dr7 = from->debug.x86_64_regs.dr7;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* get_thread_ldt_entry
|
||||
*/
|
||||
|
|
|
@ -61,6 +61,12 @@ extern void virtual_init(void) DECLSPEC_HIDDEN;
|
|||
extern void CDECL dbg_init(void) DECLSPEC_HIDDEN;
|
||||
|
||||
extern unsigned int CDECL server_call_unlocked( void *req_ptr ) DECLSPEC_HIDDEN;
|
||||
extern unsigned int CDECL server_select( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs,
|
||||
user_apc_t *user_apc ) DECLSPEC_HIDDEN;
|
||||
extern unsigned int CDECL server_wait( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN;
|
||||
extern unsigned int CDECL server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN;
|
||||
extern void CDECL server_send_fd( int fd ) DECLSPEC_HIDDEN;
|
||||
extern int CDECL server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd,
|
||||
int *needs_close, enum server_fd_type *type,
|
||||
|
@ -95,6 +101,9 @@ extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset
|
|||
extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN;
|
||||
extern void start_server( BOOL debug ) DECLSPEC_HIDDEN;
|
||||
|
||||
extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN;
|
||||
|
||||
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
||||
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
struct ldt_copy;
|
||||
|
||||
/* increment this when you change the function table */
|
||||
#define NTDLL_UNIXLIB_VERSION 12
|
||||
#define NTDLL_UNIXLIB_VERSION 13
|
||||
|
||||
struct unix_funcs
|
||||
{
|
||||
|
@ -73,6 +73,12 @@ struct unix_funcs
|
|||
/* server functions */
|
||||
unsigned int (CDECL *server_call_unlocked)( void *req_ptr );
|
||||
unsigned int (CDECL *server_call)( void *req_ptr );
|
||||
unsigned int (CDECL *server_select)( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs,
|
||||
user_apc_t *user_apc );
|
||||
unsigned int (CDECL *server_wait)( const select_op_t *select_op, data_size_t size, UINT flags,
|
||||
const LARGE_INTEGER *timeout );
|
||||
unsigned int (CDECL *server_queue_process_apc)( HANDLE process, const apc_call_t *call, apc_result_t *result );
|
||||
void (CDECL *server_send_fd)( int fd );
|
||||
int (CDECL *server_get_unix_fd)( HANDLE handle, unsigned int wanted_access, int *unix_fd,
|
||||
int *needs_close, enum server_fd_type *type, unsigned int *options );
|
||||
|
|
|
@ -2987,7 +2987,7 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z
|
|||
call.virtual_alloc.zero_bits = zero_bits;
|
||||
call.virtual_alloc.op_type = type;
|
||||
call.virtual_alloc.prot = protect;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_alloc.status == STATUS_SUCCESS)
|
||||
|
@ -3115,7 +3115,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si
|
|||
call.virtual_free.addr = wine_server_client_ptr( addr );
|
||||
call.virtual_free.size = size;
|
||||
call.virtual_free.op_type = type;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_free.status == STATUS_SUCCESS)
|
||||
|
@ -3204,7 +3204,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH NtProtectVirtualMemory( HANDLE process, PVOID
|
|||
call.virtual_protect.addr = wine_server_client_ptr( addr );
|
||||
call.virtual_protect.size = size;
|
||||
call.virtual_protect.prot = new_prot;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_protect.status == STATUS_SUCCESS)
|
||||
|
@ -3308,7 +3308,7 @@ static NTSTATUS get_basic_memory_info( HANDLE process, LPCVOID addr,
|
|||
|
||||
call.virtual_query.type = APC_VIRTUAL_QUERY;
|
||||
call.virtual_query.addr = wine_server_client_ptr( addr );
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_query.status == STATUS_SUCCESS)
|
||||
|
@ -3520,7 +3520,7 @@ NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size,
|
|||
call.virtual_lock.type = APC_VIRTUAL_LOCK;
|
||||
call.virtual_lock.addr = wine_server_client_ptr( *addr );
|
||||
call.virtual_lock.size = *size;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_lock.status == STATUS_SUCCESS)
|
||||
|
@ -3557,7 +3557,7 @@ NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, SIZE_T *size
|
|||
call.virtual_unlock.type = APC_VIRTUAL_UNLOCK;
|
||||
call.virtual_unlock.addr = wine_server_client_ptr( *addr );
|
||||
call.virtual_unlock.size = *size;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_unlock.status == STATUS_SUCCESS)
|
||||
|
@ -3697,7 +3697,7 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
|
|||
call.map_view.zero_bits = zero_bits;
|
||||
call.map_view.alloc_type = alloc_type;
|
||||
call.map_view.prot = protect;
|
||||
res = server_queue_process_apc( process, &call, &result );
|
||||
res = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (res != STATUS_SUCCESS) return res;
|
||||
|
||||
if ((NTSTATUS)result.map_view.status >= 0)
|
||||
|
@ -3733,7 +3733,7 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
|
|||
|
||||
call.unmap_view.type = APC_UNMAP_VIEW;
|
||||
call.unmap_view.addr = wine_server_client_ptr( addr );
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status == STATUS_SUCCESS) status = result.unmap_view.status;
|
||||
return status;
|
||||
}
|
||||
|
@ -3872,7 +3872,7 @@ NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
|
|||
call.virtual_flush.type = APC_VIRTUAL_FLUSH;
|
||||
call.virtual_flush.addr = wine_server_client_ptr( addr );
|
||||
call.virtual_flush.size = *size_ptr;
|
||||
status = server_queue_process_apc( process, &call, &result );
|
||||
status = unix_funcs->server_queue_process_apc( process, &call, &result );
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
if (result.virtual_flush.status == STATUS_SUCCESS)
|
||||
|
|
Loading…
Reference in New Issue