Hans Leidekker : winhttp: Implement a task queue for asynchronous requests.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Feb 16 10:01:21 CST 2015
Module: wine
Branch: master
Commit: d6c9c984e5c2c30fe7b37e21465ec71a1ad8c3de
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d6c9c984e5c2c30fe7b37e21465ec71a1ad8c3de
Author: Hans Leidekker <hans at codeweavers.com>
Date: Mon Feb 16 14:40:38 2015 +0100
winhttp: Implement a task queue for asynchronous requests.
This ensures that asynchronous calls are completed in the right order.
---
dlls/winhttp/request.c | 81 ++++++++++++++++++++++++++++++++++++++----
dlls/winhttp/session.c | 19 ++++++++--
dlls/winhttp/winhttp_private.h | 6 ++++
3 files changed, 96 insertions(+), 10 deletions(-)
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index dc13fd0..2932108 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -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 )
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index 56e776d..0eca509 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -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;
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 51043fd..4c567ed 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -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 * );
};
More information about the wine-cvs
mailing list