Commit aac09982 authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

server: Check if we have waiting asyncs in (send_socket) before enforcing blocking send.

parent 294efcdf
......@@ -3106,6 +3106,29 @@ static test_setup tests [] =
}
};
struct send_udp_thread_param
{
int sock;
HANDLE start_event;
};
static DWORD WINAPI send_udp_thread( void *param )
{
struct send_udp_thread_param *p = param;
static char buf[256];
unsigned int i;
int ret;
WaitForSingleObject( p->start_event, INFINITE );
for (i = 0; i < 256; ++i)
{
ret = send( p->sock, buf, sizeof(buf), 0 );
ok( ret == sizeof(buf), "got %d, error %u, i %u.\n", ret, WSAGetLastError(), i );
}
return 0;
}
static void test_UDP(void)
{
/* This function tests UDP sendto() and recvfrom(). UDP is unreliable, so it is
......@@ -3117,6 +3140,9 @@ static void test_UDP(void)
int ss, i, n_recv, n_sent, ret;
struct sockaddr_in addr;
int sock;
struct send_udp_thread_param udp_thread_param;
HANDLE thread;
memset (buf,0,sizeof(buf));
for ( i = NUM_UDP_PEERS - 1; i >= 0; i-- ) {
......@@ -3174,6 +3200,22 @@ static void test_UDP(void)
ok( ret == sizeof(buf), "got %d, error %u.\n", ret, WSAGetLastError() );
}
/* Test sending packets in parallel (mostly a regression test for Wine async handling race conditions). */
set_blocking( sock, FALSE );
udp_thread_param.sock = sock;
udp_thread_param.start_event = CreateEventW( NULL, FALSE, FALSE, NULL );
thread = CreateThread( NULL, 0, send_udp_thread, &udp_thread_param, 0, NULL );
SetEvent( udp_thread_param.start_event );
for (i = 0; i < 256; ++i)
{
ret = send( sock, buf, sizeof(buf), 0 );
ok( ret == sizeof(buf), "got %d, error %u, i %u.\n", ret, WSAGetLastError(), i );
}
WaitForSingleObject( thread, INFINITE );
CloseHandle( thread );
CloseHandle( udp_thread_param.start_event );
closesocket(sock);
}
......
......@@ -551,6 +551,16 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
}
}
int async_queue_has_waiting_asyncs( struct async_queue *queue )
{
struct async *async;
LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry )
if (!async->unknown_status) return 1;
return 0;
}
/* check if an async operation is waiting to be alerted */
int async_waiting( struct async_queue *queue )
{
......
......@@ -237,6 +237,7 @@ extern void set_async_pending( struct async *async );
extern void async_set_initial_status( struct async *async, unsigned int status );
extern void async_wake_obj( struct async *async );
extern int async_waiting( struct async_queue *queue );
extern int async_queue_has_waiting_asyncs( struct async_queue *queue );
extern void async_terminate( struct async *async, unsigned int status );
extern void async_request_complete( struct async *async, unsigned int status, data_size_t result,
data_size_t out_size, void *out_data );
......
......@@ -3945,7 +3945,7 @@ DECL_HANDLER(send_socket)
if (bind_errno) status = sock_get_ntstatus( bind_errno );
else if (sock->wr_shutdown) status = STATUS_PIPE_DISCONNECTED;
else if (!async_queued( &sock->write_q ))
else if (!async_queue_has_waiting_asyncs( &sock->write_q ))
{
/* If write_q is not empty, we cannot really tell if the already queued
* asyncs will not consume all available space; if there's no space
......
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