Skip to content

Commit 05b6233

Browse files
Wait for Request to finish (#46176)
1 parent 91fd14d commit 05b6233

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
2525
m_pRequestHandlerContext(pRequestHandlerContext),
2626
m_pAsyncCompletionHandler(pAsyncCompletion),
2727
m_pDisconnectHandler(pDisconnectHandler),
28-
m_disconnectFired(false)
28+
m_disconnectFired(false),
29+
m_queueNotified(false)
2930
{
3031
InitializeSRWLock(&m_srwDisconnectLock);
3132
}
@@ -114,6 +115,14 @@ IN_PROCESS_HANDLER::NotifyDisconnect()
114115
if (pManagedHttpContext != nullptr)
115116
{
116117
m_pDisconnectHandler(pManagedHttpContext);
118+
{
119+
// lock before notifying, this prevents the condition where m_queueNotified is already checked but
120+
// the condition_variable isn't waiting yet, which would cause notify_all to NOOP and block
121+
// IndicateManagedRequestComplete until a spurious wakeup
122+
std::lock_guard<std::mutex> lock(m_lockQueue);
123+
m_queueNotified = true;
124+
}
125+
m_queueCheck.notify_all();
117126
}
118127
}
119128

@@ -122,11 +131,28 @@ IN_PROCESS_HANDLER::IndicateManagedRequestComplete(
122131
VOID
123132
)
124133
{
134+
bool disconnectFired = false;
125135
{
126136
SRWExclusiveLock lock(m_srwDisconnectLock);
127137
m_fManagedRequestComplete = TRUE;
128138
m_pManagedHttpContext = nullptr;
139+
disconnectFired = m_disconnectFired;
140+
}
141+
142+
if (disconnectFired)
143+
{
144+
// Block until we know NotifyDisconnect completed
145+
// this is because the caller of IndicateManagedRequestComplete will dispose the
146+
// GCHandle pointing at m_pManagedHttpContext, and a new GCHandle could use the same address
147+
// for the next request, this could cause an in-progress NotifyDisconnect call to disconnect the new request
148+
std::unique_lock<std::mutex> lock(m_lockQueue);
149+
// loop to handle spurious wakeups
150+
while (!m_queueNotified)
151+
{
152+
m_queueCheck.wait(lock);
153+
}
129154
}
155+
130156
::RaiseEvent<ANCMEvents::ANCM_INPROC_MANAGED_REQUEST_COMPLETION>(m_pW3Context, nullptr);
131157
}
132158

src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <memory>
88
#include "iapplication.h"
99
#include "inprocessapplication.h"
10+
#include <mutex>
11+
#include <condition_variable>
1012

1113
class IN_PROCESS_APPLICATION;
1214

@@ -88,4 +90,8 @@ class IN_PROCESS_HANDLER : public REQUEST_HANDLER
8890
static ALLOC_CACHE_HANDLER * sm_pAlloc;
8991
bool m_disconnectFired;
9092
SRWLOCK m_srwDisconnectLock;
93+
94+
std::mutex m_lockQueue;
95+
std::condition_variable m_queueCheck;
96+
bool m_queueNotified;
9197
};

src/Servers/IIS/IIS/src/Core/IISHttpContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ private async Task HandleRequest()
812812
finally
813813
{
814814
// Post completion after completing the request to resume the state machine
815+
// This must be called before freeing the GCHandle _thisHandle, see comment in IndicateManagedRequestComplete for details
815816
PostCompletion(ConvertRequestCompletionResults(successfulRequest));
816817

817818
// After disposing a safe handle, Dispose() will not block waiting for the pinvokes to finish.

0 commit comments

Comments
 (0)