[PATCH 1/3] winhttp: Use a single thread pool wrapper callback for async tasks.

Paul Gofman pgofman at codeweavers.com
Mon Mar 14 12:04:01 CDT 2022


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
     The primary motivation under this patchset is to avoid leaking threads when an application is
     leaking winhttp handles by using default thread pool (like Monster Hunter Rise which was failing
     due to consequences of that).

     Also, preparatory patches 1-2 remove some code duplication around referencing and releasing
     queued task related objects.

     As a separate note, we are probably not doing quite the right thing on closing request and socket handle (as
     far as my brief testing of that shows (at least with websocket handle) it is probably supposed to behave
     somewhat similar to WinHttpWebSocketClose(): abort the queued operation and send cancel status immediately.
     If we need to fix that in the future it is probably a bit easier to do with the handle's object reference
     being managed in a single place.
     

 dlls/winhttp/request.c         | 74 +++++++++++++++++++---------------
 dlls/winhttp/winhttp_private.h | 15 +++++++
 2 files changed, 56 insertions(+), 33 deletions(-)

diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index b409c4cdced..36a3bb909b9 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -146,15 +146,23 @@ void stop_queue( struct queue *queue )
     TRACE("stopped %p\n", queue);
 }
 
-static DWORD queue_task( struct queue *queue, PTP_WORK_CALLBACK task, void *ctx )
+static void CALLBACK task_callback( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+{
+    struct task_header *task_hdr = ctx;
+
+    task_hdr->callback( task_hdr );
+}
+
+static DWORD queue_task( struct queue *queue, TASK_CALLBACK task, struct task_header *task_hdr )
 {
     TP_WORK *work;
     DWORD ret;
 
     if ((ret = start_queue( queue ))) return ret;
 
-    if (!(work = CreateThreadpoolWork( task, ctx, &queue->env ))) return GetLastError();
-    TRACE("queueing %p in %p\n", work, queue);
+    if (!(work = CreateThreadpoolWork( task_callback, task_hdr, &queue->env ))) return GetLastError();
+    TRACE("queueing %p in %p\n", task_hdr, queue);
+    task_hdr->callback = task;
     SubmitThreadpoolWork( work );
     CloseThreadpoolWork( work );
 
@@ -2167,11 +2175,11 @@ end:
     return ret;
 }
 
-static void CALLBACK task_send_request( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_send_request( void *ctx )
 {
     struct send_request *s = ctx;
 
-    TRACE("running %p\n", work);
+    TRACE( "running %p\n", ctx );
     send_request( s->request, s->headers, s->headers_len, s->optional, s->optional_len, s->total_len, s->context, TRUE );
 
     release_object( &s->request->hdr );
@@ -2219,7 +2227,7 @@ BOOL WINAPI WinHttpSendRequest( HINTERNET hrequest, const WCHAR *headers, DWORD
         s->context      = context;
 
         addref_object( &request->hdr );
-        if ((ret = queue_task( &request->queue, task_send_request, s )))
+        if ((ret = queue_task( &request->queue, task_send_request, &s->task_hdr )))
         {
             release_object( &request->hdr );
             free( s->headers );
@@ -2753,11 +2761,11 @@ static DWORD receive_response( struct request *request, BOOL async )
     return ret;
 }
 
-static void CALLBACK task_receive_response( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_receive_response( void *ctx )
 {
     struct receive_response *r = ctx;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
     receive_response( r->request, TRUE );
 
     release_object( &r->request->hdr );
@@ -2794,7 +2802,7 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
         r->request = request;
 
         addref_object( &request->hdr );
-        if ((ret = queue_task( &request->queue, task_receive_response, r )))
+        if ((ret = queue_task( &request->queue, task_receive_response, &r->task_hdr )))
         {
             release_object( &request->hdr );
             free( r );
@@ -2852,11 +2860,11 @@ done:
     return ret;
 }
 
-static void CALLBACK task_query_data_available( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_query_data_available( void *ctx )
 {
     struct query_data *q = ctx;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
     query_data_available( q->request, q->available, TRUE );
 
     release_object( &q->request->hdr );
@@ -2895,7 +2903,7 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
         q->available = available;
 
         addref_object( &request->hdr );
-        if ((ret = queue_task( &request->queue, task_query_data_available, q )))
+        if ((ret = queue_task( &request->queue, task_query_data_available, &q->task_hdr )))
         {
             release_object( &request->hdr );
             free( q );
@@ -2909,11 +2917,11 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
     return !ret || ret == ERROR_IO_PENDING;
 }
 
-static void CALLBACK task_read_data( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_read_data( void *ctx )
 {
     struct read_data *r = ctx;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
     read_data( r->request, r->buffer, r->to_read, r->read, TRUE );
 
     release_object( &r->request->hdr );
@@ -2954,7 +2962,7 @@ BOOL WINAPI WinHttpReadData( HINTERNET hrequest, void *buffer, DWORD to_read, DW
         r->read    = read;
 
         addref_object( &request->hdr );
-        if ((ret = queue_task( &request->queue, task_read_data, r )))
+        if ((ret = queue_task( &request->queue, task_read_data, &r->task_hdr )))
         {
             release_object( &request->hdr );
             free( r );
@@ -2990,11 +2998,11 @@ static DWORD write_data( struct request *request, const void *buffer, DWORD to_w
     return ret;
 }
 
-static void CALLBACK task_write_data( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_write_data( void *ctx )
 {
     struct write_data *w = ctx;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
     write_data( w->request, w->buffer, w->to_write, w->written, TRUE );
 
     release_object( &w->request->hdr );
@@ -3034,7 +3042,7 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, const void *buffer, DWORD to_w
         w->written  = written;
 
         addref_object( &request->hdr );
-        if ((ret = queue_task( &request->queue, task_write_data, w )))
+        if ((ret = queue_task( &request->queue, task_write_data, &w->task_hdr )))
         {
             release_object( &request->hdr );
             free( w );
@@ -3392,12 +3400,12 @@ static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE
     return send_frame( socket, opcode, 0, buf, len, final, ovr );
 }
 
-static void CALLBACK task_socket_send( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_socket_send( void *ctx )
 {
     struct socket_send *s = ctx;
     DWORD ret;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
 
     if (s->complete_async) ret = complete_send_frame( s->socket, &s->ovr, s->buf );
     else                   ret = socket_send( s->socket, s->type, s->buf, s->len, NULL );
@@ -3479,7 +3487,7 @@ DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_
             s->len    = len;
 
             addref_object( &socket->hdr );
-            if ((ret = queue_task( &socket->send_q, task_socket_send, s )))
+            if ((ret = queue_task( &socket->send_q, task_socket_send, &s->task_hdr )))
             {
                 InterlockedDecrement( &socket->hdr.pending_sends );
                 InterlockedExchange( &socket->pending_noncontrol_send, 0 );
@@ -3596,11 +3604,11 @@ static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_o
     return ERROR_SUCCESS;
 }
 
-static void CALLBACK task_socket_send_pong( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_socket_send_pong( void *ctx )
 {
     struct socket_send *s = ctx;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
 
     if (s->complete_async) complete_send_frame( s->socket, &s->ovr, NULL );
     else                   send_frame( s->socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
@@ -3638,7 +3646,7 @@ static DWORD socket_send_pong( struct socket *socket )
             s->complete_async = complete_async;
             s->socket = socket;
             addref_object( &socket->hdr );
-            if ((ret = queue_task( &socket->send_q, task_socket_send_pong, s )))
+            if ((ret = queue_task( &socket->send_q, task_socket_send_pong, &s->task_hdr )))
             {
                 InterlockedDecrement( &socket->hdr.pending_sends );
                 release_object( &socket->hdr );
@@ -3817,13 +3825,13 @@ static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD
     return ret;
 }
 
-static void CALLBACK task_socket_receive( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_socket_receive( void *ctx )
 {
     struct socket_receive *r = ctx;
     DWORD ret, count;
     WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
     ret = socket_receive( r->socket, r->buf, r->len, &count, &type );
 
     if (receive_io_complete( r->socket ))
@@ -3893,7 +3901,7 @@ DWORD WINAPI WinHttpWebSocketReceive( HINTERNET hsocket, void *buf, DWORD len, D
         r->len    = len;
 
         addref_object( &socket->hdr );
-        if ((ret = queue_task( &socket->recv_q, task_socket_receive, r )))
+        if ((ret = queue_task( &socket->recv_q, task_socket_receive, &r->task_hdr )))
         {
             InterlockedDecrement( &socket->hdr.pending_receives );
             release_object( &socket->hdr );
@@ -3919,12 +3927,12 @@ static void socket_shutdown_complete( struct socket *socket, DWORD ret )
     }
 }
 
-static void CALLBACK task_socket_shutdown( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_socket_shutdown( void *ctx )
 {
     struct socket_shutdown *s = ctx;
     DWORD ret;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
 
     if (s->complete_async) ret = complete_send_frame( s->socket, &s->ovr, s->reason );
     else                   ret = send_frame( s->socket, SOCKET_OPCODE_CLOSE, s->status, s->reason, s->len, TRUE, NULL );
@@ -3971,7 +3979,7 @@ static DWORD send_socket_shutdown( struct socket *socket, USHORT status, const v
             s->send_callback = send_callback;
 
             addref_object( &socket->hdr );
-            if ((ret = queue_task( &socket->send_q, task_socket_shutdown, s )))
+            if ((ret = queue_task( &socket->send_q, task_socket_shutdown, &s->task_hdr )))
             {
                 InterlockedDecrement( &socket->hdr.pending_sends );
                 release_object( &socket->hdr );
@@ -4057,12 +4065,12 @@ static void socket_close_complete( struct socket *socket, DWORD ret )
     }
 }
 
-static void CALLBACK task_socket_close( TP_CALLBACK_INSTANCE *instance, void *ctx, TP_WORK *work )
+static void task_socket_close( void *ctx )
 {
     struct socket_shutdown *s = ctx;
     DWORD ret;
 
-    TRACE("running %p\n", work);
+    TRACE("running %p\n", ctx);
 
     ret = socket_close( s->socket );
     socket_close_complete( s->socket, ret );
@@ -4132,7 +4140,7 @@ DWORD WINAPI WinHttpWebSocketClose( HINTERNET hsocket, USHORT status, void *reas
         s->socket = socket;
 
         addref_object( &socket->hdr );
-        if ((ret = queue_task( &socket->recv_q, task_socket_close, s )))
+        if ((ret = queue_task( &socket->recv_q, task_socket_close, &s->task_hdr )))
         {
             release_object( &socket->hdr );
             free( s );
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 19ef9a35e2d..96bd7b53747 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -273,8 +273,16 @@ struct socket
     BOOL last_receive_final;
 };
 
+typedef void (*TASK_CALLBACK)( void *ctx );
+
+struct task_header
+{
+    TASK_CALLBACK callback;
+};
+
 struct send_request
 {
+    struct task_header task_hdr;
     struct request *request;
     WCHAR *headers;
     DWORD headers_len;
@@ -286,17 +294,20 @@ struct send_request
 
 struct receive_response
 {
+    struct task_header task_hdr;
     struct request *request;
 };
 
 struct query_data
 {
+    struct task_header task_hdr;
     struct request *request;
     DWORD *available;
 };
 
 struct read_data
 {
+    struct task_header task_hdr;
     struct request *request;
     void *buffer;
     DWORD to_read;
@@ -305,6 +316,7 @@ struct read_data
 
 struct write_data
 {
+    struct task_header task_hdr;
     struct request *request;
     const void *buffer;
     DWORD to_write;
@@ -313,6 +325,7 @@ struct write_data
 
 struct socket_send
 {
+    struct task_header task_hdr;
     struct socket *socket;
     WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
     const void *buf;
@@ -323,6 +336,7 @@ struct socket_send
 
 struct socket_receive
 {
+    struct task_header task_hdr;
     struct socket *socket;
     void *buf;
     DWORD len;
@@ -330,6 +344,7 @@ struct socket_receive
 
 struct socket_shutdown
 {
+    struct task_header task_hdr;
     struct socket *socket;
     USHORT status;
     char reason[123];
-- 
2.35.1




More information about the wine-devel mailing list