Commit ad47a30f authored by Alexandre Julliard's avatar Alexandre Julliard

Implemented waitable timers.

parent 1a61a03b
......@@ -18,9 +18,6 @@
DEFAULT_DEBUG_CHANNEL(ntdll)
/* move to winbase.h */
typedef VOID (CALLBACK *PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine,DWORD dwTimerLowValue,DWORD dwTimerHighValue);
/*
* Timer object
*/
......
......@@ -967,6 +967,43 @@ struct set_registry_levels_request
};
/* Create a waitable timer */
struct create_timer_request
{
IN int inherit; /* inherit flag */
IN int manual; /* manual reset */
OUT int handle; /* handle to the timer */
IN WCHAR name[1]; /* timer name */
};
/* Open a waitable timer */
struct open_timer_request
{
IN unsigned int access; /* wanted access rights */
IN int inherit; /* inherit flag */
OUT int handle; /* handle to the timer */
IN WCHAR name[1]; /* timer name */
};
/* Set a waitable timer */
struct set_timer_request
{
IN int handle; /* handle to the timer */
IN int sec; /* next expiration absolute time */
IN int usec; /* next expiration absolute time */
IN int period; /* timer period in ms */
IN void* callback; /* callback function */
IN void* arg; /* callback argument */
};
/* Cancel a waitable timer */
struct cancel_timer_request
{
IN int handle; /* handle to the timer */
};
/* Everything below this line is generated automatically by tools/make_requests */
/* ### make_requests begin ### */
......@@ -1058,6 +1095,10 @@ enum request
REQ_LOAD_REGISTRY,
REQ_SAVE_REGISTRY,
REQ_SET_REGISTRY_LEVELS,
REQ_CREATE_TIMER,
REQ_OPEN_TIMER,
REQ_SET_TIMER,
REQ_CANCEL_TIMER,
REQ_NB_REQUESTS
};
......
......@@ -1086,7 +1086,8 @@ typedef struct tagCOMMTIMEOUTS {
#include "poppack.h"
typedef VOID (CALLBACK *PAPCFUNC)(ULONG_PTR);
typedef void (CALLBACK *PAPCFUNC)(ULONG_PTR);
typedef void (CALLBACK *PTIMERAPCROUTINE)(LPVOID,DWORD,DWORD);
BOOL WINAPI ClearCommError(INT,LPDWORD,LPCOMSTAT);
BOOL WINAPI BuildCommDCBA(LPCSTR,LPDCB);
......@@ -1155,6 +1156,7 @@ BOOL WINAPI BackupEventLogA(HANDLE,LPCSTR);
BOOL WINAPI BackupEventLogW(HANDLE,LPCWSTR);
#define BackupEventLog WINELIB_NAME_AW(BackupEventLog)
BOOL WINAPI Beep(DWORD,DWORD);
BOOL WINAPI CancelWaitableTimer(HANDLE);
BOOL WINAPI ClearEventLogA(HANDLE,LPCSTR);
BOOL WINAPI ClearEventLogW(HANDLE,LPCWSTR);
#define ClearEventLog WINELIB_NAME_AW(ClearEventLog)
......@@ -1198,6 +1200,9 @@ HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCSTR);
HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES,LONG,LONG,LPCWSTR);
#define CreateSemaphore WINELIB_NAME_AW(CreateSemaphore)
HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES,DWORD,LPTHREAD_START_ROUTINE,LPVOID,DWORD,LPDWORD);
HANDLE WINAPI CreateWaitableTimerA(LPSECURITY_ATTRIBUTES,BOOL,LPCSTR);
HANDLE WINAPI CreateWaitableTimerW(LPSECURITY_ATTRIBUTES,BOOL,LPCWSTR);
#define CreateWaitableTimer WINELIB_NAME_AW(CreateWaitableTimer)
BOOL WINAPI DebugActiveProcess(DWORD);
void WINAPI DebugBreak(void);
BOOL WINAPI DeregisterEventSource(HANDLE);
......@@ -1337,6 +1342,7 @@ BOOL WINAPI GetStringTypeExW(LCID,DWORD,LPCWSTR,INT,LPWORD);
VOID WINAPI GetSystemInfo(LPSYSTEM_INFO);
BOOL WINAPI GetSystemPowerStatus(LPSYSTEM_POWER_STATUS);
VOID WINAPI GetSystemTime(LPSYSTEMTIME);
VOID WINAPI GetSystemTimeAsFileTime(LPFILETIME);
INT WINAPI GetTimeFormatA(LCID,DWORD,LPSYSTEMTIME,LPCSTR,LPSTR,INT);
INT WINAPI GetTimeFormatW(LCID,DWORD,LPSYSTEMTIME,LPCWSTR,LPWSTR,INT);
#define GetTimeFormat WINELIB_NAME_AW(GetTimeFormat)
......@@ -1413,6 +1419,9 @@ HANDLE WINAPI OpenSemaphoreA(DWORD,BOOL,LPCSTR);
HANDLE WINAPI OpenSemaphoreW(DWORD,BOOL,LPCWSTR);
#define OpenSemaphore WINELIB_NAME_AW(OpenSemaphore)
BOOL WINAPI OpenThreadToken(HANDLE,DWORD,BOOL,PHANDLE);
HANDLE WINAPI OpenWaitableTimerA(DWORD,BOOL,LPCSTR);
HANDLE WINAPI OpenWaitableTimerW(DWORD,BOOL,LPCWSTR);
#define OpenWaitableTimer WINELIB_NAME_AW(OpenWaitableTimer)
BOOL WINAPI PulseEvent(HANDLE);
BOOL WINAPI PurgeComm(HANDLE,DWORD);
DWORD WINAPI QueryDosDeviceA(LPCSTR,LPSTR,DWORD);
......@@ -1487,6 +1496,7 @@ BOOL WINAPI SetThreadContext(HANDLE,const CONTEXT *);
BOOL WINAPI SetThreadLocale(LCID);
BOOL WINAPI SetThreadPriority(HANDLE,INT);
BOOL WINAPI SetTimeZoneInformation(const LPTIME_ZONE_INFORMATION);
BOOL WINAPI SetWaitableTimer(HANDLE,const LARGE_INTEGER*,LONG,PTIMERAPCROUTINE,LPVOID,BOOL);
VOID WINAPI Sleep(DWORD);
DWORD WINAPI SleepEx(DWORD,BOOL);
DWORD WINAPI SuspendThread(HANDLE);
......
......@@ -873,12 +873,12 @@ import ntdll.dll
# NT 4.0 additions
856 stub CancelIo
857 stub CancelWaitableTimer
857 stdcall CancelWaitableTimer(long) CancelWaitableTimer
858 stdcall CopyFileExA (str str ptr ptr ptr long) CopyFileExA
859 stdcall CopyFileExW (wstr wstr ptr ptr ptr long) CopyFileExW
860 stub CreateFiber
861 stub CreateWaitableTimerA
862 stub CreateWaitableTimerW
861 stdcall CreateWaitableTimerA(ptr long str) CreateWaitableTimerA
862 stdcall CreateWaitableTimerW(ptr long wstr) CreateWaitableTimerW
863 stub DeleteFiber
864 stub DuplicateConsoleHandle
865 stub FindFirstFileExA
......@@ -896,8 +896,8 @@ import ntdll.dll
878 stdcall InterlockedCompareExchange (ptr long long) InterlockedCompareExchange
879 stdcall InterlockedExchangeAdd (ptr long ) InterlockedExchangeAdd
880 stdcall IsProcessorFeaturePresent(long) IsProcessorFeaturePresent
881 stub OpenWaitableTimerA
882 stub OpenWaitableTimerW
881 stdcall OpenWaitableTimerA(long long str) OpenWaitableTimerA
882 stdcall OpenWaitableTimerW(long long wstr) OpenWaitableTimerW
883 stub ReadConsoleInputExA
884 stub ReadConsoleInputExW
885 stub ReadDirectoryChangesW
......@@ -909,7 +909,7 @@ import ntdll.dll
891 stdcall SetProcessPriorityBoost(long long) SetProcessPriorityBoost
892 stub SetThreadIdealProcessor
893 stub SetThreadPriorityBoost
894 stub SetWaitableTimer
894 stdcall SetWaitableTimer(long ptr long ptr ptr long) SetWaitableTimer
895 stub SignalObjectAndWait
896 stub SwitchToFiber
897 stub SwitchToThread
......
......@@ -19,7 +19,8 @@ C_SRCS = \
synchro.c \
sysdeps.c \
syslevel.c \
thread.c
thread.c \
timer.c
all: $(MODULE).o
......
/*
* Win32 waitable timers
*
* Copyright 1999 Alexandre Julliard
*/
#include <assert.h>
#include <string.h>
#include "winerror.h"
#include "file.h" /* for FILETIME routines */
#include "server.h"
/***********************************************************************
* CreateWaitableTimerA (KERNEL32.861)
*/
HANDLE WINAPI CreateWaitableTimerA( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCSTR name )
{
struct create_timer_request *req = get_req_buffer();
req->manual = manual;
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
server_strcpyAtoW( req->name, name );
SetLastError(0);
server_call( REQ_CREATE_TIMER );
if (req->handle == -1) return 0;
return req->handle;
}
/***********************************************************************
* CreateWaitableTimerW (KERNEL32.862)
*/
HANDLE WINAPI CreateWaitableTimerW( SECURITY_ATTRIBUTES *sa, BOOL manual, LPCWSTR name )
{
struct create_timer_request *req = get_req_buffer();
req->manual = manual;
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
server_strcpyW( req->name, name );
SetLastError(0);
server_call( REQ_CREATE_TIMER );
if (req->handle == -1) return 0;
return req->handle;
}
/***********************************************************************
* OpenWaitableTimerA (KERNEL32.881)
*/
HANDLE WINAPI OpenWaitableTimerA( DWORD access, BOOL inherit, LPCSTR name )
{
struct open_timer_request *req = get_req_buffer();
req->access = access;
req->inherit = inherit;
server_strcpyAtoW( req->name, name );
server_call( REQ_OPEN_TIMER );
if (req->handle == -1) return 0; /* must return 0 on failure, not -1 */
return req->handle;
}
/***********************************************************************
* OpenWaitableTimerW (KERNEL32.882)
*/
HANDLE WINAPI OpenWaitableTimerW( DWORD access, BOOL inherit, LPCWSTR name )
{
struct open_timer_request *req = get_req_buffer();
req->access = access;
req->inherit = inherit;
server_strcpyW( req->name, name );
server_call( REQ_OPEN_TIMER );
if (req->handle == -1) return 0; /* must return 0 on failure, not -1 */
return req->handle;
}
/***********************************************************************
* SetWaitableTimer (KERNEL32.894)
*/
BOOL WINAPI SetWaitableTimer( HANDLE handle, const LARGE_INTEGER *when, LONG period,
PTIMERAPCROUTINE callback, LPVOID arg, BOOL resume )
{
FILETIME ft;
DWORD remainder;
struct set_timer_request *req = get_req_buffer();
if (when->s.HighPart < 0) /* relative time */
{
DWORD low = ft.dwLowDateTime;
GetSystemTimeAsFileTime( &ft );
ft.dwLowDateTime -= when->s.LowPart;
ft.dwHighDateTime -= when->s.HighPart;
if (low < ft.dwLowDateTime) ft.dwHighDateTime--; /* overflow */
}
else /* absolute time */
{
ft.dwLowDateTime = when->s.LowPart;
ft.dwHighDateTime = when->s.HighPart;
}
req->handle = handle;
req->sec = DOSFS_FileTimeToUnixTime( &ft, &remainder );
req->usec = remainder / 10; /* convert from 100-ns to us units */
req->period = period;
req->callback = callback;
req->arg = arg;
if (resume) SetLastError( ERROR_NOT_SUPPORTED ); /* set error but can still succeed */
return !server_call( REQ_SET_TIMER );
}
/***********************************************************************
* CancelWaitableTimer (KERNEL32.857)
*/
BOOL WINAPI CancelWaitableTimer( HANDLE handle )
{
struct cancel_timer_request *req = get_req_buffer();
req->handle = handle;
return !server_call( REQ_CANCEL_TIMER );
}
......@@ -27,6 +27,7 @@ C_SRCS = \
sock.c \
socket.c \
thread.c \
timer.c \
trace.c \
unicode.c
......
......@@ -155,6 +155,10 @@ DECL_HANDLER(delete_key_value);
DECL_HANDLER(load_registry);
DECL_HANDLER(save_registry);
DECL_HANDLER(set_registry_levels);
DECL_HANDLER(create_timer);
DECL_HANDLER(open_timer);
DECL_HANDLER(set_timer);
DECL_HANDLER(cancel_timer);
#ifdef WANT_REQUEST_HANDLERS
......@@ -248,6 +252,10 @@ static const struct handler {
{ (void(*)())req_load_registry, sizeof(struct load_registry_request) },
{ (void(*)())req_save_registry, sizeof(struct save_registry_request) },
{ (void(*)())req_set_registry_levels, sizeof(struct set_registry_levels_request) },
{ (void(*)())req_create_timer, sizeof(struct create_timer_request) },
{ (void(*)())req_open_timer, sizeof(struct open_timer_request) },
{ (void(*)())req_set_timer, sizeof(struct set_timer_request) },
{ (void(*)())req_cancel_timer, sizeof(struct cancel_timer_request) },
};
#endif /* WANT_REQUEST_HANDLERS */
......
/*
* Waitable timers management
*
* Copyright (C) 1999 Alexandre Julliard
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include "winerror.h"
#include "handle.h"
#include "request.h"
/* FIXME: check values and move to standard header */
#define TIMER_MODIFY_STATE 0x0001
#define TIMER_QUERY_STATE 0x0002
#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
struct timer
{
struct object obj; /* object header */
int manual; /* manual reset */
int signaled; /* current signaled state */
int period; /* timer period in ms */
struct timeval when; /* next expiration */
struct timeout_user *timeout; /* timeout user */
void *callback; /* callback APC function */
void *arg; /* callback argument */
};
static void timer_dump( struct object *obj, int verbose );
static int timer_signaled( struct object *obj, struct thread *thread );
static int timer_satisfied( struct object *obj, struct thread *thread );
static void timer_destroy( struct object *obj );
static const struct object_ops timer_ops =
{
sizeof(struct timer),
timer_dump,
add_queue,
remove_queue,
timer_signaled,
timer_satisfied,
no_read_fd,
no_write_fd,
no_flush,
no_get_file_info,
timer_destroy
};
/* create a timer object */
static struct timer *create_timer( const WCHAR *name, size_t len, int manual )
{
struct timer *timer;
if ((timer = create_named_object( &timer_ops, name, len )))
{
if (get_error() != ERROR_ALREADY_EXISTS)
{
/* initialize it if it didn't already exist */
timer->manual = manual;
timer->signaled = 0;
timer->when.tv_sec = 0;
timer->when.tv_usec = 0;
timer->period = 0;
timer->timeout = NULL;
}
}
return timer;
}
/* callback on timer expiration */
static void timer_callback( void *private )
{
struct timer *timer = (struct timer *)private;
if (timer->period) /* schedule the next expiration */
{
make_timeout( &timer->when, timer->period );
timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
}
else timer->timeout = NULL;
/* wake up waiters */
timer->signaled = 1;
wake_up( &timer->obj, 0 );
}
/* set the timer expiration and period */
static void set_timer( struct timer *timer, int sec, int usec, int period,
void *callback, void *arg )
{
if (timer->manual)
{
period = 0; /* period doesn't make any sense for a manual timer */
timer->signaled = 0;
}
if (timer->timeout) remove_timeout_user( timer->timeout );
timer->when.tv_sec = sec;
timer->when.tv_usec = usec;
timer->period = period;
timer->callback = callback;
timer->arg = arg;
timer->timeout = add_timeout_user( &timer->when, timer_callback, timer );
}
/* cancel a running timer */
static void cancel_timer( struct timer *timer )
{
if (timer->timeout)
{
remove_timeout_user( timer->timeout );
timer->timeout = NULL;
}
}
static void timer_dump( struct object *obj, int verbose )
{
struct timer *timer = (struct timer *)obj;
assert( obj->ops == &timer_ops );
fprintf( stderr, "Timer manual=%d when=%ld.%06ld period=%d ",
timer->manual, timer->when.tv_sec, timer->when.tv_usec, timer->period );
dump_object_name( &timer->obj );
fputc( '\n', stderr );
}
static int timer_signaled( struct object *obj, struct thread *thread )
{
struct timer *timer = (struct timer *)obj;
assert( obj->ops == &timer_ops );
return timer->signaled;
}
static int timer_satisfied( struct object *obj, struct thread *thread )
{
struct timer *timer = (struct timer *)obj;
assert( obj->ops == &timer_ops );
if (!timer->manual) timer->signaled = 0;
return 0;
}
static void timer_destroy( struct object *obj )
{
struct timer *timer = (struct timer *)obj;
assert( obj->ops == &timer_ops );
if (timer->timeout) remove_timeout_user( timer->timeout );
}
/* create a timer */
DECL_HANDLER(create_timer)
{
size_t len = get_req_strlenW( req->name );
struct timer *timer;
req->handle = -1;
if ((timer = create_timer( req->name, len, req->manual )))
{
req->handle = alloc_handle( current->process, timer, TIMER_ALL_ACCESS, req->inherit );
release_object( timer );
}
}
/* open a handle to a timer */
DECL_HANDLER(open_timer)
{
size_t len = get_req_strlenW( req->name );
req->handle = open_object( req->name, len, &timer_ops, req->access, req->inherit );
}
/* set a waitable timer */
DECL_HANDLER(set_timer)
{
struct timer *timer;
if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
TIMER_MODIFY_STATE, &timer_ops )))
{
set_timer( timer, req->sec, req->usec, req->period, req->callback, req->arg );
release_object( timer );
}
}
/* cancel a waitable timer */
DECL_HANDLER(cancel_timer)
{
struct timer *timer;
if ((timer = (struct timer *)get_handle_obj( current->process, req->handle,
TIMER_MODIFY_STATE, &timer_ops )))
{
cancel_timer( timer );
release_object( timer );
}
}
......@@ -999,6 +999,47 @@ static void dump_set_registry_levels_request( struct set_registry_levels_request
fprintf( stderr, " version=%d", req->version );
}
static void dump_create_timer_request( struct create_timer_request *req )
{
fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " manual=%d,", req->manual );
fprintf( stderr, " name=" );
dump_unicode_string( req->name );
}
static void dump_create_timer_reply( struct create_timer_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
}
static void dump_open_timer_request( struct open_timer_request *req )
{
fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " name=" );
dump_unicode_string( req->name );
}
static void dump_open_timer_reply( struct open_timer_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
}
static void dump_set_timer_request( struct set_timer_request *req )
{
fprintf( stderr, " handle=%d,", req->handle );
fprintf( stderr, " sec=%d,", req->sec );
fprintf( stderr, " usec=%d,", req->usec );
fprintf( stderr, " period=%d,", req->period );
fprintf( stderr, " callback=%p,", req->callback );
fprintf( stderr, " arg=%p", req->arg );
}
static void dump_cancel_timer_request( struct cancel_timer_request *req )
{
fprintf( stderr, " handle=%d", req->handle );
}
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_new_process_request,
(dump_func)dump_new_thread_request,
......@@ -1086,6 +1127,10 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_load_registry_request,
(dump_func)dump_save_registry_request,
(dump_func)dump_set_registry_levels_request,
(dump_func)dump_create_timer_request,
(dump_func)dump_open_timer_request,
(dump_func)dump_set_timer_request,
(dump_func)dump_cancel_timer_request,
};
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
......@@ -1175,6 +1220,10 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)0,
(dump_func)0,
(dump_func)0,
(dump_func)dump_create_timer_reply,
(dump_func)dump_open_timer_reply,
(dump_func)0,
(dump_func)0,
};
static const char * const req_names[REQ_NB_REQUESTS] = {
......@@ -1264,6 +1313,10 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"load_registry",
"save_registry",
"set_registry_levels",
"create_timer",
"open_timer",
"set_timer",
"cancel_timer",
};
/* ### make_requests end ### */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment