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 */
|
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 )
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 * );
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue