PXENBUS_FDO Fdo;
KSPIN_LOCK Lock;
LONG References;
+ BOOLEAN Success;
ULONG Count;
LIST_ENTRY EarlyList;
LIST_ENTRY LateList;
PerformanceFrequency.LowPart);
}
+static VOID
+SuspendEarly(
+ IN PVOID Argument,
+ IN ULONG Cpu
+ )
+{
+ PXENBUS_SUSPEND_CONTEXT Context = Argument;
+ PLIST_ENTRY ListEntry;
+
+ LogPrintf(LOG_LEVEL_INFO,
+ "SUSPEND: EARLY (%u)\n", Cpu);
+
+ if (!Context->Success || Cpu != 0)
+ return;
+
+ //
+ // No lock is required here as the VM is single-threaded with interrupts
+ // disabled.
+ //
+
+ Context->Count++;
+
+ HypercallPopulate();
+
+ UnplugDevices();
+
+ for (ListEntry = Context->EarlyList.Flink;
+ ListEntry != &Context->EarlyList;
+ ListEntry = ListEntry->Flink) {
+ PXENBUS_SUSPEND_CALLBACK Callback;
+
+ Callback = CONTAINING_RECORD(ListEntry,
+ XENBUS_SUSPEND_CALLBACK,
+ ListEntry);
+ Callback->Function(Callback->Argument);
+ }
+}
+
+static VOID
+SuspendLate(
+ IN PVOID Argument,
+ IN ULONG Cpu
+ )
+{
+ PXENBUS_SUSPEND_CONTEXT Context = Argument;
+ PLIST_ENTRY ListEntry;
+
+ LogPrintf(LOG_LEVEL_INFO,
+ "SUSPEND: LATE (%u)\n", Cpu);
+
+ if (!Context->Success || Cpu != 0)
+ return;
+
+ // No lock is required here as the VM is single-threaded
+
+ for (ListEntry = Context->LateList.Flink;
+ ListEntry != &Context->LateList;
+ ListEntry = ListEntry->Flink) {
+ PXENBUS_SUSPEND_CALLBACK Callback;
+
+ Callback = CONTAINING_RECORD(ListEntry,
+ XENBUS_SUSPEND_CALLBACK,
+ ListEntry);
+ Callback->Function(Callback->Argument);
+ }
+}
+
NTSTATUS
#pragma prefast(suppress:28167) // Function changes IRQL
SuspendTrigger(
LogPrintf(LOG_LEVEL_INFO,
"SUSPEND: ====>\n");
- SyncCapture();
+ SyncCapture(Context, SuspendEarly, SuspendLate);
SyncDisableInterrupts();
__SuspendLogTimers("PRE-SUSPEND");
__SuspendLogTimers("POST-SUSPEND");
- if (NT_SUCCESS(status)) {
- PLIST_ENTRY ListEntry;
-
- Context->Count++;
-
- HypercallPopulate();
-
- UnplugDevices();
-
- for (ListEntry = Context->EarlyList.Flink;
- ListEntry != &Context->EarlyList;
- ListEntry = ListEntry->Flink) {
- PXENBUS_SUSPEND_CALLBACK Callback;
-
- Callback = CONTAINING_RECORD(ListEntry, XENBUS_SUSPEND_CALLBACK, ListEntry);
- Callback->Function(Callback->Argument);
- }
- }
+ Context->Success = NT_SUCCESS(status) ? TRUE : FALSE;
SyncEnableInterrupts();
-
- // No lock is required here as the VM is single-threaded until
- // SyncRelease() is called.
-
- if (NT_SUCCESS(status)) {
- PLIST_ENTRY ListEntry;
-
- for (ListEntry = Context->LateList.Flink;
- ListEntry != &Context->LateList;
- ListEntry = ListEntry->Flink) {
- PXENBUS_SUSPEND_CALLBACK Callback;
-
- Callback = CONTAINING_RECORD(ListEntry, XENBUS_SUSPEND_CALLBACK, ListEntry);
- Callback->Function(Callback->Argument);
- }
- }
-
SyncRelease();
LogPrintf(LOG_LEVEL_INFO, "SUSPEND: <====\n");
} SYNC_PROCESSOR, *PSYNC_PROCESSOR;
typedef struct _SYNC_CONTEXT {
+ PVOID Argument;
+ SYNC_CALLBACK Early;
+ SYNC_CALLBACK Late;
ULONG Sequence;
LONG ProcessorCount;
LONG CompletionCount;
static FORCEINLINE VOID
__SyncRelease(
- IN LONG Index
+ VOID
)
{
- LONG Old;
+ LONG Old;
+ LONG Index;
+
+ Index = KeGetCurrentProcessorNumberEx(NULL);
Old = InterlockedExchange(&SyncOwner, -1);
ASSERT3U(Old, ==, Index);
InterruptsDisabled = FALSE;
Index = KeGetCurrentProcessorNumberEx(&ProcNumber);
+
+ ASSERT(SyncOwner >= 0 && Index != (ULONG)SyncOwner);
+
Processor = &Context->Processor[Index];
Trace("====> (%u:%u)\n", ProcNumber.Group, ProcNumber.Number);
for (;;) {
ULONG Sequence;
- if (Processor->Exit)
+ if (Processor->Exit) {
+ if (Context->Late != NULL)
+ Context->Late(Context->Argument, Index);
+
break;
+ }
if (Processor->DisableInterrupts == InterruptsDisabled) {
_mm_pause();
} else {
InterruptsDisabled = FALSE;
+ if (Context->Early != NULL)
+ Context->Early(Context->Argument, Index);
+
_enable();
#pragma prefast(suppress:28138) // Use constant rather than variable
__drv_raisesIRQL(DISPATCH_LEVEL)
VOID
SyncCapture(
- VOID
+ IN PVOID Argument OPTIONAL,
+ IN SYNC_CALLBACK Early OPTIONAL,
+ IN SYNC_CALLBACK Late OPTIONAL
)
{
PSYNC_CONTEXT Context = SyncContext;
ASSERT(IsZeroMemory(Context, PAGE_SIZE));
+ Context->Argument = Argument;
+ Context->Early = Early;
+ Context->Late = Late;
+
Context->Sequence++;
Context->CompletionCount = 0;
Trace("====>\n");
+ ASSERT(SyncOwner >= 0);
+
Context->Sequence++;
Context->CompletionCount = 0;
KIRQL Irql;
LONG Index;
+ ASSERT(SyncOwner >= 0);
+
+ if (Context->Early != NULL)
+ Context->Early(Context->Argument, SyncOwner);
+
_enable();
Irql = KeGetCurrentIrql();
Trace("====>\n");
+ ASSERT(SyncOwner >= 0);
+
+ if (Context->Late != NULL)
+ Context->Late(Context->Argument, SyncOwner);
+
Context->Sequence++;
Context->CompletionCount = 0;
RtlZeroMemory(Context, PAGE_SIZE);
- Index = KeGetCurrentProcessorNumberEx(NULL);
- __SyncRelease(Index);
+ __SyncRelease();
Trace("<====\n");
}