Moved WaitForMultipleObjects to ntdll (based on a patch by Eric
Pouech). Added NTDLL_get_server_timeout function to compute ntdll-style timeouts and adapted the timer code to use it.
This commit is contained in:
parent
43bfe7f2d0
commit
fbef57c0ce
|
@ -249,7 +249,7 @@
|
||||||
@ stdcall NtUnmapViewOfSection(long ptr)
|
@ stdcall NtUnmapViewOfSection(long ptr)
|
||||||
@ stub NtVdmControl
|
@ stub NtVdmControl
|
||||||
@ stub NtW32Call
|
@ stub NtW32Call
|
||||||
@ stub NtWaitForMultipleObjects
|
@ stdcall NtWaitForMultipleObjects(long ptr long long ptr)
|
||||||
@ stub NtWaitForProcessMutant
|
@ stub NtWaitForProcessMutant
|
||||||
@ stdcall NtWaitForSingleObject(long long long)
|
@ stdcall NtWaitForSingleObject(long long long)
|
||||||
@ stub NtWaitHighEventPair
|
@ stub NtWaitHighEventPair
|
||||||
|
@ -773,7 +773,7 @@
|
||||||
@ stdcall ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection
|
@ stdcall ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection
|
||||||
@ stub ZwVdmControl
|
@ stub ZwVdmControl
|
||||||
@ stub ZwW32Call
|
@ stub ZwW32Call
|
||||||
@ stub ZwWaitForMultipleObjects
|
@ stdcall ZwWaitForMultipleObjects(long ptr long long ptr) NtWaitForMultipleObjects
|
||||||
@ stub ZwWaitForProcessMutant
|
@ stub ZwWaitForProcessMutant
|
||||||
@ stdcall ZwWaitForSingleObject(long long long) NtWaitForSingleObject
|
@ stdcall ZwWaitForSingleObject(long long long) NtWaitForSingleObject
|
||||||
@ stub ZwWaitHighEventPair
|
@ stub ZwWaitHighEventPair
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
extern LPCSTR debugstr_us( const UNICODE_STRING *str );
|
extern LPCSTR debugstr_us( const UNICODE_STRING *str );
|
||||||
extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
|
extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
|
||||||
|
|
||||||
|
extern void NTDLL_get_server_timeout( struct timeval *when, const LARGE_INTEGER *timeout );
|
||||||
|
|
||||||
/* module handling */
|
/* module handling */
|
||||||
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
|
extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop );
|
||||||
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
|
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
|
||||||
|
|
|
@ -268,19 +268,6 @@ NTSTATUS WINAPI NtClose( HANDLE Handle )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* NtWaitForSingleObject [NTDLL.@]
|
|
||||||
* ZwWaitForSingleObject [NTDLL.@]
|
|
||||||
*/
|
|
||||||
NTSTATUS WINAPI NtWaitForSingleObject(
|
|
||||||
IN HANDLE Object,
|
|
||||||
IN BOOLEAN Alertable,
|
|
||||||
IN PLARGE_INTEGER Time)
|
|
||||||
{
|
|
||||||
FIXME("(%p,0x%08x,%p),stub!\n",Object,Alertable,Time);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Directory functions
|
* Directory functions
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Process synchronisation
|
* Process synchronisation
|
||||||
*
|
*
|
||||||
|
* Copyright 1997 Alexandre Julliard
|
||||||
* Copyright 1999, 2000 Juergen Schmied
|
* Copyright 1999, 2000 Juergen Schmied
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
|
@ -18,16 +19,31 @@
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#ifdef HAVE_SYS_TIME_H
|
||||||
|
# include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_POLL_H
|
||||||
|
# include <sys/poll.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "wine/debug.h"
|
|
||||||
|
|
||||||
#include "winerror.h"
|
|
||||||
#include "wine/unicode.h"
|
|
||||||
#include "wine/server.h"
|
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
#include "async.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "wine/server.h"
|
||||||
|
#include "wine/unicode.h"
|
||||||
|
#include "wine/debug.h"
|
||||||
#include "ntdll_misc.h"
|
#include "ntdll_misc.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
||||||
|
@ -261,3 +277,174 @@ NTSTATUS WINAPI NtQueryEvent (
|
||||||
FIXME("(%p)\n", EventHandle);
|
FIXME("(%p)\n", EventHandle);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* check_async_list
|
||||||
|
*
|
||||||
|
* Process a status event from the server.
|
||||||
|
*/
|
||||||
|
static void WINAPI check_async_list(async_private *asp, DWORD status)
|
||||||
|
{
|
||||||
|
async_private *ovp;
|
||||||
|
DWORD ovp_status;
|
||||||
|
|
||||||
|
for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
|
||||||
|
|
||||||
|
if(!ovp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( status != STATUS_ALERTED )
|
||||||
|
{
|
||||||
|
ovp_status = status;
|
||||||
|
ovp->ops->set_status (ovp, status);
|
||||||
|
}
|
||||||
|
else ovp_status = ovp->ops->get_status (ovp);
|
||||||
|
|
||||||
|
if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
|
||||||
|
|
||||||
|
/* This will destroy all but PENDING requests */
|
||||||
|
register_old_async( ovp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* wait_reply
|
||||||
|
*
|
||||||
|
* Wait for a reply on the waiting pipe of the current thread.
|
||||||
|
*/
|
||||||
|
static int wait_reply( void *cookie )
|
||||||
|
{
|
||||||
|
int signaled;
|
||||||
|
struct wake_up_reply reply;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
|
||||||
|
if (ret == sizeof(reply))
|
||||||
|
{
|
||||||
|
if (!reply.cookie) break; /* thread got killed */
|
||||||
|
if (reply.cookie == cookie) return reply.signaled;
|
||||||
|
/* we stole another reply, wait for the real one */
|
||||||
|
signaled = wait_reply( cookie );
|
||||||
|
/* and now put the wrong one back in the pipe */
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ret = write( NtCurrentTeb()->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");
|
||||||
|
}
|
||||||
|
/* the server closed the connection; time to die... */
|
||||||
|
SYSDEPS_AbortThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* call_apcs
|
||||||
|
*
|
||||||
|
* Call outstanding APCs.
|
||||||
|
*/
|
||||||
|
static void call_apcs( BOOL alertable )
|
||||||
|
{
|
||||||
|
FARPROC proc = NULL;
|
||||||
|
LARGE_INTEGER time;
|
||||||
|
void *args[4];
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int type = APC_NONE;
|
||||||
|
SERVER_START_REQ( get_apc )
|
||||||
|
{
|
||||||
|
req->alertable = alertable;
|
||||||
|
wine_server_set_reply( req, args, sizeof(args) );
|
||||||
|
if (!wine_server_call( req ))
|
||||||
|
{
|
||||||
|
type = reply->type;
|
||||||
|
proc = reply->func;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case APC_NONE:
|
||||||
|
return; /* no more APCs */
|
||||||
|
case APC_ASYNC:
|
||||||
|
proc( args[0], args[1]);
|
||||||
|
break;
|
||||||
|
case APC_USER:
|
||||||
|
proc( args[0] );
|
||||||
|
break;
|
||||||
|
case APC_TIMER:
|
||||||
|
/* convert sec/usec to NT time */
|
||||||
|
RtlSecondsSince1970ToTime( (time_t)args[0], &time );
|
||||||
|
time.QuadPart += (DWORD)args[1] * 10;
|
||||||
|
proc( args[2], time.s.LowPart, time.s.HighPart );
|
||||||
|
break;
|
||||||
|
case APC_ASYNC_IO:
|
||||||
|
check_async_list ( args[0], (DWORD) args[1]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
server_protocol_error( "get_apc_request: bad type %d\n", type );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait operations */
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* NtWaitForMultipleObjects (NTDLL.@)
|
||||||
|
*/
|
||||||
|
NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
|
||||||
|
BOOLEAN wait_all, BOOLEAN alertable,
|
||||||
|
PLARGE_INTEGER timeout )
|
||||||
|
{
|
||||||
|
int ret, cookie;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
if (count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
|
||||||
|
|
||||||
|
NTDLL_get_server_timeout( &tv, timeout );
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
SERVER_START_REQ( select )
|
||||||
|
{
|
||||||
|
req->flags = SELECT_INTERRUPTIBLE;
|
||||||
|
req->cookie = &cookie;
|
||||||
|
req->sec = tv.tv_sec;
|
||||||
|
req->usec = tv.tv_usec;
|
||||||
|
wine_server_add_data( req, handles, count * sizeof(HANDLE) );
|
||||||
|
|
||||||
|
if (wait_all) req->flags |= SELECT_ALL;
|
||||||
|
if (alertable) req->flags |= SELECT_ALERTABLE;
|
||||||
|
if (timeout) req->flags |= SELECT_TIMEOUT;
|
||||||
|
|
||||||
|
ret = wine_server_call( req );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
|
||||||
|
if (ret != STATUS_USER_APC) break;
|
||||||
|
call_apcs( alertable );
|
||||||
|
if (alertable) break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************
|
||||||
|
* NtWaitForSingleObject (NTDLL.@)
|
||||||
|
*/
|
||||||
|
NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, PLARGE_INTEGER timeout )
|
||||||
|
{
|
||||||
|
return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
|
||||||
|
}
|
||||||
|
|
|
@ -269,9 +269,11 @@ static const struct tagTZ_INFO TZ_INFO[] =
|
||||||
#define MONSPERYEAR 12
|
#define MONSPERYEAR 12
|
||||||
|
|
||||||
/* 1601 to 1970 is 369 years plus 89 leap days */
|
/* 1601 to 1970 is 369 years plus 89 leap days */
|
||||||
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400)
|
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
|
||||||
|
#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
|
||||||
/* 1601 to 1980 is 379 years plus 91 leap days */
|
/* 1601 to 1980 is 379 years plus 91 leap days */
|
||||||
#define SECS_1601_to_1980 ((379 * 365 + 91) * (ULONGLONG)86400)
|
#define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY)
|
||||||
|
#define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC)
|
||||||
|
|
||||||
|
|
||||||
static const int YearLengths[2] = {DAYSPERNORMALYEAR, DAYSPERLEAPYEAR};
|
static const int YearLengths[2] = {DAYSPERNORMALYEAR, DAYSPERLEAPYEAR};
|
||||||
|
@ -292,6 +294,39 @@ static inline void NormalizeTimeFields(CSHORT *FieldToNormalize, CSHORT *CarryFi
|
||||||
*CarryField = (CSHORT) (*CarryField + 1);
|
*CarryField = (CSHORT) (*CarryField + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* NTDLL_get_server_timeout
|
||||||
|
*
|
||||||
|
* Convert a NTDLL timeout into a timeval struct to send to the server.
|
||||||
|
*/
|
||||||
|
void NTDLL_get_server_timeout( struct timeval *when, const LARGE_INTEGER *timeout )
|
||||||
|
{
|
||||||
|
UINT remainder;
|
||||||
|
|
||||||
|
if (!timeout) /* infinite timeout */
|
||||||
|
{
|
||||||
|
when->tv_sec = when->tv_usec = 0;
|
||||||
|
}
|
||||||
|
else if (timeout->QuadPart <= 0) /* relative timeout */
|
||||||
|
{
|
||||||
|
ULONG sec = RtlEnlargedUnsignedDivide( -timeout->QuadPart, TICKSPERSEC, &remainder );
|
||||||
|
gettimeofday( when, 0 );
|
||||||
|
if ((when->tv_usec += remainder / 10) >= 1000000)
|
||||||
|
{
|
||||||
|
when->tv_usec -= 1000000;
|
||||||
|
when->tv_sec++;
|
||||||
|
}
|
||||||
|
when->tv_sec += sec;
|
||||||
|
}
|
||||||
|
else /* absolute time */
|
||||||
|
{
|
||||||
|
when->tv_sec = RtlEnlargedUnsignedDivide( timeout->QuadPart - TICKS_1601_TO_1970,
|
||||||
|
TICKSPERSEC, &remainder );
|
||||||
|
when->tv_usec = remainder / 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* RtlTimeToTimeFields [NTDLL.@]
|
* RtlTimeToTimeFields [NTDLL.@]
|
||||||
*
|
*
|
||||||
|
@ -501,7 +536,7 @@ BOOLEAN WINAPI RtlTimeToSecondsSince1980( const LARGE_INTEGER *time, LPDWORD res
|
||||||
{
|
{
|
||||||
ULONGLONG tmp = ((ULONGLONG)time->s.HighPart << 32) | time->s.LowPart;
|
ULONGLONG tmp = ((ULONGLONG)time->s.HighPart << 32) | time->s.LowPart;
|
||||||
tmp = RtlLargeIntegerDivide( tmp, 10000000, NULL );
|
tmp = RtlLargeIntegerDivide( tmp, 10000000, NULL );
|
||||||
tmp -= SECS_1601_to_1980;
|
tmp -= SECS_1601_TO_1980;
|
||||||
if (tmp > 0xffffffff) return FALSE;
|
if (tmp > 0xffffffff) return FALSE;
|
||||||
*res = (DWORD)tmp;
|
*res = (DWORD)tmp;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -521,7 +556,7 @@ BOOLEAN WINAPI RtlTimeToSecondsSince1980( const LARGE_INTEGER *time, LPDWORD res
|
||||||
*/
|
*/
|
||||||
void WINAPI RtlSecondsSince1970ToTime( DWORD time, LARGE_INTEGER *res )
|
void WINAPI RtlSecondsSince1970ToTime( DWORD time, LARGE_INTEGER *res )
|
||||||
{
|
{
|
||||||
ULONGLONG secs = RtlExtendedIntegerMultiply( time + SECS_1601_TO_1970, 10000000 );
|
ULONGLONG secs = time * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
|
||||||
res->s.LowPart = (DWORD)secs;
|
res->s.LowPart = (DWORD)secs;
|
||||||
res->s.HighPart = (DWORD)(secs >> 32);
|
res->s.HighPart = (DWORD)(secs >> 32);
|
||||||
}
|
}
|
||||||
|
@ -540,7 +575,7 @@ void WINAPI RtlSecondsSince1970ToTime( DWORD time, LARGE_INTEGER *res )
|
||||||
*/
|
*/
|
||||||
void WINAPI RtlSecondsSince1980ToTime( DWORD time, LARGE_INTEGER *res )
|
void WINAPI RtlSecondsSince1980ToTime( DWORD time, LARGE_INTEGER *res )
|
||||||
{
|
{
|
||||||
ULONGLONG secs = RtlExtendedIntegerMultiply( time + SECS_1601_to_1980, 10000000 );
|
ULONGLONG secs = time * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1980;
|
||||||
res->s.LowPart = (DWORD)secs;
|
res->s.LowPart = (DWORD)secs;
|
||||||
res->s.HighPart = (DWORD)(secs >> 32);
|
res->s.HighPart = (DWORD)(secs >> 32);
|
||||||
}
|
}
|
||||||
|
@ -588,7 +623,8 @@ NTSTATUS WINAPI NtQuerySystemTime( PLARGE_INTEGER time )
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
|
|
||||||
gettimeofday( &now, 0 );
|
gettimeofday( &now, 0 );
|
||||||
time->QuadPart = RtlExtendedIntegerMultiply( now.tv_sec+SECS_1601_TO_1970, 10000000 ) + now.tv_usec * 10;
|
time->QuadPart = now.tv_sec * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970;
|
||||||
|
time->QuadPart += now.tv_usec * 10;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -872,6 +872,7 @@ NTSTATUS WINAPI NtUnloadKey(HKEY);
|
||||||
NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG);
|
NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG);
|
||||||
NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID);
|
NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID);
|
||||||
NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,PLARGE_INTEGER);
|
NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,PLARGE_INTEGER);
|
||||||
|
NTSTATUS WINAPI NtWaitForMultipleObjects(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,PLARGE_INTEGER);
|
||||||
|
|
||||||
void WINAPI RtlAcquirePebLock(void);
|
void WINAPI RtlAcquirePebLock(void);
|
||||||
BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK,BYTE);
|
BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK,BYTE);
|
||||||
|
|
|
@ -20,163 +20,9 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include "winbase.h"
|
||||||
#include <errno.h>
|
#include "winternl.h"
|
||||||
#include <signal.h>
|
|
||||||
#ifdef HAVE_SYS_TIME_H
|
|
||||||
# include <sys/time.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYS_POLL_H
|
|
||||||
# include <sys/poll.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "file.h" /* for DOSFS_UnixTimeToFileTime */
|
|
||||||
#include "thread.h"
|
|
||||||
#include "winerror.h"
|
|
||||||
#include "wine/server.h"
|
|
||||||
#include "async.h"
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* get_timeout
|
|
||||||
*/
|
|
||||||
inline static void get_timeout( struct timeval *when, int timeout )
|
|
||||||
{
|
|
||||||
gettimeofday( when, 0 );
|
|
||||||
if (timeout)
|
|
||||||
{
|
|
||||||
long sec = timeout / 1000;
|
|
||||||
if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
|
|
||||||
{
|
|
||||||
when->tv_usec -= 1000000;
|
|
||||||
when->tv_sec++;
|
|
||||||
}
|
|
||||||
when->tv_sec += sec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* check_async_list
|
|
||||||
*
|
|
||||||
* Process a status event from the server.
|
|
||||||
*/
|
|
||||||
static void WINAPI check_async_list(async_private *asp, DWORD status)
|
|
||||||
{
|
|
||||||
async_private *ovp;
|
|
||||||
DWORD ovp_status;
|
|
||||||
|
|
||||||
for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
|
|
||||||
|
|
||||||
if(!ovp)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( status != STATUS_ALERTED )
|
|
||||||
{
|
|
||||||
ovp_status = status;
|
|
||||||
ovp->ops->set_status (ovp, status);
|
|
||||||
}
|
|
||||||
else ovp_status = ovp->ops->get_status (ovp);
|
|
||||||
|
|
||||||
if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
|
|
||||||
|
|
||||||
/* This will destroy all but PENDING requests */
|
|
||||||
register_old_async( ovp );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* wait_reply
|
|
||||||
*
|
|
||||||
* Wait for a reply on the waiting pipe of the current thread.
|
|
||||||
*/
|
|
||||||
static int wait_reply( void *cookie )
|
|
||||||
{
|
|
||||||
int signaled;
|
|
||||||
struct wake_up_reply reply;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
|
|
||||||
if (ret == sizeof(reply))
|
|
||||||
{
|
|
||||||
if (!reply.cookie) break; /* thread got killed */
|
|
||||||
if (reply.cookie == cookie) return reply.signaled;
|
|
||||||
/* we stole another reply, wait for the real one */
|
|
||||||
signaled = wait_reply( cookie );
|
|
||||||
/* and now put the wrong one back in the pipe */
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ret = write( NtCurrentTeb()->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");
|
|
||||||
}
|
|
||||||
/* the server closed the connection; time to die... */
|
|
||||||
SYSDEPS_AbortThread(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* call_apcs
|
|
||||||
*
|
|
||||||
* Call outstanding APCs.
|
|
||||||
*/
|
|
||||||
static void call_apcs( BOOL alertable )
|
|
||||||
{
|
|
||||||
FARPROC proc = NULL;
|
|
||||||
FILETIME ft;
|
|
||||||
void *args[4];
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int type = APC_NONE;
|
|
||||||
SERVER_START_REQ( get_apc )
|
|
||||||
{
|
|
||||||
req->alertable = alertable;
|
|
||||||
wine_server_set_reply( req, args, sizeof(args) );
|
|
||||||
if (!wine_server_call( req ))
|
|
||||||
{
|
|
||||||
type = reply->type;
|
|
||||||
proc = reply->func;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case APC_NONE:
|
|
||||||
return; /* no more APCs */
|
|
||||||
case APC_ASYNC:
|
|
||||||
proc( args[0], args[1]);
|
|
||||||
break;
|
|
||||||
case APC_USER:
|
|
||||||
proc( args[0] );
|
|
||||||
break;
|
|
||||||
case APC_TIMER:
|
|
||||||
/* convert sec/usec to NT time */
|
|
||||||
DOSFS_UnixTimeToFileTime( (time_t)args[0], &ft, (DWORD)args[1] * 10 );
|
|
||||||
proc( args[2], ft.dwLowDateTime, ft.dwHighDateTime );
|
|
||||||
break;
|
|
||||||
case APC_ASYNC_IO:
|
|
||||||
check_async_list ( args[0], (DWORD) args[1]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
server_protocol_error( "get_apc_request: bad type %d\n", type );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Sleep (KERNEL32.@)
|
* Sleep (KERNEL32.@)
|
||||||
|
@ -233,46 +79,27 @@ DWORD WINAPI WaitForMultipleObjectsEx( DWORD count, const HANDLE *handles,
|
||||||
BOOL wait_all, DWORD timeout,
|
BOOL wait_all, DWORD timeout,
|
||||||
BOOL alertable )
|
BOOL alertable )
|
||||||
{
|
{
|
||||||
int ret, cookie;
|
NTSTATUS status;
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
if (count > MAXIMUM_WAIT_OBJECTS)
|
if (timeout == INFINITE)
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_INVALID_PARAMETER );
|
status = NtWaitForMultipleObjects( count, handles, wait_all, alertable, NULL );
|
||||||
return WAIT_FAILED;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LARGE_INTEGER time;
|
||||||
|
|
||||||
|
time.QuadPart = timeout * (ULONGLONG)10000;
|
||||||
|
time.QuadPart = -time.QuadPart;
|
||||||
|
status = NtWaitForMultipleObjects( count, handles, wait_all, alertable, &time );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout == INFINITE) tv.tv_sec = tv.tv_usec = 0;
|
if (HIWORD(status)) /* is it an error code? */
|
||||||
else get_timeout( &tv, timeout );
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
SERVER_START_REQ( select )
|
SetLastError( RtlNtStatusToDosError(status) );
|
||||||
{
|
status = WAIT_FAILED;
|
||||||
req->flags = SELECT_INTERRUPTIBLE;
|
|
||||||
req->cookie = &cookie;
|
|
||||||
req->sec = tv.tv_sec;
|
|
||||||
req->usec = tv.tv_usec;
|
|
||||||
wine_server_add_data( req, handles, count * sizeof(HANDLE) );
|
|
||||||
|
|
||||||
if (wait_all) req->flags |= SELECT_ALL;
|
|
||||||
if (alertable) req->flags |= SELECT_ALERTABLE;
|
|
||||||
if (timeout != INFINITE) req->flags |= SELECT_TIMEOUT;
|
|
||||||
|
|
||||||
ret = wine_server_call( req );
|
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
return status;
|
||||||
if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
|
|
||||||
if (ret != STATUS_USER_APC) break;
|
|
||||||
call_apcs( alertable );
|
|
||||||
if (alertable) break;
|
|
||||||
}
|
|
||||||
if (HIWORD(ret)) /* is it an error code? */
|
|
||||||
{
|
|
||||||
SetLastError( RtlNtStatusToDosError(ret) );
|
|
||||||
ret = WAIT_FAILED;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,9 @@
|
||||||
#include "winerror.h"
|
#include "winerror.h"
|
||||||
#include "winnls.h"
|
#include "winnls.h"
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
#include "file.h" /* for FILETIME routines */
|
|
||||||
#include "wine/server.h"
|
#include "wine/server.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "ntdll_misc.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(timer);
|
WINE_DEFAULT_DEBUG_CHANNEL(timer);
|
||||||
|
|
||||||
|
@ -130,34 +130,21 @@ BOOL WINAPI SetWaitableTimer( HANDLE handle, const LARGE_INTEGER *when, LONG per
|
||||||
PTIMERAPCROUTINE callback, LPVOID arg, BOOL resume )
|
PTIMERAPCROUTINE callback, LPVOID arg, BOOL resume )
|
||||||
{
|
{
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
LARGE_INTEGER exp = *when;
|
struct timeval tv;
|
||||||
|
|
||||||
if (exp.s.HighPart < 0) /* relative time */
|
if (!when->s.LowPart && !when->s.HighPart)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER now;
|
/* special case to start timeout on now+period without too many calculations */
|
||||||
NtQuerySystemTime( &now );
|
tv.tv_sec = 0;
|
||||||
exp.QuadPart = RtlLargeIntegerSubtract( now.QuadPart, exp.QuadPart );
|
tv.tv_usec = 0;
|
||||||
}
|
}
|
||||||
|
else NTDLL_get_server_timeout( &tv, when );
|
||||||
|
|
||||||
SERVER_START_REQ( set_timer )
|
SERVER_START_REQ( set_timer )
|
||||||
{
|
{
|
||||||
if (!exp.s.LowPart && !exp.s.HighPart)
|
|
||||||
{
|
|
||||||
/* special case to start timeout on now+period without too many calculations */
|
|
||||||
req->sec = 0;
|
|
||||||
req->usec = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DWORD remainder;
|
|
||||||
FILETIME ft;
|
|
||||||
|
|
||||||
ft.dwLowDateTime = exp.s.LowPart;
|
|
||||||
ft.dwHighDateTime = exp.s.HighPart;
|
|
||||||
req->sec = DOSFS_FileTimeToUnixTime( &ft, &remainder );
|
|
||||||
req->usec = remainder / 10; /* convert from 100-ns to us units */
|
|
||||||
}
|
|
||||||
req->handle = handle;
|
req->handle = handle;
|
||||||
|
req->sec = tv.tv_sec;
|
||||||
|
req->usec = tv.tv_usec;
|
||||||
req->period = period;
|
req->period = period;
|
||||||
req->callback = callback;
|
req->callback = callback;
|
||||||
req->arg = arg;
|
req->arg = arg;
|
||||||
|
|
Loading…
Reference in New Issue