diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c index dc13fd093c669a49cdaaeed98501b3a1e107da3e..2932108f501278dd2936370baf3b6747ba868361 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 56e776da8be68fe305dd9c3f390855eb8a749c1f..0eca509b7eeb61583759d76cd8d60df87bf5a0c2 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 51043fdee34c5730ff332304f81d79360d796411..4c567edb64a3ecd056f20a7610c18b00744cdd28 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 * ); };