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/win3…
==============================================================================
--- 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/win3…
==============================================================================
--- 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/win3…
==============================================================================
--- 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/win3…
==============================================================================
--- 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/win3…
==============================================================================
--- 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(a)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/win3…
==============================================================================
--- 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/win3…
==============================================================================
--- 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 */