winhttp: Implement a task queue for asynchronous requests.

This ensures that asynchronous calls are completed in the right order.
This commit is contained in:
Hans Leidekker 2015-02-16 14:40:38 +01:00 committed by Alexandre Julliard
parent 8c158c1e33
commit d6c9c984e5
3 changed files with 96 additions and 10 deletions

View File

@ -178,20 +178,87 @@ static const WCHAR *attribute_table[] =
NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */ NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */
}; };
static DWORD CALLBACK task_thread( LPVOID param ) static task_header_t *dequeue_task( request_t *request )
{ {
task_header_t *task = param; task_header_t *task;
task->proc( task ); EnterCriticalSection( &request->task_cs );
TRACE("%u tasks queued\n", list_count( &request->task_queue ));
task = LIST_ENTRY( list_head( &request->task_queue ), task_header_t, entry );
if (task) list_remove( &task->entry );
LeaveCriticalSection( &request->task_cs );
release_object( &task->request->hdr ); TRACE("returning task %p\n", task);
heap_free( task ); return task;
return ERROR_SUCCESS; }
static DWORD CALLBACK task_proc( LPVOID param )
{
request_t *request = param;
HANDLE handles[2];
handles[0] = request->task_wait;
handles[1] = request->task_cancel;
for (;;)
{
DWORD err = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
switch (err)
{
case WAIT_OBJECT_0:
{
task_header_t *task;
while ((task = dequeue_task( request )))
{
task->proc( task );
release_object( &task->request->hdr );
heap_free( task );
}
break;
}
case WAIT_OBJECT_0 + 1:
TRACE("exiting\n");
return 0;
default:
ERR("wait failed %u (%u)\n", err, GetLastError());
break;
}
}
return 0;
} }
static BOOL queue_task( task_header_t *task ) static BOOL queue_task( task_header_t *task )
{ {
return QueueUserWorkItem( task_thread, task, WT_EXECUTELONGFUNCTION ); request_t *request = task->request;
if (!request->task_thread)
{
if (!(request->task_wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE;
if (!(request->task_cancel = CreateEventW( NULL, FALSE, FALSE, NULL )))
{
CloseHandle( request->task_wait );
request->task_wait = NULL;
return FALSE;
}
if (!(request->task_thread = CreateThread( NULL, 0, task_proc, request, 0, NULL )))
{
CloseHandle( request->task_wait );
request->task_wait = NULL;
CloseHandle( request->task_cancel );
request->task_cancel = NULL;
return FALSE;
}
InitializeCriticalSection( &request->task_cs );
request->task_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": request.task_cs");
}
EnterCriticalSection( &request->task_cs );
TRACE("queueing task %p\n", task );
list_add_tail( &request->task_queue, &task->entry );
LeaveCriticalSection( &request->task_cs );
SetEvent( request->task_wait );
return TRUE;
} }
static void free_header( header_t *header ) static void free_header( header_t *header )

View File

@ -70,9 +70,12 @@ DWORD get_last_error( void )
void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen ) void send_callback( object_header_t *hdr, DWORD status, LPVOID info, DWORD buflen )
{ {
TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen); if (hdr->callback && (hdr->notify_mask & status))
{
if (hdr->callback && (hdr->notify_mask & status)) hdr->callback( hdr->handle, hdr->context, status, info, buflen ); TRACE("%p, 0x%08x, %p, %u\n", hdr, status, info, buflen);
hdr->callback( hdr->handle, hdr->context, status, info, buflen );
TRACE("returning from 0x%08x callback\n", status);
}
} }
/*********************************************************************** /***********************************************************************
@ -556,6 +559,15 @@ static void request_destroy( object_header_t *hdr )
TRACE("%p\n", request); TRACE("%p\n", request);
if (request->task_thread)
{
SetEvent( request->task_cancel );
WaitForSingleObject( request->task_thread, INFINITE );
CloseHandle( request->task_thread );
CloseHandle( request->task_cancel );
CloseHandle( request->task_wait );
DeleteCriticalSection( &request->task_cs );
}
release_object( &request->connect->hdr ); release_object( &request->connect->hdr );
destroy_authinfo( request->authinfo ); destroy_authinfo( request->authinfo );
@ -1057,6 +1069,7 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, LPCWSTR verb, LPCWSTR o
request->hdr.context = connect->hdr.context; request->hdr.context = connect->hdr.context;
request->hdr.redirect_policy = connect->hdr.redirect_policy; request->hdr.redirect_policy = connect->hdr.redirect_policy;
list_init( &request->hdr.children ); list_init( &request->hdr.children );
list_init( &request->task_queue );
addref_object( &connect->hdr ); addref_object( &connect->hdr );
request->connect = connect; request->connect = connect;

View File

@ -201,12 +201,18 @@ typedef struct
DWORD num_accept_types; DWORD num_accept_types;
struct authinfo *authinfo; struct authinfo *authinfo;
struct authinfo *proxy_authinfo; struct authinfo *proxy_authinfo;
HANDLE task_wait;
HANDLE task_cancel;
HANDLE task_thread;
struct list task_queue;
CRITICAL_SECTION task_cs;
} request_t; } request_t;
typedef struct _task_header_t task_header_t; typedef struct _task_header_t task_header_t;
struct _task_header_t struct _task_header_t
{ {
struct list entry;
request_t *request; request_t *request;
void (*proc)( task_header_t * ); void (*proc)( task_header_t * );
}; };