@@ -25,7 +25,8 @@ IN_PROCESS_HANDLER::IN_PROCESS_HANDLER(
25
25
m_pRequestHandlerContext(pRequestHandlerContext),
26
26
m_pAsyncCompletionHandler(pAsyncCompletion),
27
27
m_pDisconnectHandler(pDisconnectHandler),
28
- m_disconnectFired(false )
28
+ m_disconnectFired(false ),
29
+ m_queueNotified(false )
29
30
{
30
31
InitializeSRWLock (&m_srwDisconnectLock);
31
32
}
@@ -114,6 +115,14 @@ IN_PROCESS_HANDLER::NotifyDisconnect()
114
115
if (pManagedHttpContext != nullptr )
115
116
{
116
117
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 ();
117
126
}
118
127
}
119
128
@@ -122,11 +131,28 @@ IN_PROCESS_HANDLER::IndicateManagedRequestComplete(
122
131
VOID
123
132
)
124
133
{
134
+ bool disconnectFired = false ;
125
135
{
126
136
SRWExclusiveLock lock (m_srwDisconnectLock);
127
137
m_fManagedRequestComplete = TRUE ;
128
138
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
+ }
129
154
}
155
+
130
156
::RaiseEvent<ANCMEvents::ANCM_INPROC_MANAGED_REQUEST_COMPLETION>(m_pW3Context, nullptr );
131
157
}
132
158
0 commit comments