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