[ros-diffs] [fireball] 49416: - 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...

fireball at svn.reactos.org fireball at svn.reactos.org
Mon Nov 1 21:31:09 UTC 2010


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/win32k/include/winesup.h?rev=49416&r1=49415&r2=49416&view=diff
==============================================================================
--- 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/win32k/main/init.c?rev=49416&r1=49415&r2=49416&view=diff
==============================================================================
--- 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/win32k/win32k.rbuild?rev=49416&r1=49415&r2=49416&view=diff
==============================================================================
--- 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/win32k/wine/queue.c?rev=49416&r1=49415&r2=49416&view=diff
==============================================================================
--- 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/win32k/wine/timeout.c?rev=49416&view=auto
==============================================================================
--- 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 at 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(&current_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(&current_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(&current_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/win32k/wine/winesup.c?rev=49416&r1=49415&r2=49416&view=diff
==============================================================================
--- 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/win32k/wine/winstation.c?rev=49416&r1=49415&r2=49416&view=diff
==============================================================================
--- 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 */




More information about the Ros-diffs mailing list