Author: ion Date: Thu Aug 4 00:54:00 2011 New Revision: 53056
URL: http://svn.reactos.org/svn/reactos?rev=53056&view=rev Log: [KERNEL32]: Cleanup and fix bugs in the TimerQueue implementation... mainly related to wrong/incorrect parameter checks and error codes.
Modified: trunk/reactos/dll/win32/kernel32/client/timerqueue.c
Modified: trunk/reactos/dll/win32/kernel32/client/timerqueue.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/t... ============================================================================== --- trunk/reactos/dll/win32/kernel32/client/timerqueue.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/kernel32/client/timerqueue.c [iso-8859-1] Thu Aug 4 00:54:00 2011 @@ -1,132 +1,112 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * PURPOSE: Timer Queue functions - * FILE: dll/win32/kernel32/misc/timerqueue.c - * PROGRAMER: Thomas Weidenmueller w3seek@reactos.com - */ - -/* INCLUDES ******************************************************************/ +/* + * PROJECT: ReactOS Win32 Base API + * LICENSE: See COPYING in the top level directory + * FILE: dll/win32/kernel32/client/timerqueue.c + * PURPOSE: Timer Queue Functions + * PROGRAMMERS: Thomas Weidenmueller w3seek@reactos.com + */ + +/* INCLUDES *******************************************************************/
#include <k32.h>
#define NDEBUG #include <debug.h>
- -/* FUNCTIONS *****************************************************************/ - -HANDLE DefaultTimerQueue = NULL; - -/* - * Create the default timer queue for the current process. This function is only - * called if CreateTimerQueueTimer() or SetTimerQueueTimer() is called. - * However, ChangeTimerQueueTimer() fails with ERROR_INVALID_PARAMETER if the - * default timer queue has not been created, because it assumes there has to be - * a timer queue with a timer if it want's to be changed. - */ -static BOOL -IntCreateDefaultTimerQueue(VOID) -{ - NTSTATUS Status; - - /* FIXME - make this thread safe */ - - /* create the timer queue */ - Status = RtlCreateTimerQueue(&DefaultTimerQueue); - if(!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - DPRINT1("Unable to create the default timer queue!\n"); - return FALSE; - } - - return TRUE; -} - -/* - * @implemented - */ -BOOL -WINAPI -CancelTimerQueueTimer(HANDLE TimerQueue, - HANDLE Timer) -{ - /* Since this function is not documented in PSDK and apparently does nothing - but delete the timer, we just do the same as DeleteTimerQueueTimer(), without - passing a completion event. */ - NTSTATUS Status; - - if(TimerQueue == NULL) - { - /* let's use the process' default timer queue. We assume the default timer - queue has been created with a previous call to CreateTimerQueueTimer() or - SetTimerQueueTimer(), otherwise this call wouldn't make much sense. */ - if(!(TimerQueue = DefaultTimerQueue)) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - } - - if(Timer == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* delete the timer */ - Status = RtlDeleteTimer(TimerQueue, Timer, NULL); - - if(!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - return FALSE; - } - - return TRUE; -} - -/* - * @implemented - */ -BOOL -WINAPI -ChangeTimerQueueTimer(HANDLE TimerQueue, - HANDLE Timer, - ULONG DueTime, - ULONG Period) -{ - NTSTATUS Status; - - if(TimerQueue == NULL) - { - /* let's use the process' default timer queue. We assume the default timer - queue has been created with a previous call to CreateTimerQueueTimer() or - SetTimerQueueTimer(), otherwise this call wouldn't make much sense. */ - if(!(TimerQueue = DefaultTimerQueue)) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - } - - if(Timer == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* update the timer */ - Status = RtlUpdateTimer(TimerQueue, Timer, DueTime, Period); - if(!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - return FALSE; - } - - return TRUE; +/* GLOBALS ********************************************************************/ + +HANDLE BasepDefaultTimerQueue = NULL; + +/* PRIVATE FUNCTIONS **********************************************************/ + +/* FIXME - make this thread safe */ +BOOL +WINAPI +BasepCreateDefaultTimerQueue(VOID) +{ + NTSTATUS Status; + + /* Create the timer queue */ + Status = RtlCreateTimerQueue(&BasepDefaultTimerQueue); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + DPRINT1("Unable to create the default timer queue!\n"); + return FALSE; + } + + return TRUE; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + + +/* + * @implemented + */ +BOOL +WINAPI +CancelTimerQueueTimer(IN HANDLE TimerQueue, + IN HANDLE Timer) +{ + NTSTATUS Status; + + if (!TimerQueue) + { + /* Use the default timer queue */ + TimerQueue = BasepDefaultTimerQueue; + if (!TimerQueue) + { + /* A timer is being cancelled before one was created... fail */ + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + } + + /* Delete the timer */ + Status = RtlDeleteTimer(TimerQueue, Timer, NULL); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; +} + +/* + * @implemented + */ +BOOL +WINAPI +ChangeTimerQueueTimer(IN HANDLE TimerQueue, + IN HANDLE Timer, + IN ULONG DueTime, + IN ULONG Period) +{ + NTSTATUS Status; + + if (!TimerQueue) + { + /* Use the default timer queue */ + TimerQueue = BasepDefaultTimerQueue; + if (!TimerQueue) + { + /* A timer is being cancelled before one was created... fail */ + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + /* Delete the timer */ + Status = RtlUpdateTimer(TimerQueue, Timer, DueTime, Period); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; }
/* @@ -136,173 +116,161 @@ WINAPI CreateTimerQueue(VOID) { - HANDLE Handle; - NTSTATUS Status; - - /* create the timer queue */ - Status = RtlCreateTimerQueue(&Handle); - if(!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - return NULL; - } - - return Handle; -} - -/* - * @implemented - */ -BOOL -WINAPI -CreateTimerQueueTimer(PHANDLE phNewTimer, - HANDLE TimerQueue, - WAITORTIMERCALLBACK Callback, - PVOID Parameter, - DWORD DueTime, - DWORD Period, - ULONG Flags) -{ - NTSTATUS Status; - - /* windows seems not to test this parameter at all, so we'll try to clear it here - so we don't crash somewhere inside ntdll */ - *phNewTimer = NULL; - - if(TimerQueue == NULL) - { - /* the default timer queue is requested, try to create it if it hasn't been already */ - if(!(TimerQueue = DefaultTimerQueue)) - { - if(!IntCreateDefaultTimerQueue()) - { - /* IntCreateDefaultTimerQueue() set the last error code already, just fail */ - return FALSE; - } - TimerQueue = DefaultTimerQueue; - } - } - - /* !!! Win doesn't even check if Callback == NULL, so we don't, too! That'll - raise a nice exception later... */ - - /* create the timer */ - Status = RtlCreateTimer(TimerQueue, phNewTimer, Callback, Parameter, DueTime, - Period, Flags); - if(!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - return FALSE; - } - - return TRUE; -} - -/* - * @implemented - */ -BOOL -WINAPI -DeleteTimerQueue(HANDLE TimerQueue) -{ - NTSTATUS Status; - - /* We don't allow the user to delete the default timer queue */ - if(TimerQueue == NULL) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - /* delete the timer queue */ - Status = RtlDeleteTimerQueue(TimerQueue); - return NT_SUCCESS(Status); -} - -/* - * @implemented - */ -BOOL -WINAPI -DeleteTimerQueueEx(HANDLE TimerQueue, - HANDLE CompletionEvent) -{ - NTSTATUS Status; - - /* We don't allow the user to delete the default timer queue */ - if(TimerQueue == NULL) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - /* delete the queue */ - Status = RtlDeleteTimerQueueEx(TimerQueue, CompletionEvent); - - if((CompletionEvent != INVALID_HANDLE_VALUE && Status == STATUS_PENDING) || - !NT_SUCCESS(Status)) - { - /* In case CompletionEvent == NULL, RtlDeleteTimerQueueEx() returns before - all callback routines returned. We set the last error code to STATUS_PENDING - and return FALSE. In case CompletionEvent == INVALID_HANDLE_VALUE we only - can get here if another error occured. In case CompletionEvent is something - else, we get here and fail, even though it isn't really an error (if Status == STATUS_PENDING). - We also handle all other failures the same way. */ - - BaseSetLastNTError(Status); - return FALSE; - } - - return TRUE; -} - -/* - * @implemented - */ -BOOL -WINAPI -DeleteTimerQueueTimer(HANDLE TimerQueue, - HANDLE Timer, - HANDLE CompletionEvent) -{ - NTSTATUS Status; - - if(TimerQueue == NULL) - { - /* let's use the process' default timer queue. We assume the default timer - queue has been created with a previous call to CreateTimerQueueTimer() or - SetTimerQueueTimer(), otherwise this call wouldn't make much sense. */ - if(!(TimerQueue = DefaultTimerQueue)) - { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - } - - if(Timer == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* delete the timer */ - Status = RtlDeleteTimer(TimerQueue, Timer, CompletionEvent); - - if((CompletionEvent != INVALID_HANDLE_VALUE && Status == STATUS_PENDING) || - !NT_SUCCESS(Status)) - { - /* In case CompletionEvent == NULL, RtlDeleteTimer() returns before - the callback routine returned. We set the last error code to STATUS_PENDING - and return FALSE. In case CompletionEvent == INVALID_HANDLE_VALUE we only - can get here if another error occured. In case CompletionEvent is something - else, we get here and fail, even though it isn't really an error (if Status == STATUS_PENDING). - We also handle all other failures the same way. */ - - BaseSetLastNTError(Status); - return FALSE; - } - - return TRUE; + HANDLE Handle; + NTSTATUS Status; + + /* Create the timer queue */ + Status = RtlCreateTimerQueue(&Handle); + if(!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return NULL; + } + + return Handle; +} + +/* + * @implemented + */ +BOOL +WINAPI +CreateTimerQueueTimer(OUT PHANDLE phNewTimer, + IN HANDLE TimerQueue, + IN WAITORTIMERCALLBACK Callback, + IN PVOID Parameter, + IN DWORD DueTime, + IN DWORD Period, + IN ULONG Flags) +{ + NTSTATUS Status; + + /* Parameter is not optional -- clear it now */ + *phNewTimer = NULL; + + /* Check if no queue was given */ + if (!TimerQueue) + { + /* Create the queue if it didn't already exist */ + if (!(BasepDefaultTimerQueue) && !(BasepCreateDefaultTimerQueue())) + { + return FALSE; + } + + /* Use the default queue */ + TimerQueue = BasepDefaultTimerQueue; + } + + /* Create the timer. Note that no parameter checking is done here */ + Status = RtlCreateTimer(TimerQueue, + phNewTimer, + Callback, + Parameter, + DueTime, + Period, + Flags); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; +} + +/* + * @implemented + */ +BOOL +WINAPI +DeleteTimerQueue(IN HANDLE TimerQueue) +{ + /* We don't allow the user to delete the default timer queue */ + if (!TimerQueue) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + /* Delete the timer queue */ + RtlDeleteTimerQueueEx(TimerQueue, 0); + return TRUE; +} + +/* + * @implemented + */ +BOOL +WINAPI +DeleteTimerQueueEx(IN HANDLE TimerQueue, + IN HANDLE CompletionEvent) +{ + NTSTATUS Status; + + /* We don't allow the user to delete the default timer queue */ + if (!TimerQueue) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + /* Delete the timer queue */ + Status = RtlDeleteTimerQueueEx(TimerQueue, CompletionEvent); + if (((CompletionEvent != INVALID_HANDLE_VALUE) && (Status == STATUS_PENDING)) || + !(NT_SUCCESS(Status))) + { + /* In case CompletionEvent == NULL, RtlDeleteTimerQueueEx() returns before + all callback routines returned. We set the last error code to STATUS_PENDING + and return FALSE. In case CompletionEvent == INVALID_HANDLE_VALUE we only + can get here if another error occured. In case CompletionEvent is something + else, we get here and fail, even though it isn't really an error (if Status == STATUS_PENDING). + We also handle all other failures the same way. */ + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; +} + +/* + * @implemented + */ +BOOL +WINAPI +DeleteTimerQueueTimer(IN HANDLE TimerQueue, + IN HANDLE Timer, + IN HANDLE CompletionEvent) +{ + NTSTATUS Status; + + if (!TimerQueue) + { + /* Use the default timer queue */ + TimerQueue = BasepDefaultTimerQueue; + if (!TimerQueue) + { + /* A timer is being cancelled before one was created... fail */ + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + + /* Delete the timer */ + Status = RtlDeleteTimer(TimerQueue, Timer, CompletionEvent); + if (((CompletionEvent != INVALID_HANDLE_VALUE) && (Status == STATUS_PENDING)) || + !(NT_SUCCESS(Status))) + { + /* In case CompletionEvent == NULL, RtlDeleteTimerQueueEx() returns before + all callback routines returned. We set the last error code to STATUS_PENDING + and return FALSE. In case CompletionEvent == INVALID_HANDLE_VALUE we only + can get here if another error occured. In case CompletionEvent is something + else, we get here and fail, even though it isn't really an error (if Status == STATUS_PENDING). + We also handle all other failures the same way. */ + BaseSetLastNTError(Status); + return FALSE; + } + + return TRUE; }
/* @@ -310,50 +278,44 @@ */ HANDLE WINAPI -SetTimerQueueTimer(HANDLE TimerQueue, - WAITORTIMERCALLBACK Callback, - PVOID Parameter, - DWORD DueTime, - DWORD Period, - BOOL PreferIo) -{ - /* Since this function is not documented in PSDK and apparently does nothing - but create a timer, we just do the same as CreateTimerQueueTimer(). Unfortunately - I don't really know what PreferIo is supposed to be, it propably just affects the - Flags parameter of CreateTimerQueueTimer(). Looking at the PSDK documentation of - CreateTimerQueueTimer() there's only one flag (WT_EXECUTEINIOTHREAD) that causes - the callback function queued to an I/O worker thread. I guess it uses this flag - if PreferIo == TRUE, otherwise let's just use WT_EXECUTEDEFAULT. We should - test this though, this is only guess work and I'm too lazy to do further - investigation. */ - - HANDLE Timer; - NTSTATUS Status; - - if(TimerQueue == NULL) - { - /* the default timer queue is requested, try to create it if it hasn't been already */ - if(!(TimerQueue = DefaultTimerQueue)) - { - if(!IntCreateDefaultTimerQueue()) - { - /* IntCreateDefaultTimerQueue() set the last error code already, just fail */ - return FALSE; - } - TimerQueue = DefaultTimerQueue; - } - } - - /* create the timer */ - Status = RtlCreateTimer(TimerQueue, &Timer, Callback, Parameter, DueTime, - Period, (PreferIo ? WT_EXECUTEINIOTHREAD : WT_EXECUTEDEFAULT)); - if(!NT_SUCCESS(Status)) - { - BaseSetLastNTError(Status); - return NULL; - } - - return Timer; +SetTimerQueueTimer(IN HANDLE TimerQueue, + IN WAITORTIMERCALLBACK Callback, + IN PVOID Parameter, + IN DWORD DueTime, + IN DWORD Period, + IN BOOL PreferIo) +{ + HANDLE Timer; + NTSTATUS Status; + + /* Check if no queue was given */ + if (!TimerQueue) + { + /* Create the queue if it didn't already exist */ + if (!(BasepDefaultTimerQueue) && !(BasepCreateDefaultTimerQueue())) + { + return FALSE; + } + + /* Use the default queue */ + TimerQueue = BasepDefaultTimerQueue; + } + + /* Create the timer */ + Status = RtlCreateTimer(TimerQueue, + &Timer, + Callback, + Parameter, + DueTime, + Period, + PreferIo ? WT_EXECUTEINIOTHREAD : WT_EXECUTEDEFAULT); + if (!NT_SUCCESS(Status)) + { + BaseSetLastNTError(Status); + return NULL; + } + + return Timer; }
/* EOF */