Author: fireball Date: Mon Nov 1 21:31:07 2010 New Revision: 49416
URL: http://svn.reactos.org/svn/reactos?rev=49416&view=rev Log: - Properly implement win32k timers in arwinss. Fixes a whole bunch of weird crashes, race conditions, unnecessary code complications, and things like that (e.g. #5222). - A couple of timer managing functions are based on code (c) Alexandre Julliard, Wine project (server/fd.c). See issue #5222 for more details.
Added: branches/arwinss/reactos/subsystems/win32/win32k/wine/timeout.c (with props) Modified: branches/arwinss/reactos/subsystems/win32/win32k/include/winesup.h branches/arwinss/reactos/subsystems/win32/win32k/main/init.c branches/arwinss/reactos/subsystems/win32/win32k/win32k.rbuild branches/arwinss/reactos/subsystems/win32/win32k/wine/queue.c branches/arwinss/reactos/subsystems/win32/win32k/wine/winesup.c branches/arwinss/reactos/subsystems/win32/win32k/wine/winstation.c
Modified: branches/arwinss/reactos/subsystems/win32/win32k/include/winesup.h URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/include/winesup.h [iso-8859-1] (original) +++ branches/arwinss/reactos/subsystems/win32/win32k/include/winesup.h [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -123,14 +123,13 @@ static inline int check_object_access(struct object *obj, unsigned int *access) { return TRUE; };
// timeout stuff -struct timeout_user -{ - KTIMER Timer; - KDPC Dpc; -}; +VOID NTAPI InitTimeThread(); +struct timeout_user;
-typedef PKDEFERRED_ROUTINE timeout_callback; #define TICKS_PER_SEC 10000000 + +typedef void (*timeout_callback)( void *private ); + void remove_timeout_user( struct timeout_user *user ); struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private );
@@ -140,7 +139,7 @@ LARGE_INTEGER time; KeQuerySystemTime(&time);
- *value = time.QuadPart / 10; + *value = time.QuadPart; }
Modified: branches/arwinss/reactos/subsystems/win32/win32k/main/init.c URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/main/init.c [iso-8859-1] (original) +++ branches/arwinss/reactos/subsystems/win32/win32k/main/init.c [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -374,6 +374,9 @@ /* Create stock objects */ CreateStockObjects();
+ /* Initialize timers */ + InitTimeThread(); + /* Init video driver implementation */ InitDcImpl();
Modified: branches/arwinss/reactos/subsystems/win32/win32k/win32k.rbuild URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/win32k.rbuild [iso-8859-1] (original) +++ branches/arwinss/reactos/subsystems/win32/win32k/win32k.rbuild [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -148,6 +148,7 @@ <file>queue.c</file> <file>region.c</file> <file>stubs.c</file> + <file>timeout.c</file> <file>user.c</file> <file>window.c</file> <file>winesup.c</file>
Modified: branches/arwinss/reactos/subsystems/win32/win32k/wine/queue.c URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/wine/queue.c [iso-8859-1] (original) +++ branches/arwinss/reactos/subsystems/win32/win32k/wine/queue.c [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -139,7 +139,7 @@ static void msg_queue_poll_event( struct fd *fd, int event ); static void thread_input_dump( struct object *obj, int verbose ); static void thread_input_destroy( struct object *obj ); -static VOID NTAPI timer_callback( PKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2 ); +static void timer_callback( void *private );
static const struct object_ops msg_queue_ops = { @@ -527,21 +527,14 @@ free_message( msg ); }
-VOID -NTAPI -result_timeout_worker( PVOID Context ) -{ - PQUEUE_WORKER_CONTEXT work_context = Context; - struct message_result *result = work_context->result; - - UserEnterExclusive(); +/* message timed out without getting a reply */ +static void result_timeout( void *private ) +{ + struct message_result *result = private;
assert( !result->replied );
result->timeout = NULL; - - /* Free work item memory */ - ExFreePool(work_context);
if (result->msg) /* not received yet */ { @@ -554,30 +547,11 @@ if (!result->sender) { free_result( result ); - UserLeave(); return; } }
store_message_result( result, 0, STATUS_TIMEOUT ); - UserLeave(); -} - -/* message timed out without getting a reply */ -static VOID -NTAPI -result_timeout( PKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2) -{ - struct message_result *result = Context; - PQUEUE_WORKER_CONTEXT work_context; - - /* Allocate memory for the work iteam */ - work_context = ExAllocatePool(NonPagedPool, sizeof(QUEUE_WORKER_CONTEXT)); - work_context->result = result; - - /* Queue a work item */ - ExInitializeWorkItem(&work_context->item, result_timeout_worker, result); - ExQueueWorkItem(&work_context->item, DelayedWorkQueue); }
/* allocate and fill a message result structure */ @@ -1063,21 +1037,10 @@ }
/* callback for the next timer expiration */ -static -VOID -NTAPI -timer_callback_worker( PVOID Context ) -{ - PQUEUE_WORKER_CONTEXT work_context = Context; +static void timer_callback( void *private ) +{ struct list *ptr; - struct msg_queue *queue = work_context->queue; - - ASSERT(queue); - - UserEnterExclusive(); - - /* Free workitem */ - ExFreePool(work_context); + struct msg_queue *queue = private;
queue->timeout = NULL; /* move on to the next timer */ @@ -1085,26 +1048,6 @@ list_remove( ptr ); list_add_tail( &queue->expired_timers, ptr ); set_next_timer( queue ); - - UserLeave(); -} - -static -VOID -NTAPI -timer_callback( PKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2 ) -{ - struct msg_queue *queue = Context; - PQUEUE_WORKER_CONTEXT work_context; - - /* Allocate memory for the work iteam */ - work_context = ExAllocatePool(NonPagedPool, sizeof(QUEUE_WORKER_CONTEXT)); - - work_context->queue = queue; - - /* Queue a work item */ - ExInitializeWorkItem(&work_context->item, timer_callback_worker, work_context); - ExQueueWorkItem(&work_context->item, DelayedWorkQueue); }
/* link a timer at its rightful place in the queue list */
Added: branches/arwinss/reactos/subsystems/win32/win32k/wine/timeout.c URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/wine/timeout.c (added) +++ branches/arwinss/reactos/subsystems/win32/win32k/wine/timeout.c [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -1,0 +1,241 @@ +/* + * PROJECT: ReactOS Win32K + * LICENSE: LGPL v2.1 or any later - See COPYING in the top level directory + * FILE: subsystems/win32/win32k/wine/timer.c + * PURPOSE: Timer code for user server + * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#include <win32k.h> + +#include "object.h" + +#define NDEBUG +#include <debug.h> + +PKTIMER MasterTimer; +static HANDLE TimerThreadHandle; +static CLIENT_ID TimerThreadId; +static KEVENT TimerThreadsStart; +static PVOID TimerWaitObjects[2]; + +/* PRIVATE FUNCTIONS *********************************************************/ + +/****************************************************************/ +/* timeouts support */ + +struct timeout_user +{ + struct list entry; /* entry in sorted timeout list */ + timeout_t when; /* timeout expiry (absolute time) */ + timeout_callback callback; /* callback function */ + void *private; /* callback private data */ +}; + +static struct list timeout_list = LIST_INIT(timeout_list); /* sorted timeouts list */ + +/* add a timeout user */ +struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private ) +{ + struct timeout_user *user; + struct list *ptr; + timeout_t current_time; + + DPRINT("add_timeout_user(when %I64d, func %p)\n", when, func); + + get_current_time(¤t_time); + + if (!(user = mem_alloc( sizeof(*user) ))) return NULL; + user->when = (when > 0) ? when : current_time - when; + user->callback = func; + user->private = private; + + /* Now insert it in the linked list */ + + LIST_FOR_EACH( ptr, &timeout_list ) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + if (timeout->when >= user->when) break; + } + list_add_before( ptr, &user->entry ); + + /* Inform timeout thread that we have a new timer */ + KeSetEvent(&TimerThreadsStart, IO_NO_INCREMENT, FALSE); + + return user; +} + +/* remove a timeout user */ +void remove_timeout_user( struct timeout_user *user ) +{ + list_remove( &user->entry ); + ExFreePool( user ); +} + +/* return a text description of a timeout for debugging purposes */ +const char *get_timeout_str( timeout_t timeout ) +{ + static char buffer[64]; + long secs, nsecs; + timeout_t current_time; + + get_current_time(¤t_time); + + if (!timeout) return "0"; + if (timeout == TIMEOUT_INFINITE) return "infinite"; + + if (timeout < 0) /* relative */ + { + secs = -timeout / TICKS_PER_SEC; + nsecs = -timeout % TICKS_PER_SEC; + sprintf( buffer, "+%ld.%07ld", secs, nsecs ); + } + else /* absolute */ + { + secs = (timeout - current_time) / TICKS_PER_SEC; + nsecs = (timeout - current_time) % TICKS_PER_SEC; + if (nsecs < 0) + { + nsecs += TICKS_PER_SEC; + secs--; + } + if (secs >= 0) + sprintf( buffer, "%x%08x (+%ld.%07ld)", + (unsigned int)(timeout >> 32), (unsigned int)timeout, secs, nsecs ); + else + sprintf( buffer, "%x%08x (-%ld.%07ld)", + (unsigned int)(timeout >> 32), (unsigned int)timeout, + -(secs + 1), TICKS_PER_SEC - nsecs ); + } + return buffer; +} + +/* process pending timeouts and return the time until the next timeout, in milliseconds */ +static int get_next_timeout(void) +{ + timeout_t current_time; + get_current_time(¤t_time); + + if (!list_empty( &timeout_list )) + { + struct list expired_list, *ptr; + + /* first remove all expired timers from the list */ + + list_init( &expired_list ); + while ((ptr = list_head( &timeout_list )) != NULL) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + + if (timeout->when <= current_time) + { + list_remove( &timeout->entry ); + list_add_tail( &expired_list, &timeout->entry ); + } + else break; + } + + /* now call the callback for all the removed timers */ + + while ((ptr = list_head( &expired_list )) != NULL) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + list_remove( &timeout->entry ); + timeout->callback( timeout->private ); + ExFreePool( timeout ); + } + + if ((ptr = list_head( &timeout_list )) != NULL) + { + struct timeout_user *timeout = LIST_ENTRY( ptr, struct timeout_user, entry ); + //int diff = (timeout->when - current_time + 9999) / 10000; + int diff = timeout->when - current_time + 1; + if (diff < 0) diff = 0; + return diff; + } + } + return -1; /* no pending timeouts */ +} + +VOID +ProcessTimers() +{ + int timeout; + LARGE_INTEGER DueTime; + + timeout = get_next_timeout(); + + if (timeout != -1) + { + /* Wait for the next time out */ + DueTime.QuadPart = -timeout; + KeSetTimer(MasterTimer, DueTime, NULL); + } + else + { + /* Reset the timer making it signal in 60 seconds */ + DueTime.QuadPart = Int32x32To64(60, -TICKS_PER_SEC); + KeSetTimer(MasterTimer, DueTime, NULL); + } +} + +static VOID APIENTRY +TimerThreadMain(PVOID StartContext) +{ + NTSTATUS Status; + + TimerWaitObjects[0] = &TimerThreadsStart; + TimerWaitObjects[1] = MasterTimer; + + KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + 3); + + for(;;) + { + Status = KeWaitForMultipleObjects(2, + TimerWaitObjects, + WaitAny, + WrUserRequest, + KernelMode, + TRUE, + NULL, + NULL); + + /* Process timers inside a user lock */ + UserEnterExclusive(); + ProcessTimers(); + UserLeave(); + } + DPRINT1("Timer thread exit!\n"); +} + +VOID +NTAPI +InitTimeThread() +{ + NTSTATUS Status; + + /* Event used to signal when a new timer is added */ + KeInitializeEvent(&TimerThreadsStart, SynchronizationEvent, FALSE); + + MasterTimer = ExAllocatePool(NonPagedPool, sizeof(KTIMER)); + if (!MasterTimer) + { + ASSERT(FALSE); + return; + } + + KeInitializeTimer(MasterTimer); + + Status = PsCreateSystemThread(&TimerThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + &TimerThreadId, + TimerThreadMain, + NULL); + if (!NT_SUCCESS(Status)) DPRINT1("Win32K: Failed to create timer thread.\n"); +} + +/* EOF */
Propchange: branches/arwinss/reactos/subsystems/win32/win32k/wine/timeout.c ------------------------------------------------------------------------------ svn:eol-style = native
Modified: branches/arwinss/reactos/subsystems/win32/win32k/wine/winesup.c URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/wine/winesup.c [iso-8859-1] (original) +++ branches/arwinss/reactos/subsystems/win32/win32k/wine/winesup.c [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -47,40 +47,6 @@ { UNIMPLEMENTED; return NULL; -} - -struct timeout_user *add_timeout_user( timeout_t when, timeout_callback func, void *private ) -{ - LARGE_INTEGER DueTime; - struct timeout_user *TimeoutUser; - - DueTime.QuadPart = (LONGLONG)when * 10; - - /* Allocate memory for timeout structure */ - TimeoutUser = ExAllocatePool(NonPagedPool, sizeof(struct timeout_user)); - - //DPRINT1("add_timeout_user(%p when %I64d, diff %I64d msecs, func %p)\n", TimeoutUser, when, secs, func); - - /* Initialize timer and DPC objects */ - KeInitializeTimer(&TimeoutUser->Timer); - KeInitializeDpc(&TimeoutUser->Dpc, func, private); - - /* Set the timer */ - KeSetTimer(&TimeoutUser->Timer, DueTime, &TimeoutUser->Dpc); - - return TimeoutUser; -} - -/* remove a timeout user */ -void remove_timeout_user( struct timeout_user *user ) -{ - //DPRINT1("remove_timeout_user %p, current time %I64d\n", user, current_time); - - /* Cancel the timer */ - KeCancelTimer(&user->Timer); - - /* Free memory */ - ExFreePool(user); }
/* default map_access() routine for objects that behave like an fd */
Modified: branches/arwinss/reactos/subsystems/win32/win32k/wine/winstation.c URL: http://svn.reactos.org/svn/reactos/branches/arwinss/reactos/subsystems/win32... ============================================================================== --- branches/arwinss/reactos/subsystems/win32/win32k/wine/winstation.c [iso-8859-1] (original) +++ branches/arwinss/reactos/subsystems/win32/win32k/wine/winstation.c [iso-8859-1] Mon Nov 1 21:31:07 2010 @@ -467,12 +467,9 @@ clear_error(); }
-static -VOID -NTAPI -close_desktop_timeout( PKDPC Dpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2 ) -{ - struct desktop *desktop = Context; +static void close_desktop_timeout( void *private ) +{ + struct desktop *desktop = private;
desktop->close_timeout = NULL; unlink_named_object( &desktop->obj ); /* make sure no other process can open it */