Skip to content

Commit 9404d51

Browse files
zfiguraGuy1524
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 #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 ca6b0ae commit 9404d51

File tree

6 files changed

+100
-23
lines changed

6 files changed

+100
-23
lines changed

dlls/ntdll/esync.c

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

832832
/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we
833833
* need to delegate to server_select(). */
834-
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
835-
BOOLEAN alertable, const LARGE_INTEGER *timeout )
834+
static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles,
835+
BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout )
836836
{
837837
static const LARGE_INTEGER zero = {0};
838838

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

896896
if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE)
897897
{
898-
select_op_t select_op;
899-
900898
/* Last object in the list is a queue, which means someone is using
901899
* MsgWaitForMultipleObjects(). We have to wait not only for the server
902900
* fd (signaled on send_message, etc.) but also the USER driver's fd
903901
* (signaled on e.g. X11 events.) */
904902
msgwait = TRUE;
905-
906-
/* We need to let the server know we are doing a message wait, for two
907-
* reasons. First one is WaitForInputIdle(). Second one is checking for
908-
* hung queues. Do it like this. */
909-
select_op.wait.op = SELECT_WAIT;
910-
select_op.wait.handles[0] = wine_server_obj_handle( handles[count - 1] );
911-
ret = server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), 0, &zero );
912-
if (ret != STATUS_WAIT_0 && ret != STATUS_TIMEOUT)
913-
ERR("Unexpected ret %#x\n", ret);
914903
}
915904

916905
if (has_esync && has_server)
@@ -1283,6 +1272,44 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an
12831272
return ret;
12841273
}
12851274

1275+
/* We need to let the server know when we are doing a message wait, and when we
1276+
* are done with one, so that all of the code surrounding hung queues works.
1277+
* We also need this for WaitForInputIdle(). */
1278+
static void server_set_msgwait( int in_msgwait )
1279+
{
1280+
SERVER_START_REQ( esync_msgwait )
1281+
{
1282+
req->in_msgwait = in_msgwait;
1283+
wine_server_call( req );
1284+
}
1285+
SERVER_END_REQ;
1286+
}
1287+
1288+
/* This is a very thin wrapper around the proper implementation above. The
1289+
* purpose is to make sure the server knows when we are doing a message wait.
1290+
* This is separated into a wrapper function since there are at least a dozen
1291+
* exit paths from esync_wait_objects(). */
1292+
NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
1293+
BOOLEAN alertable, const LARGE_INTEGER *timeout )
1294+
{
1295+
BOOL msgwait = FALSE;
1296+
struct esync *obj;
1297+
NTSTATUS ret;
1298+
1299+
if (!get_object( handles[count - 1], &obj ) && obj->type == ESYNC_QUEUE)
1300+
{
1301+
msgwait = TRUE;
1302+
server_set_msgwait( 1 );
1303+
}
1304+
1305+
ret = __esync_wait_objects( count, handles, wait_any, alertable, timeout );
1306+
1307+
if (msgwait)
1308+
server_set_msgwait( 0 );
1309+
1310+
return ret;
1311+
}
1312+
12861313
NTSTATUS esync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable,
12871314
const LARGE_INTEGER *timeout )
12881315
{

include/wine/server_protocol.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6001,6 +6001,17 @@ struct get_esync_apc_fd_reply
60016001
struct reply_header __header;
60026002
};
60036003

6004+
6005+
struct esync_msgwait_request
6006+
{
6007+
struct request_header __header;
6008+
int in_msgwait;
6009+
};
6010+
struct esync_msgwait_reply
6011+
{
6012+
struct reply_header __header;
6013+
};
6014+
60046015
enum esync_type
60056016
{
60066017
ESYNC_SEMAPHORE = 1,
@@ -6325,6 +6336,7 @@ enum request
63256336
REQ_open_esync,
63266337
REQ_get_esync_fd,
63276338
REQ_get_esync_apc_fd,
6339+
REQ_esync_msgwait,
63286340
REQ_NB_REQUESTS
63296341
};
63306342

@@ -6642,6 +6654,7 @@ union generic_request
66426654
struct open_esync_request open_esync_request;
66436655
struct get_esync_fd_request get_esync_fd_request;
66446656
struct get_esync_apc_fd_request get_esync_apc_fd_request;
6657+
struct esync_msgwait_request esync_msgwait_request;
66456658
};
66466659
union generic_reply
66476660
{
@@ -6957,11 +6970,12 @@ union generic_reply
69576970
struct open_esync_reply open_esync_reply;
69586971
struct get_esync_fd_reply get_esync_fd_reply;
69596972
struct get_esync_apc_fd_reply get_esync_apc_fd_reply;
6973+
struct esync_msgwait_reply esync_msgwait_reply;
69606974
};
69616975

69626976
/* ### protocol_version begin ### */
69636977

6964-
#define SERVER_PROTOCOL_VERSION 626
6978+
#define SERVER_PROTOCOL_VERSION 627
69656979

69666980
/* ### protocol_version end ### */
69676981

server/protocol.def

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

40784078
/* Retrieve the fd to wait on for user APCs. */
40794079
@REQ(get_esync_apc_fd)
4080-
@REPLY
4080+
@END
4081+
4082+
/* Notify the server that we are doing a message wait (or done with one). */
4083+
@REQ(esync_msgwait)
4084+
int in_msgwait; /* are we in a message wait? */
40814085
@END
40824086

40834087
enum esync_type

server/queue.c

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ struct msg_queue
126126
struct thread *thread; /* reference to the thread owning the queue */
127127
struct fd *fd; /* optional file descriptor to poll */
128128
int esync_fd; /* esync file descriptor (signalled on message) */
129+
int esync_in_msgwait; /* our thread is currently waiting on us */
129130
unsigned int wake_bits; /* wakeup bits */
130131
unsigned int wake_mask; /* wakeup mask */
131132
unsigned int changed_bits; /* changed wakeup bits */
@@ -996,7 +997,21 @@ static void cleanup_results( struct msg_queue *queue )
996997
/* check if the thread owning the queue is hung (not checking for messages) */
997998
static int is_queue_hung( struct msg_queue *queue )
998999
{
999-
return (current_time - queue->last_get_msg > 5 * TICKS_PER_SEC);
1000+
struct wait_queue_entry *entry;
1001+
1002+
if (current_time - queue->last_get_msg <= 5 * TICKS_PER_SEC)
1003+
return 0; /* less than 5 seconds since last get message -> not hung */
1004+
1005+
LIST_FOR_EACH_ENTRY( entry, &queue->obj.wait_queue, struct wait_queue_entry, entry )
1006+
{
1007+
if (get_wait_queue_thread(entry)->queue == queue)
1008+
return 0; /* thread is waiting on queue -> not hung */
1009+
}
1010+
1011+
if (do_esync() && queue->esync_in_msgwait)
1012+
return 0; /* thread is waiting on queue in absentia -> not hung */
1013+
1014+
return 1;
10001015
}
10011016

10021017
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
@@ -1012,12 +1027,6 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent
10121027
}
10131028
if (process->idle_event && !(queue->wake_mask & QS_SMRESULT)) set_event( process->idle_event );
10141029

1015-
/* On Windows, we are considered hung iff we have not somehow processed
1016-
* messages OR done a MsgWait call in the last 5 seconds. Note that in the
1017-
* latter case repeatedly waiting for 0 seconds is not hung, but waiting
1018-
* forever is hung, so this is correct. */
1019-
queue->last_get_msg = current_time;
1020-
10211030
if (queue->fd && list_empty( &obj->wait_queue )) /* first on the queue */
10221031
set_fd_events( queue->fd, POLLIN );
10231032
add_queue( obj, entry );
@@ -1728,6 +1737,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
17281737

17291738
if (!(hook_thread = get_first_global_hook( id ))) return 0;
17301739
if (!(queue = hook_thread->queue)) return 0;
1740+
if (is_queue_hung( queue )) return 0;
17311741

17321742
if (!(msg = mem_alloc( sizeof(*msg) ))) return 0;
17331743

@@ -3432,3 +3442,14 @@ DECL_HANDLER(get_rawinput_devices)
34323442

34333443
set_reply_data_ptr( devices, device_count * sizeof (*devices) );
34343444
}
3445+
3446+
DECL_HANDLER(esync_msgwait)
3447+
{
3448+
struct msg_queue *queue = get_current_queue();
3449+
3450+
if (!queue) return;
3451+
queue->esync_in_msgwait = req->in_msgwait;
3452+
3453+
if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT))
3454+
set_event( current->process->idle_event );
3455+
}

server/request.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ DECL_HANDLER(create_esync);
423423
DECL_HANDLER(open_esync);
424424
DECL_HANDLER(get_esync_fd);
425425
DECL_HANDLER(get_esync_apc_fd);
426+
DECL_HANDLER(esync_msgwait);
426427

427428
#ifdef WANT_REQUEST_HANDLERS
428429

@@ -739,6 +740,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
739740
(req_handler)req_open_esync,
740741
(req_handler)req_get_esync_fd,
741742
(req_handler)req_get_esync_apc_fd,
743+
(req_handler)req_esync_msgwait,
742744
};
743745

744746
C_ASSERT( sizeof(affinity_t) == 8 );
@@ -2534,7 +2536,8 @@ C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, type) == 8 );
25342536
C_ASSERT( FIELD_OFFSET(struct get_esync_fd_reply, shm_idx) == 12 );
25352537
C_ASSERT( sizeof(struct get_esync_fd_reply) == 16 );
25362538
C_ASSERT( sizeof(struct get_esync_apc_fd_request) == 16 );
2537-
C_ASSERT( sizeof(struct get_esync_apc_fd_reply) == 8 );
2539+
C_ASSERT( FIELD_OFFSET(struct esync_msgwait_request, in_msgwait) == 12 );
2540+
C_ASSERT( sizeof(struct esync_msgwait_request) == 16 );
25382541

25392542
#endif /* WANT_REQUEST_HANDLERS */
25402543

server/trace.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,6 +4741,11 @@ static void dump_get_esync_apc_fd_request( const struct get_esync_apc_fd_request
47414741
{
47424742
}
47434743

4744+
static void dump_esync_msgwait_request( const struct esync_msgwait_request *req )
4745+
{
4746+
fprintf( stderr, " in_msgwait=%d", req->in_msgwait );
4747+
}
4748+
47444749
static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
47454750
(dump_func)dump_new_process_request,
47464751
(dump_func)dump_exec_process_request,
@@ -5052,6 +5057,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
50525057
(dump_func)dump_open_esync_request,
50535058
(dump_func)dump_get_esync_fd_request,
50545059
(dump_func)dump_get_esync_apc_fd_request,
5060+
(dump_func)dump_esync_msgwait_request,
50555061
};
50565062

50575063
static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -5365,6 +5371,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
53655371
(dump_func)dump_open_esync_reply,
53665372
(dump_func)dump_get_esync_fd_reply,
53675373
NULL,
5374+
NULL,
53685375
};
53695376

53705377
static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -5678,6 +5685,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
56785685
"open_esync",
56795686
"get_esync_fd",
56805687
"get_esync_apc_fd",
5688+
"esync_msgwait",
56815689
};
56825690

56835691
static const struct

0 commit comments

Comments
 (0)