You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
432 lines
8.9 KiB
432 lines
8.9 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
blocklst.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains WinInet async support to allow blocking of unknown threads, on auto-proxy events.
|
|
|
|
Contents:
|
|
BlockThreadOnEvent
|
|
SignalThreadOnEvent
|
|
AcquireBlockedRequestQueue
|
|
ReleaseBlockedRequestQueue
|
|
(DestroyBlockedThreadEvent)
|
|
|
|
|
|
Author:
|
|
|
|
Arthur L Bierer (arthurbi) 15-Feb-1998
|
|
|
|
Environment:
|
|
|
|
Win32 user-mode DLL
|
|
|
|
Revision History:
|
|
|
|
15-Feb-1998 arthurbi
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
#include <perfdiag.hxx>
|
|
|
|
//
|
|
// private data
|
|
//
|
|
|
|
//
|
|
// BlockedRequestQueue - when threads need to block on an event they get
|
|
// placed in here until their event is signaled. This is needed so threads
|
|
// can block on internally kept events without having to be tied
|
|
// to keeping track of event handles.
|
|
//
|
|
// Blocked threads must not be also waiting for a socket to become unblocked
|
|
//
|
|
|
|
GLOBAL SERIALIZED_LIST BlockedRequestQueue = {0};
|
|
|
|
//
|
|
// ARB - information common to all asynchronous blocked events
|
|
//
|
|
|
|
typedef struct {
|
|
|
|
//
|
|
// List - requests are queued on doubly-linked list. N.B. Code that deals
|
|
// in ARBs implicitly assumes that List is at offset zero in the ARB. Move
|
|
// this and pick up the pieces...
|
|
//
|
|
|
|
LIST_ENTRY List;
|
|
|
|
//
|
|
// hEvent - handle to Event that we are blocked on.
|
|
//
|
|
|
|
HANDLE hEvent;
|
|
|
|
//
|
|
// dwBlockedOnEvent - contains the event this ARB may be blocked
|
|
// on. This allows a FIBER to block itself on an Internally kept
|
|
// event. When the event is signalled, it will wakeup, and moved
|
|
// to the Active Pool of fibers.
|
|
//
|
|
// A ZERO value means there is NO event that is being blocked on.
|
|
//
|
|
|
|
DWORD_PTR dwBlockedOnEvent;
|
|
|
|
//
|
|
// dwBlockedOnEventReturnCode - contains error code returned from
|
|
// fiber or main thread that is doing the unblocking.
|
|
//
|
|
|
|
DWORD dwBlockedOnEventReturnCode;
|
|
|
|
#if INET_DEBUG
|
|
|
|
//
|
|
// dwSignature - in the debug version, we maintain a signature in the ARB
|
|
// for sanity checking
|
|
//
|
|
|
|
DWORD dwSignature;
|
|
|
|
#endif // INET_DEBUG
|
|
|
|
} ARB, * LPARB;
|
|
|
|
//
|
|
// functions...
|
|
//
|
|
|
|
PRIVATE
|
|
VOID
|
|
DestroyBlockedThreadEvent(
|
|
IN LPARB lpArb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes lpArb from the blocked request queue if its still there, and
|
|
destroys it
|
|
|
|
Arguments:
|
|
|
|
lpArb - pointer to AR_SYNC_EVENT ARB
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_ASYNC,
|
|
None,
|
|
"DestroyBlockedThreadEvent",
|
|
"%#x",
|
|
lpArb
|
|
));
|
|
|
|
AcquireBlockedRequestQueue();
|
|
|
|
if (lpArb->hEvent != NULL) {
|
|
CloseHandle(lpArb->hEvent);
|
|
}
|
|
|
|
if (IsOnSerializedList(&BlockedRequestQueue, &lpArb->List)) {
|
|
RemoveFromSerializedList(&BlockedRequestQueue, &lpArb->List);
|
|
}
|
|
|
|
ReleaseBlockedRequestQueue();
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
DWORD
|
|
BlockThreadOnEvent(
|
|
IN DWORD_PTR dwEventId,
|
|
IN DWORD dwTimeout,
|
|
IN BOOL bReleaseLock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Waits for an async event if called in the context of a fiber, else waits for
|
|
an event if called in the context of a sync request
|
|
|
|
Arguments:
|
|
|
|
dwEventId - event id to wait on
|
|
|
|
dwTimeout - amount of time to wait
|
|
|
|
bReleaseLock - TRUE if we need to release the blocked request queue
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
The request/wait completed successfully
|
|
|
|
Failure - ERROR_INTERNET_TIMEOUT
|
|
The request timed out
|
|
|
|
ERROR_INTERNET_INTERNAL_ERROR
|
|
We couldn't get the INTERNET_THREAD_INFO
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_ASYNC,
|
|
Dword,
|
|
"BlockThreadOnEvent",
|
|
"%#x, %d, %B",
|
|
dwEventId,
|
|
dwTimeout,
|
|
bReleaseLock
|
|
));
|
|
|
|
DWORD error;
|
|
ARB Arb;
|
|
|
|
ZeroMemory(&Arb, sizeof(Arb));
|
|
|
|
//
|
|
// set up the remaining fields in the ARB - initialize the list pointer,
|
|
// set the priority (to default), and the event id
|
|
//
|
|
|
|
Arb.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (Arb.hEvent == NULL) {
|
|
error = GetLastError();
|
|
|
|
// IE6 BUG #25117
|
|
// if we acquired the blocked request queue before calling this function
|
|
// then we need to release it
|
|
//
|
|
|
|
if (bReleaseLock) {
|
|
ReleaseBlockedRequestQueue();
|
|
}
|
|
|
|
goto quit;
|
|
}
|
|
Arb.dwBlockedOnEvent = dwEventId;
|
|
|
|
//
|
|
// add the request to the blocked request queue
|
|
//
|
|
|
|
InsertAtTailOfSerializedList(&BlockedRequestQueue, &Arb.List);
|
|
|
|
//
|
|
// if we acquired the blocked request queue before calling this function
|
|
// then we need to release it
|
|
//
|
|
|
|
if (bReleaseLock) {
|
|
ReleaseBlockedRequestQueue();
|
|
}
|
|
|
|
//
|
|
// now wait here for the event to become signalled
|
|
//
|
|
|
|
error = PERF_WaitForSingleObject(Arb.hEvent,
|
|
dwTimeout
|
|
);
|
|
|
|
//
|
|
// if we timed out then we will remove and destroy the ARB, else the thread
|
|
// which signalled the request will have done so
|
|
//
|
|
|
|
if (error == WAIT_TIMEOUT) {
|
|
error = ERROR_INTERNET_TIMEOUT;
|
|
} else {
|
|
error = Arb.dwBlockedOnEventReturnCode;
|
|
}
|
|
|
|
quit:
|
|
|
|
//
|
|
// remove the request from the blocked request queue and destroy it
|
|
//
|
|
|
|
DestroyBlockedThreadEvent(&Arb);
|
|
|
|
DEBUG_LEAVE(error);
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SignalThreadOnEvent(
|
|
IN DWORD_PTR dwEventId,
|
|
IN DWORD dwNumberOfWaiters,
|
|
IN DWORD dwReturnCode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unblocks a number of fibers that may be waiting for an event to be signalled.
|
|
When the fibers unblock they will be rescheduled to the Active Request Queue.
|
|
The 'event' is reset automatically back to unsignalled state.
|
|
|
|
If called outside of the worker thread, this function also handles
|
|
interupting the blocked worked thread so it can resume requests.
|
|
|
|
Arguments:
|
|
|
|
dwEventId - Event ID to wake up on.
|
|
|
|
dwNumberOfWaiters - number of waiters to unblock. Choose a large number
|
|
to mean 'all'
|
|
|
|
dwReturnCode - Upon waking up fibers, their blocked called will return
|
|
with this error code.
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Number of waiters unblocked
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_ASYNC,
|
|
Int,
|
|
"SignalThreadOnEvent",
|
|
"%#x, %d, %d (%s)",
|
|
dwEventId,
|
|
dwNumberOfWaiters,
|
|
dwReturnCode,
|
|
InternetMapError(dwReturnCode)
|
|
));
|
|
|
|
INET_ASSERT(dwNumberOfWaiters > 0);
|
|
|
|
DWORD dwUnblocked = 0;
|
|
|
|
AcquireBlockedRequestQueue();
|
|
|
|
LPARB lpArb = (LPARB)HeadOfSerializedList(&BlockedRequestQueue);
|
|
LPARB lpArbPrevious = (LPARB)SlSelf(&BlockedRequestQueue);
|
|
|
|
while (lpArb != (LPARB)SlSelf(&BlockedRequestQueue)) {
|
|
if (lpArb->dwBlockedOnEvent == dwEventId) {
|
|
|
|
lpArb->dwBlockedOnEventReturnCode = dwReturnCode;
|
|
|
|
//
|
|
// if the ARB is really an async request then add it to the end of
|
|
// the async request queue else if it is a sync request then just
|
|
// signal the event. The waiter will free the ARB
|
|
//
|
|
|
|
SetEvent(lpArb->hEvent);
|
|
|
|
DEBUG_PRINT(ASYNC,
|
|
INFO,
|
|
("signalled sync request %#x, on %#x\n",
|
|
lpArb,
|
|
lpArb->dwBlockedOnEvent
|
|
));
|
|
|
|
|
|
//
|
|
// if we've hit the number of waiters we were to unblock then
|
|
// quit
|
|
//
|
|
|
|
++dwUnblocked;
|
|
if (dwUnblocked == dwNumberOfWaiters) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// we moved the ARB
|
|
//
|
|
|
|
lpArb = lpArbPrevious;
|
|
}
|
|
lpArbPrevious = lpArb;
|
|
lpArb = (LPARB)lpArb->List.Flink;
|
|
}
|
|
|
|
ReleaseBlockedRequestQueue();
|
|
|
|
DEBUG_LEAVE(dwUnblocked);
|
|
|
|
return dwUnblocked;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AcquireBlockedRequestQueue(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Synchronizes access to the blocked request queue
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LockSerializedList(&BlockedRequestQueue);
|
|
}
|
|
|
|
|
|
VOID
|
|
ReleaseBlockedRequestQueue(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases the lock acquired with AcquireBlockedRequestQueue
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UnlockSerializedList(&BlockedRequestQueue);
|
|
}
|