Converted the timer list to use standard list functions.
authorAlexandre Julliard <julliard@winehq.org>
Mon, 29 Nov 2004 18:08:18 +0000 (18:08 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 29 Nov 2004 18:08:18 +0000 (18:08 +0000)
Allocate a timer id when the window is 0 instead of relying on the
client to do it.
Allow setting timers on windows belonging to other threads (found by
Mike McCormack).

include/wine/server_protocol.h
server/protocol.def
server/queue.c
server/trace.c

index 36c41c1eec8ee2dc29ec3ff8f43271981c3eccba..192cfacd5826700edad16e92a3324ef31d9fdc3b 100644 (file)
@@ -2198,6 +2198,7 @@ struct set_win_timer_request
 struct set_win_timer_reply
 {
     struct reply_header __header;
+    unsigned int    id;
 };
 
 
@@ -3642,6 +3643,6 @@ union generic_reply
     struct set_global_windows_reply set_global_windows_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 149
+#define SERVER_PROTOCOL_VERSION 150
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
index 7f4d10be7e4d6a4601d274a595cdb663d103b926..e4b8e98f23dabb122b5bdd3beb82cca2b3a5518d 100644 (file)
@@ -1557,6 +1557,8 @@ enum message_type
     unsigned int    id;        /* timer id */
     unsigned int    rate;      /* timer rate in ms */
     unsigned int    lparam;    /* message lparam (callback proc) */
+@REPLY
+    unsigned int    id;        /* timer id */
 @END
 
 
index d71176985b69b6d29dc1452d5fc68e6c85e00f8d..0c9b23f60e2372a1d5f2d255db4561c0066f8875 100644 (file)
@@ -83,8 +83,7 @@ struct message_list
 
 struct timer
 {
-    struct timer   *next;      /* next timer in list */
-    struct timer   *prev;      /* prev timer in list */
+    struct list     entry;     /* entry in timer list */
     struct timeval  when;      /* next expiration */
     unsigned int    rate;      /* timer rate in ms */
     user_handle_t   win;       /* window handle */
@@ -123,9 +122,9 @@ struct msg_queue
     struct list            send_result;     /* stack of sent messages waiting for result */
     struct list            callback_result; /* list of callback messages waiting for result */
     struct message_result *recv_result;     /* stack of received messages waiting for result */
-    struct timer          *first_timer;     /* head of timer list */
-    struct timer          *last_timer;      /* tail of timer list */
-    struct timer          *next_timer;      /* next timer to expire */
+    struct list            pending_timers;  /* list of pending timers */
+    struct list            expired_timers;  /* list of expired timers */
+    unsigned int           next_timer_id;   /* id for the next timer with a 0 window */
     struct timeout_user   *timeout;         /* timeout for next timer to expire */
     struct thread_input   *input;           /* thread input descriptor */
     struct hook_table     *hooks;           /* hook table */
@@ -235,15 +234,15 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
         queue->changed_mask    = 0;
         queue->paint_count     = 0;
         queue->recv_result     = NULL;
-        queue->first_timer     = NULL;
-        queue->last_timer      = NULL;
-        queue->next_timer      = NULL;
+        queue->next_timer_id   = 1;
         queue->timeout         = NULL;
         queue->input           = (struct thread_input *)grab_object( input );
         queue->hooks           = NULL;
         gettimeofday( &queue->last_get_msg, NULL );
         list_init( &queue->send_result );
         list_init( &queue->callback_result );
+        list_init( &queue->pending_timers );
+        list_init( &queue->expired_timers );
         for (i = 0; i < NB_MSG_KINDS; i++)
             queue->msg_list[i].first = queue->msg_list[i].last = NULL;
 
@@ -749,17 +748,23 @@ static int msg_queue_satisfied( struct object *obj, struct thread *thread )
 static void msg_queue_destroy( struct object *obj )
 {
     struct msg_queue *queue = (struct msg_queue *)obj;
-    struct timer *timer = queue->first_timer;
+    struct list *ptr;
     int i;
 
     cleanup_results( queue );
     for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
 
-    while (timer)
+    while ((ptr = list_head( &queue->pending_timers )))
     {
-        struct timer *next = timer->next;
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
+        list_remove( &timer->entry );
+        free( timer );
+    }
+    while ((ptr = list_head( &queue->expired_timers )))
+    {
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
+        list_remove( &timer->entry );
         free( timer );
-        timer = next;
     }
     if (queue->timeout) remove_timeout_user( queue->timeout );
     if (queue->input) release_object( queue->input );
@@ -855,79 +860,93 @@ static void detach_thread_input( struct thread *thread_from, struct thread *thre
 
 
 /* set the next timer to expire */
-static void set_next_timer( struct msg_queue *queue, struct timer *timer )
+static void set_next_timer( struct msg_queue *queue )
 {
+    struct list *ptr;
+
     if (queue->timeout)
     {
         remove_timeout_user( queue->timeout );
         queue->timeout = NULL;
     }
-    if ((queue->next_timer = timer))
+    if ((ptr = list_head( &queue->pending_timers )))
+    {
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
         queue->timeout = add_timeout_user( &timer->when, timer_callback, queue );
-
+    }
     /* set/clear QS_TIMER bit */
-    if (queue->next_timer == queue->first_timer)
+    if (list_empty( &queue->expired_timers ))
         clear_queue_bits( queue, QS_TIMER );
     else
         set_queue_bits( queue, QS_TIMER );
 }
 
+/* find a timer from its window and id */
+static struct timer *find_timer( struct msg_queue *queue, user_handle_t win,
+                                 unsigned int msg, unsigned int id )
+{
+    struct list *ptr;
+
+    /* we need to search both lists */
+
+    LIST_FOR_EACH( ptr, &queue->pending_timers )
+    {
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
+        if (timer->win == win && timer->msg == msg && timer->id == id) return timer;
+    }
+    LIST_FOR_EACH( ptr, &queue->expired_timers )
+    {
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
+        if (timer->win == win && timer->msg == msg && timer->id == id) return timer;
+    }
+    return NULL;
+}
+
 /* callback for the next timer expiration */
 static void timer_callback( void *private )
 {
     struct msg_queue *queue = private;
+    struct list *ptr;
 
     queue->timeout = NULL;
     /* move on to the next timer */
-    set_next_timer( queue, queue->next_timer->next );
+    ptr = list_head( &queue->pending_timers );
+    list_remove( ptr );
+    list_add_tail( &queue->expired_timers, ptr );
+    set_next_timer( queue );
 }
 
 /* link a timer at its rightful place in the queue list */
 static void link_timer( struct msg_queue *queue, struct timer *timer )
 {
-    struct timer *pos = queue->next_timer;
-
-    while (pos && time_before( &pos->when, &timer->when )) pos = pos->next;
+    struct list *ptr;
 
-    if (pos) /* insert before pos */
-    {
-        if ((timer->prev = pos->prev)) timer->prev->next = timer;
-        else queue->first_timer = timer;
-        timer->next = pos;
-        pos->prev = timer;
-    }
-    else  /* insert at end */
+    for (ptr = queue->pending_timers.next; ptr != &queue->pending_timers; ptr = ptr->next)
     {
-        timer->next = NULL;
-        timer->prev = queue->last_timer;
-        if (queue->last_timer) queue->last_timer->next = timer;
-        else queue->first_timer = timer;
-        queue->last_timer = timer;
+        struct timer *t = LIST_ENTRY( ptr, struct timer, entry );
+        if (!time_before( &t->when, &timer->when )) break;
     }
-    /* check if we replaced the next timer */
-    if (pos == queue->next_timer) set_next_timer( queue, timer );
+    list_add_before( ptr, &timer->entry );
 }
 
-/* remove a timer from the queue timer list */
-static void unlink_timer( struct msg_queue *queue, struct timer *timer )
+/* remove a timer from the queue timer list and free it */
+static void free_timer( struct msg_queue *queue, struct timer *timer )
 {
-    if (timer->next) timer->next->prev = timer->prev;
-    else queue->last_timer = timer->prev;
-    if (timer->prev) timer->prev->next = timer->next;
-    else queue->first_timer = timer->next;
-    /* check if we removed the next timer */
-    if (queue->next_timer == timer) set_next_timer( queue, timer->next );
-    else if (queue->next_timer == queue->first_timer) clear_queue_bits( queue, QS_TIMER );
+    list_remove( &timer->entry );
+    free( timer );
+    set_next_timer( queue );
 }
 
 /* restart an expired timer */
 static void restart_timer( struct msg_queue *queue, struct timer *timer )
 {
     struct timeval now;
-    unlink_timer( queue, timer );
+
+    list_remove( &timer->entry );
     gettimeofday( &now, 0 );
     while (!time_before( &now, &timer->when )) add_timeout( &timer->when, timer->rate );
     link_timer( queue, timer );
+    set_next_timer( queue );
 }
 
 /* find an expired timer matching the filtering parameters */
@@ -935,9 +954,11 @@ static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t
                                          unsigned int get_first, unsigned int get_last,
                                          int remove )
 {
-    struct timer *timer;
-    for (timer = queue->first_timer; (timer && timer != queue->next_timer); timer = timer->next)
+    struct list *ptr;
+
+    LIST_FOR_EACH( ptr, &queue->expired_timers )
     {
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
         if (win && timer->win != win) continue;
         if (timer->msg >= get_first && timer->msg <= get_last)
         {
@@ -948,32 +969,18 @@ static struct timer *find_expired_timer( struct msg_queue *queue, user_handle_t
     return NULL;
 }
 
-/* kill a timer */
-static int kill_timer( struct msg_queue *queue, user_handle_t win,
-                       unsigned int msg, unsigned int id )
-{
-    struct timer *timer;
-
-    for (timer = queue->first_timer; timer; timer = timer->next)
-    {
-        if (timer->win != win || timer->msg != msg || timer->id != id) continue;
-        unlink_timer( queue, timer );
-        free( timer );
-        return 1;
-    }
-    return 0;
-}
-
 /* add a timer */
 static struct timer *set_timer( struct msg_queue *queue, unsigned int rate )
 {
     struct timer *timer = mem_alloc( sizeof(*timer) );
     if (timer)
     {
-        timer->rate  = rate;
+        timer->rate  = max( rate, 1 );
         gettimeofday( &timer->when, 0 );
         add_timeout( &timer->when, rate );
         link_timer( queue, timer );
+        /* check if we replaced the next timer */
+        if (list_head( &queue->pending_timers ) == &timer->entry) set_next_timer( queue );
     }
     return timer;
 }
@@ -1219,23 +1226,29 @@ void inc_queue_paint_count( struct thread *thread, int incr )
 void queue_cleanup_window( struct thread *thread, user_handle_t win )
 {
     struct msg_queue *queue = thread->queue;
-    struct timer *timer;
+    struct list *ptr;
     struct message *msg;
     int i;
 
     if (!queue) return;
 
     /* remove timers */
-    timer = queue->first_timer;
-    while (timer)
+
+    ptr = list_head( &queue->pending_timers );
+    while (ptr)
     {
-        struct timer *next = timer->next;
-        if (timer->win == win)
-        {
-            unlink_timer( queue, timer );
-            free( timer );
-        }
-        timer = next;
+        struct list *next = list_next( &queue->pending_timers, ptr );
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
+        if (timer->win == win) free_timer( queue, timer );
+        ptr = next;
+    }
+    ptr = list_head( &queue->expired_timers );
+    while (ptr)
+    {
+        struct list *next = list_next( &queue->expired_timers, ptr );
+        struct timer *timer = LIST_ENTRY( ptr, struct timer, entry );
+        if (timer->win == win) free_timer( queue, timer );
+        ptr = next;
     }
 
     /* remove messages */
@@ -1569,30 +1582,80 @@ DECL_HANDLER(get_message_reply)
 DECL_HANDLER(set_win_timer)
 {
     struct timer *timer;
-    struct msg_queue *queue = get_current_queue();
-    user_handle_t win = get_user_full_handle( req->win );
-
-    if (!queue) return;
+    struct msg_queue *queue;
+    struct thread *thread = NULL;
+    user_handle_t win = 0;
+    unsigned int id = req->id;
 
-    /* remove it if it existed already */
-    if (win) kill_timer( queue, win, req->msg, req->id );
+    if (req->win)
+    {
+        if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win )))
+        {
+            set_error( STATUS_INVALID_HANDLE );
+            return;
+        }
+        if (thread->process != current->process)
+        {
+            release_object( thread );
+            set_error( STATUS_ACCESS_DENIED );
+            return;
+        }
+        queue = thread->queue;
+        /* remove it if it existed already */
+        if ((timer = find_timer( queue, win, req->msg, id ))) free_timer( queue, timer );
+    }
+    else
+    {
+        queue = get_current_queue();
+        /* find a free id for it */
+        do
+        {
+            id = queue->next_timer_id;
+            if (++queue->next_timer_id >= 0x10000) queue->next_timer_id = 1;
+        }
+        while (find_timer( queue, 0, req->msg, id ));
+    }
 
     if ((timer = set_timer( queue, req->rate )))
     {
         timer->win    = win;
         timer->msg    = req->msg;
-        timer->id     = req->id;
+        timer->id     = id;
         timer->lparam = req->lparam;
+        reply->id     = id;
     }
+    if (thread) release_object( thread );
 }
 
 /* kill a window timer */
 DECL_HANDLER(kill_win_timer)
 {
-    struct msg_queue *queue = current->queue;
+    struct timer *timer;
+    struct thread *thread;
+    user_handle_t win = 0;
 
-    if (!queue || !kill_timer( queue, get_user_full_handle(req->win), req->msg, req->id ))
+    if (req->win)
+    {
+        if (!(win = get_user_full_handle( req->win )) || !(thread = get_window_thread( win )))
+        {
+            set_error( STATUS_INVALID_HANDLE );
+            return;
+        }
+        if (thread->process != current->process)
+        {
+            release_object( thread );
+            set_error( STATUS_ACCESS_DENIED );
+            return;
+        }
+    }
+    else thread = (struct thread *)grab_object( current );
+
+    if (thread->queue && (timer = find_timer( thread->queue, win, req->msg, req->id )))
+        free_timer( thread->queue, timer );
+    else
         set_error( STATUS_INVALID_PARAMETER );
+
+    release_object( thread );
 }
 
 
index ac52fcaa23c68b5fada2b16301b63e5be1febfed..99c20f58992a90033958a774f8c485d636e61741 100644 (file)
@@ -1881,6 +1881,11 @@ static void dump_set_win_timer_request( const struct set_win_timer_request *req
     fprintf( stderr, " lparam=%08x", req->lparam );
 }
 
+static void dump_set_win_timer_reply( const struct set_win_timer_reply *req )
+{
+    fprintf( stderr, " id=%08x", req->id );
+}
+
 static void dump_kill_win_timer_request( const struct kill_win_timer_request *req )
 {
     fprintf( stderr, " win=%p,", req->win );
@@ -2851,7 +2856,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_get_message_reply,
     (dump_func)0,
     (dump_func)dump_get_message_reply_reply,
-    (dump_func)0,
+    (dump_func)dump_set_win_timer_reply,
     (dump_func)0,
     (dump_func)dump_get_serial_info_reply,
     (dump_func)0,