From ac4712c326cdda97942befa72a83142e10969697 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Wed, 20 Jun 2018 13:30:45 -0500
Subject: [PATCH 54/83] server: Alter conditions in is_queue_hung(), again.

Complications with SMTO_ABORTIFHUNG lead to implementing this function
exactly correctly.

On Windows, a queue is not hung if you somehow process messages (doesn't
matter how), or if you call MsgWaitForMultipleObjects().

In a sense, Wine had this correct, except not exactly. Firstly, you can call
MsgWait(0, NULL, FALSE, 0, 0); Sleep(1000); in a loop and not be considered
hung; i.e. you don't have to be actively waiting on the queue, but can just
poll it. You also don't have to have a mask that lets in any events--but
just calling WaitForMultipleObjects() isn't enough. On the other hand,
calling MsgWait(0, NULL, FALSE, INFINITE, 0) will result in a hung queue.

last_get_msg should probably be renamed, but nothing better comes to mind.
---
 server/queue.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/server/queue.c b/server/queue.c
index e217a5e6a..16ed7c5d3 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -975,7 +975,7 @@ static void cleanup_results( struct msg_queue *queue )
 /* check if the thread owning the queue is hung (not checking for messages) */
 static int is_queue_hung( struct msg_queue *queue )
 {
-    return is_signaled( queue ) && (current_time - queue->last_get_msg > 5 * TICKS_PER_SEC);
+    return (current_time - queue->last_get_msg > 5 * TICKS_PER_SEC);
 }
 
 static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -991,6 +991,12 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent
     }
     if (process->idle_event && !(queue->wake_mask & QS_SMRESULT)) set_event( process->idle_event );
 
+    /* On Windows, we are considered hung iff we have not somehow processed
+     * messages OR done a MsgWait call in the last 5 seconds. Note that in the
+     * latter case repeatedly waiting for 0 seconds is not hung, but waiting
+     * forever is hung, so this is correct. */
+    queue->last_get_msg = current_time;
+
     if (queue->fd && list_empty( &obj->wait_queue ))  /* first on the queue */
         set_fd_events( queue->fd, POLLIN );
     add_queue( obj, entry );
-- 
2.20.1

