[PATCH v2 3/3] winhttp: Use default thread pool.

Paul Gofman pgofman at codeweavers.com
Tue Mar 15 11:07:25 CDT 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
     v2:
          - no changes.

 dlls/winhttp/request.c         | 86 +++++++++++++++++++++++-----------
 dlls/winhttp/session.c         |  1 +
 dlls/winhttp/winhttp_private.h |  7 ++-
 3 files changed, 64 insertions(+), 30 deletions(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index a825ac71d33..fe703c19109 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -122,54 +122,82 @@ static const WCHAR *attribute_table[] =
     NULL                            /* WINHTTP_QUERY_PASSPORT_CONFIG            = 78 */
 };
 
-static DWORD start_queue( struct queue *queue )
+void init_queue( struct queue *queue )
 {
-    if (queue->pool) return ERROR_SUCCESS;
-
-    if (!(queue->pool = CreateThreadpool( NULL ))) return GetLastError();
-    SetThreadpoolThreadMinimum( queue->pool, 1 );
-    SetThreadpoolThreadMaximum( queue->pool, 1 );
-
-    memset( &queue->env, 0, sizeof(queue->env) );
-    queue->env.Version = 1;
-    queue->env.Pool = queue->pool;
-
-    TRACE("started %p\n", queue);
-    return ERROR_SUCCESS;
+    InitializeSRWLock( &queue->lock );
+    list_init( &queue->queued_tasks );
+    queue->callback_running = FALSE;
 }
 
 void stop_queue( struct queue *queue )
 {
-    if (!queue->pool) return;
-    CloseThreadpool( queue->pool );
-    queue->pool = NULL;
+    assert( list_empty( &queue->queued_tasks ));
     TRACE("stopped %p\n", queue);
 }
 
-static void CALLBACK task_callback( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static struct task_header *get_next_task( struct queue *queue )
 {
-    struct task_header *task_hdr = ctx;
+    struct list *entry;
 
-    task_hdr->callback( task_hdr );
-    release_object( task_hdr->obj );
-    free( task_hdr );
+    AcquireSRWLockExclusive( &queue->lock );
+    assert( queue->callback_running );
+    if ((entry = list_head( &queue->queued_tasks )))
+        list_remove( entry );
+    else
+        queue->callback_running = FALSE;
+    ReleaseSRWLockExclusive( &queue->lock );
+    if (!entry) return NULL;
+    return LIST_ENTRY( entry, struct task_header, entry );
+}
+
+static void CALLBACK task_callback( TP_CALLBACK_INSTANCE *instance, void *ctx )
+{
+    struct task_header *task, *next_task;
+    struct queue *queue = ctx;
+
+    TRACE( "instance %p.\n", instance );
+
+    task = get_next_task( queue );
+    while (task)
+    {
+        task->callback( task );
+        /* Queue object may be freed by release_object() unless there is another task referencing it. */
+        next_task = get_next_task( queue );
+        release_object( task->obj );
+        free( task );
+        task = next_task;
+    }
+    TRACE( "instance %p exiting.\n", instance );
 }
 
 static DWORD queue_task( struct queue *queue, TASK_CALLBACK task, struct task_header *task_hdr,
                          struct object_header *obj )
 {
-    TP_WORK *work;
-    DWORD ret;
-
-    if ((ret = start_queue( queue ))) return ret;
+    BOOL callback_running;
 
-    if (!(work = CreateThreadpoolWork( task_callback, task_hdr, &queue->env ))) return GetLastError();
     TRACE("queueing %p in %p\n", task_hdr, queue);
     task_hdr->callback = task;
     task_hdr->obj = obj;
     addref_object( obj );
-    SubmitThreadpoolWork( work );
-    CloseThreadpoolWork( work );
+
+    AcquireSRWLockExclusive( &queue->lock );
+    list_add_tail( &queue->queued_tasks, &task_hdr->entry );
+    if (!(callback_running = queue->callback_running))
+    {
+        if ((queue->callback_running = TrySubmitThreadpoolCallback( task_callback, queue, NULL )))
+            callback_running = TRUE;
+        else
+            list_remove( &task_hdr->entry );
+    }
+    ReleaseSRWLockExclusive( &queue->lock );
+
+    if (!callback_running)
+    {
+        release_object( obj );
+        free( task_hdr );
+        ERR( "Submiting threadpool callback failed, err %lu.\n", GetLastError() );
+        return ERROR_OUTOFMEMORY;
+    }
 
     return ERROR_SUCCESS;
 }
@@ -3096,6 +3124,8 @@ HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR
     socket->hdr.notify_mask = request->hdr.notify_mask;
     socket->hdr.context = context;
     InitializeSRWLock( &socket->send_lock );
+    init_queue( &socket->send_q );
+    init_queue( &socket->recv_q );
 
     addref_object( &request->hdr );
     socket->request = request;
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index 7c55adb8475..3b00d2448d1 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -1160,6 +1160,7 @@ HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, cons
     request->hdr.notify_mask = connect->hdr.notify_mask;
     request->hdr.context = connect->hdr.context;
     request->hdr.redirect_policy = connect->hdr.redirect_policy;
+    init_queue( &request->queue );
 
     addref_object( &connect->hdr );
     request->connect = connect;
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 35f3e64b5a3..4754d9258d1 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -159,8 +159,9 @@ struct authinfo
 
 struct queue
 {
-    TP_POOL *pool;
-    TP_CALLBACK_ENVIRON env;
+    SRWLOCK lock;
+    struct list queued_tasks;
+    BOOL callback_running;
 };
 
 enum request_flags
@@ -277,6 +278,7 @@ typedef void (*TASK_CALLBACK)( void *ctx );
 
 struct task_header
 {
+    struct list entry;
     TASK_CALLBACK callback;
     struct object_header *obj;
 };
@@ -355,6 +357,7 @@ BOOL free_handle( HINTERNET ) DECLSPEC_HIDDEN;
 
 void send_callback( struct object_header *, DWORD, LPVOID, DWORD ) DECLSPEC_HIDDEN;
 void close_connection( struct request * ) DECLSPEC_HIDDEN;
+void init_queue( struct queue *queue ) DECLSPEC_HIDDEN;
 void stop_queue( struct queue * ) DECLSPEC_HIDDEN;
 
 void netconn_close( struct netconn * ) DECLSPEC_HIDDEN;
-- 
2.35.1




More information about the wine-devel mailing list