Skip to content

Commit 862c85c

Browse files
zfigurakakra
authored andcommitted
ntdll, server: Revert to old implementation of hung queue detection.
By manually notifying the server every time we enter and exit a message wait. The hung queue logic keeps breaking. In the case of bug wine-mirror#9 it was breaking because we were waiting for more than 5 seconds on our queue and then someone sent us a message with SMTO_ABORTIFHUNG. Just stop fighting against the server and try to coöperate with it instead. It takes two extra server calls, but ideally the GUI thread isn't going to be in the same sort of performance- critical code that this patchset was written for.
1 parent 9a4ac43 commit 862c85c

File tree

6 files changed

+101
-23
lines changed

6 files changed

+101
-23
lines changed

dlls/ntdll/esync.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -812,8 +812,8 @@ static void update_grabbed_object( struct esync *obj )
812812

813813
/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
814814
* need to delegate to server_select(). */
815-
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
816-
BOOLEAN alertable, const LARGE_INTEGER *timeout )
815+
static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles,
816+
BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout )
817817
{
818818
static const LARGE_INTEGER zero = {0};
819819

@@ -876,22 +876,11 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
876876

877877
if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE)
878878
{
879-
select_op_t select_op;
880-
881879
/* Last object in the list is a queue, which means someone is using
882880
* MsgWaitForMultipleObjects(). We have to wait not only for the server
883881
* fd (signaled on send_message, etc.) but also the USER driver's fd
884882
* (signaled on e.g. X11 events.) */
885883
msgwait = TRUE;
886-
887-
/* We need to let the server know we are doing a message wait, for two
888-
* reasons. First one is WaitForInputIdle(). Second one is checking for
889-
* hung queues. Do it like this. */
890-
select_op.wait.op = SELECT_WAIT;
891-
select_op.wait.handles[0] = wine_server_obj_handle( handles[count - 1] );
892-
ret = server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &zero );
893-
if (ret != STATUS_WAIT_0 && ret != STATUS_TIMEOUT)
894-
ERR("Unexpected ret %#x\n", ret);
895884
}
896885

897886
if (has_esync && has_server)
@@ -1263,6 +1252,44 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
12631252
return ret;
12641253
}
12651254

1255+
/* We need to let the server know when we are doing a message wait, and when we
1256+
* are done with one, so that all of the code surrounding hung queues works.
1257+
* We also need this for WaitForInputIdle(). */
1258+
static void server_set_msgwait( int in_msgwait )
1259+
{
1260+
SERVER_START_REQ( esync_msgwait )
1261+
{
1262+
req->in_msgwait = in_msgwait;
1263+
wine_server_call( req );
1264+
}
1265+
SERVER_END_REQ;
1266+
}
1267+
1268+
/* This is a very thin wrapper around the proper implementation above. The
1269+
* purpose is to make sure the server knows when we are doing a message wait.
1270+
* This is separated into a wrapper function since there are at least a dozen
1271+
* exit paths from esync_wait_objects(). */
1272+
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
1273+
BOOLEAN alertable, const LARGE_INTEGER *timeout )
1274+
{
1275+
BOOL msgwait = FALSE;
1276+
struct esync *obj;
1277+
NTSTATUS ret;
1278+
1279+
if (!get_object( handles[count - 1], &obj ) && obj->type == ESYNC_QUEUE)
1280+
{
1281+
msgwait = TRUE;
1282+
server_set_msgwait( 1 );
1283+
}
1284+
1285+
ret = __esync_wait_objects( count, handles, wait_any, alertable, timeout );
1286+
1287+
if (msgwait)
1288+
server_set_msgwait( 0 );
1289+
1290+
return ret;
1291+
}
1292+
12661293
NTSTATUS esync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable,
12671294
const LARGE_INTEGER *timeout )
12681295
{

include/wine/server_protocol.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5710,6 +5710,17 @@ struct get_esync_apc_fd_reply
57105710
struct reply_header __header;
57115711
};
57125712

5713+
5714+
struct esync_msgwait_request
5715+
{
5716+
struct request_header __header;
5717+
int in_msgwait;
5718+
};
5719+
struct esync_msgwait_reply
5720+
{
5721+
struct reply_header __header;
5722+
};
5723+
57135724
enum esync_type
57145725
{
57155726
ESYNC_SEMAPHORE = 1,
@@ -6018,6 +6029,7 @@ enum request
60186029
REQ_open_esync,
60196030
REQ_get_esync_fd,
60206031
REQ_get_esync_apc_fd,
6032+
REQ_esync_msgwait,
60216033
REQ_NB_REQUESTS
60226034
};
60236035

@@ -6319,6 +6331,7 @@ union generic_request
63196331
struct open_esync_request open_esync_request;
63206332
struct get_esync_fd_request get_esync_fd_request;
63216333
struct get_esync_apc_fd_request get_esync_apc_fd_request;
6334+
struct esync_msgwait_request esync_msgwait_request;
63226335
};
63236336
union generic_reply
63246337
{
@@ -6618,8 +6631,9 @@ union generic_reply
66186631
struct open_esync_reply open_esync_reply;
66196632
struct get_esync_fd_reply get_esync_fd_reply;
66206633
struct get_esync_apc_fd_reply get_esync_apc_fd_reply;
6634+
struct esync_msgwait_reply esync_msgwait_reply;
66216635
};
66226636

6623-
#define SERVER_PROTOCOL_VERSION 566
6637+
#define SERVER_PROTOCOL_VERSION 567
66246638

66256639
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

server/protocol.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3888,7 +3888,11 @@ struct handle_info
38883888

38893889
/* Retrieve the fd to wait on for user APCs. */
38903890
@REQ(get_esync_apc_fd)
3891-
@REPLY
3891+
@END
3892+
3893+
/* Notify the server that we are doing a message wait (or done with one). */
3894+
@REQ(esync_msgwait)
3895+
int in_msgwait; /* are we in a message wait? */
38923896
@END
38933897

38943898
enum esync_type

server/queue.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ struct msg_queue
142142
struct hook_table *hooks; /* hook table */
143143
timeout_t last_get_msg; /* time of last get message call */
144144
int esync_fd; /* esync file descriptor (signalled on message) */
145+
int esync_in_msgwait; /* our thread is currently waiting on us */
145146
};
146147

147148
struct hotkey
@@ -899,7 +900,21 @@ static void cleanup_results( struct msg_queue *queue )
899900
/* check if the thread owning the queue is hung (not checking for messages) */
900901
static int is_queue_hung( struct msg_queue *queue )
901902
{
902-
return (current_time - queue->last_get_msg > 5 * TICKS_PER_SEC);
903+
struct wait_queue_entry *entry;
904+
905+
if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC)
906+
return 0; /* less than 5 seconds since last get message -> not hung */
907+
908+
LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
909+
{
910+
if (get_wait_queue_thread(entry)->queue == queue)
911+
return 0; /* thread is waiting on queue -> not hung */
912+
}
913+
914+
if (do_esync() && queue->esync_in_msgwait)
915+
return 0; /* thread is waiting on queue in absentia -> not hung */
916+
917+
return 1;
903918
}
904919

905920
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -915,12 +930,6 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent
915930
}
916931
if (process->idle_event && !(queue->wake_mask & QS_SMRESULT)) set_event( process->idle_event );
917932

918-
/* On Windows, we are considered hung iff we have not somehow processed
919-
* messages OR done a MsgWait call in the last 5 seconds. Note that in the
920-
* latter case repeatedly waiting for 0 seconds is not hung, but waiting
921-
* forever is hung, so this is correct. */
922-
queue->last_get_msg = current_time;
923-
924933
if (queue->fd && list_empty( &obj->wait_queue )) /* first on the queue */
925934
set_fd_events( queue->fd, POLLIN );
926935
add_queue( obj, entry );
@@ -1566,6 +1575,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
15661575

15671576
if (!(hook_thread = get_first_global_hook( id ))) return 0;
15681577
if (!(queue = hook_thread->queue)) return 0;
1578+
if (is_queue_hung( queue )) return 0;
15691579

15701580
if (!(msg = mem_alloc( sizeof(*msg) ))) return 0;
15711581

@@ -3181,3 +3191,14 @@ DECL_HANDLER(update_rawinput_devices)
31813191
e = find_rawinput_device( 1, 6 );
31823192
current->process->rawinput_kbd = e ? &e->device : NULL;
31833193
}
3194+
3195+
DECL_HANDLER(esync_msgwait)
3196+
{
3197+
struct msg_queue *queue = get_current_queue();
3198+
3199+
if (!queue) return;
3200+
queue->esync_in_msgwait = req->in_msgwait;
3201+
3202+
if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT))
3203+
set_event( current->process->idle_event );
3204+
}

server/request.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ DECL_HANDLER(create_esync);
406406
DECL_HANDLER(open_esync);
407407
DECL_HANDLER(get_esync_fd);
408408
DECL_HANDLER(get_esync_apc_fd);
409+
DECL_HANDLER(esync_msgwait);
409410

410411
#ifdef WANT_REQUEST_HANDLERS
411412

@@ -706,6 +707,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
706707
(req_handler)req_open_esync,
707708
(req_handler)req_get_esync_fd,
708709
(req_handler)req_get_esync_apc_fd,
710+
(req_handler)req_esync_msgwait,
709711
};
710712

711713
C_ASSERT( sizeof(affinity_t) == 8 );
@@ -2440,7 +2442,8 @@ C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, type) == 8 );
24402442
C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, shm_idx) == 12 );
24412443
C_ASSERT( sizeof(struct get_esync_fd_reply) == 16 );
24422444
C_ASSERT( sizeof(struct get_esync_apc_fd_request) == 16 );
2443-
C_ASSERT( sizeof(struct get_esync_apc_fd_reply) == 8 );
2445+
C_ASSERT( FIELD_OFFSET(struct esync_msgwait_request, in_msgwait) == 12 );
2446+
C_ASSERT( sizeof(struct esync_msgwait_request) == 16 );
24442447

24452448
#endif /* WANT_REQUEST_HANDLERS */
24462449

server/trace.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4589,6 +4589,11 @@ static void dump_get_esync_apc_fd_request( const struct get_esync_apc_fd_request
45894589
{
45904590
}
45914591

4592+
static void dump_esync_msgwait_request( const struct esync_msgwait_request *req )
4593+
{
4594+
fprintf( stderr, " in_msgwait=%d", req->in_msgwait );
4595+
}
4596+
45924597
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
45934598
(dump_func)dump_new_process_request,
45944599
(dump_func)dump_get_new_process_info_request,
@@ -4884,6 +4889,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
48844889
(dump_func)dump_open_esync_request,
48854890
(dump_func)dump_get_esync_fd_request,
48864891
(dump_func)dump_get_esync_apc_fd_request,
4892+
(dump_func)dump_esync_msgwait_request,
48874893
};
48884894

48894895
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -5181,6 +5187,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
51815187
(dump_func)dump_open_esync_reply,
51825188
(dump_func)dump_get_esync_fd_reply,
51835189
NULL,
5190+
NULL,
51845191
};
51855192

51865193
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -5478,6 +5485,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
54785485
"open_esync",
54795486
"get_esync_fd",
54805487
"get_esync_apc_fd",
5488+
"esync_msgwait",
54815489
};
54825490

54835491
static const struct
@@ -5546,6 +5554,7 @@ static const struct
55465554
{ "INVALID_OWNER", STATUS_INVALID_OWNER },
55475555
{ "INVALID_PARAMETER", STATUS_INVALID_PARAMETER },
55485556
{ "INVALID_PIPE_STATE", STATUS_INVALID_PIPE_STATE },
5557+
{ "INVALID_PARAMETER_4", STATUS_INVALID_PARAMETER_4 },
55495558
{ "INVALID_READ_MODE", STATUS_INVALID_READ_MODE },
55505559
{ "INVALID_SECURITY_DESCR", STATUS_INVALID_SECURITY_DESCR },
55515560
{ "IO_TIMEOUT", STATUS_IO_TIMEOUT },

0 commit comments

Comments
 (0)