Commit 09029b28 authored by Alexandre Julliard's avatar Alexandre Julliard

Implemented the SMTO_ABORTIFHUNG flag of SendMessageTimeout.

parent 17c69c65
......@@ -69,8 +69,9 @@ ULONG WINAPI RtlNtStatusToDosError( NTSTATUS status )
/* conversion tables */
static const DWORD table_00000103[31] =
static const DWORD table_00000102[32] =
{
ERROR_TIMEOUT, /* 00000102 (STATUS_TIMEOUT) */
ERROR_IO_PENDING, /* 00000103 (STATUS_PENDING) */
ERROR_MR_MID_NOT_FOUND, /* 00000104 */
ERROR_MORE_DATA, /* 00000105 (STATUS_MORE_ENTRIES) */
......@@ -1333,7 +1334,7 @@ static const DWORD table_c0150001[14] =
static const struct error_table error_table[] =
{
{ 0x00000103, 0x00000122, table_00000103 },
{ 0x00000102, 0x00000122, table_00000102 },
{ 0x40000002, 0x4000000e, table_40000002 },
{ 0x40000370, 0x40000371, table_40000370 },
{ 0x40020056, 0x40020057, table_40020056 },
......
......@@ -1663,12 +1663,14 @@ static BOOL put_message_in_queue( DWORD dest_tid, const struct send_message_info
{
req->id = dest_tid;
req->type = info->type;
req->flags = 0;
req->win = info->hwnd;
req->msg = info->msg;
req->wparam = info->wparam;
req->lparam = info->lparam;
req->time = GetCurrentTime();
req->timeout = timeout;
if (info->flags & SMTO_ABORTIFHUNG) req->flags |= SEND_MSG_ABORT_IF_HUNG;
for (i = 0; i < data.count; i++) wine_server_add_data( req, data.data[i], data.size[i] );
if ((res = wine_server_call( req )))
{
......@@ -1720,10 +1722,9 @@ static LRESULT retrieve_reply( const struct send_message_info *info,
info->hwnd, info->msg, SPY_GetMsgName(info->msg, info->hwnd), info->wparam,
info->lparam, *result, status );
if (!status) return 1;
if (status == STATUS_TIMEOUT) SetLastError(0); /* timeout */
else SetLastError( RtlNtStatusToDosError(status) );
return 0;
/* MSDN states that last error is 0 on timeout, but at least NT4 returns ERROR_TIMEOUT */
if (status) SetLastError( RtlNtStatusToDosError(status) );
return !status;
}
......
......@@ -2204,6 +2204,7 @@ struct send_message_request
struct request_header __header;
thread_id_t id;
int type;
int flags;
user_handle_t win;
unsigned int msg;
unsigned int wparam;
......@@ -2230,6 +2231,7 @@ enum message_type
MSG_POSTED,
MSG_HARDWARE
};
#define SEND_MSG_ABORT_IF_HUNG 0x01
......@@ -3620,6 +3622,6 @@ union generic_reply
struct set_clipboard_info_reply set_clipboard_info_reply;
};
#define SERVER_PROTOCOL_VERSION 114
#define SERVER_PROTOCOL_VERSION 115
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
......@@ -1564,6 +1564,7 @@ enum char_info_mode
@REQ(send_message)
thread_id_t id; /* thread id */
int type; /* message type (see below) */
int flags; /* message flags (see below) */
user_handle_t win; /* window handle */
unsigned int msg; /* message code */
unsigned int wparam; /* parameters */
......@@ -1586,6 +1587,7 @@ enum message_type
MSG_POSTED, /* posted message (from PostMessageW), always Unicode */
MSG_HARDWARE /* hardware message */
};
#define SEND_MSG_ABORT_IF_HUNG 0x01
/* Get a message from the current queue */
......
......@@ -125,6 +125,7 @@ struct msg_queue
struct timeout_user *timeout; /* timeout for next timer to expire */
struct thread_input *input; /* thread input descriptor */
struct hook_table *hooks; /* hook table */
struct timeval last_get_msg; /* time of last get message call */
};
static void msg_queue_dump( struct object *obj, int verbose );
......@@ -221,6 +222,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
queue->timeout = NULL;
queue->input = (struct thread_input *)grab_object( input );
queue->hooks = NULL;
gettimeofday( &queue->last_get_msg, NULL );
for (i = 0; i < NB_MSG_KINDS; i++)
queue->msg_list[i].first = queue->msg_list[i].last = NULL;
......@@ -589,6 +591,24 @@ static void cleanup_results( struct msg_queue *queue )
reply_message( queue, 0, STATUS_ACCESS_DENIED /*FIXME*/, 1, NULL, 0 );
}
/* check if the thread owning the queue is hung (not checking for messages) */
static int is_queue_hung( struct msg_queue *queue )
{
struct timeval now;
struct wait_queue_entry *entry;
gettimeofday( &now, NULL );
if (now.tv_sec - queue->last_get_msg.tv_sec <= 5)
return 0; /* less than 5 seconds since last get message -> not hung */
for (entry = queue->obj.head; entry; entry = entry->next)
{
if (entry->thread->queue == queue)
return 0; /* thread is waiting on queue -> not hung */
}
return 1;
}
static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry )
{
struct msg_queue *queue = (struct msg_queue *)obj;
......@@ -1253,6 +1273,12 @@ DECL_HANDLER(send_message)
release_object( thread );
return;
}
if (recv_queue && (req->flags & SEND_MSG_ABORT_IF_HUNG) && is_queue_hung(recv_queue))
{
set_error( STATUS_TIMEOUT );
release_object( thread );
return;
}
if ((msg = mem_alloc( sizeof(*msg) )))
{
......@@ -1326,6 +1352,7 @@ DECL_HANDLER(get_message)
user_handle_t get_win = get_user_full_handle( req->get_win );
if (!queue) return;
gettimeofday( &queue->last_get_msg, NULL );
/* first of all release the hardware input lock if we own it */
/* we'll grab it again if we find a hardware message */
......
......@@ -1834,6 +1834,7 @@ static void dump_send_message_request( const struct send_message_request *req )
{
fprintf( stderr, " id=%04x,", req->id );
fprintf( stderr, " type=%d,", req->type );
fprintf( stderr, " flags=%d,", req->flags );
fprintf( stderr, " win=%p,", req->win );
fprintf( stderr, " msg=%08x,", req->msg );
fprintf( stderr, " wparam=%08x,", req->wparam );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment