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 */
};
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 );
heap_free( task );
return ERROR_SUCCESS;
TRACE("returning task %p\n", task);
return task;
}
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 )
{
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 )

View File

@ -70,9 +70,12 @@ DWORD get_last_error( void )
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)) hdr->callback( hdr->handle, hdr->context, status, info, buflen );
if (hdr->callback && (hdr->notify_mask & status))
{
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);
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 );
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.redirect_policy = connect->hdr.redirect_policy;
list_init( &request->hdr.children );
list_init( &request->task_queue );
addref_object( &connect->hdr );
request->connect = connect;

View File

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