winhttp: Implement a task queue for asynchronous requests.
This ensures that asynchronous calls are completed in the right order.
This commit is contained in:
parent
8c158c1e33
commit
d6c9c984e5
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 * );
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue