Skip to content

Commit b3d35b3

Browse files
committed
Add debug tab and notification support
1 parent 6e99eed commit b3d35b3

File tree

22 files changed

+1827
-67
lines changed

22 files changed

+1827
-67
lines changed

.gitignore

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
################################################################################
2-
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
3-
################################################################################
4-
5-
/.vs
1+
.vs
62
/exe/.vs/ectest_app
73
/kmdf/.vs/ectest_kmdf
84
/exe/ARM64
95
/lib/ARM64
106
/lib/eclib/ARM64
117
/kmdf/ARM64
128
/rust/target
9+
/rust/mock-bin-src/target
10+
/rust/mock-bin

lib/eclib.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ VOID CleanupNotification()
279279
// Cancel any pending IO
280280
if(g_notify.handle) {
281281
while(g_notify.in_progress) {
282-
CancelIo(g_notify.handle);
282+
CancelIoEx(g_notify.handle, NULL);
283283
SleepConditionVariableCS(&g_notify.cv, &g_notify.lock, INFINITE);
284284
}
285285
CloseHandle(g_notify.handle);
@@ -310,14 +310,17 @@ UINT32 WaitForNotification(UINT32 event)
310310
UINT32 ievent = 0;
311311
NotificationRsp_t notify_response = {0};
312312
NotificationReq_t notify_request = {0};
313-
314-
// Make sure Initialization has been done
315-
if(g_notify.handle == INVALID_HANDLE_VALUE) {
316-
return 0;
317-
}
313+
BOOL aborted = FALSE;
318314

319315
// Loop until we get event we are looking for
320316
for(;;) {
317+
// Make sure Initialization has been done
318+
// This is checked every iteration because CleanupNotification may have been called which
319+
// destroys the critical section, and attempting to enter it below is undefined behavior
320+
if(g_notify.handle == INVALID_HANDLE_VALUE) {
321+
return 0;
322+
}
323+
321324
// There could be many calls into this function, only first call calls into KMDF driver
322325
// Subsequent calls just wait for the event to be set by the KMDF driver
323326
EnterCriticalSection(&g_notify.lock);
@@ -339,19 +342,33 @@ UINT32 WaitForNotification(UINT32 event)
339342
) == TRUE )
340343
{
341344
g_notify.event = notify_response.lastevent;
345+
// Tricky race condition where Cleanup cancels the IO call and we beat it back to the top
346+
// where we set in_progress to true again, then Cleanup calls cancel again but we haven't
347+
// entered IoControl call yet, but then we get there and Cleanup is sleeping but now we
348+
// are stuck in IoControl and can't return to Wake it again resulting in deadlock.
349+
// So we explicitly check if we returned due to being cancelled and bail out of the loop to prevent this.
350+
} else if(GetLastError() == ERROR_OPERATION_ABORTED) {
351+
aborted = TRUE;
342352
} else {
343353
g_notify.event = 0;
344354
}
345355

356+
// Enter critical section here to ensure wake is caught by Cleanup
357+
EnterCriticalSection(&g_notify.lock);
346358
g_notify.in_progress = FALSE;
347359
WakeAllConditionVariable(&g_notify.cv);
348360
} else {
349361
// Wait for notification to be set
350-
LeaveCriticalSection(&g_notify.lock);
351-
SleepConditionVariableCS(&g_notify.cv, &g_notify.lock, INFINITE);
362+
// Loop for spurious wakeups
363+
while(g_notify.in_progress) {
364+
SleepConditionVariableCS(&g_notify.cv, &g_notify.lock, INFINITE);
365+
}
352366
}
353367

354-
if(event == 0 || g_notify.event == event) {
368+
// Regardless of branch we are always in a critical section at this point so leave it
369+
LeaveCriticalSection(&g_notify.lock);
370+
371+
if(aborted || event == 0 || g_notify.event == event) {
355372
ievent = g_notify.event;
356373
break;
357374
}

0 commit comments

Comments
 (0)