[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH 13/15] Re-work EVTCHN Trigger



By re-working the event channel poll callback to add pending channels to a
list and then service them, we can tidy up Trigger by forcibly appending a
channel to the same list and then scheduling a DPC on the correct cpu to
service in the list (unless an interrupt callback came along in the interim
and did the job).

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/xenbus/evtchn.c | 212 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 148 insertions(+), 64 deletions(-)

diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index 81f97e4..437bfac 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -75,6 +75,7 @@ struct _XENBUS_EVTCHN_CHANNEL {
     ULONG                       Magic;
     KSPIN_LOCK                  Lock;
     LIST_ENTRY                  ListEntry;
+    LIST_ENTRY                  PendingListEntry;
     PVOID                       Caller;
     PKSERVICE_ROUTINE           Callback;
     PVOID                       Argument;
@@ -105,6 +106,7 @@ struct _XENBUS_EVTCHN_CONTEXT {
     BOOLEAN                         UseEvtchnFifoAbi;
     PXENBUS_HASH_TABLE              Table;
     LIST_ENTRY                      List;
+    LIST_ENTRY                      PendingList[MAXIMUM_PROCESSORS];
     KDPC                            Dpc[MAXIMUM_PROCESSORS];
 };
 
@@ -308,6 +310,8 @@ EvtchnOpen(
 
     LocalPort = Channel->LocalPort;
 
+    InitializeListHead(&Channel->PendingListEntry);
+
     status = XENBUS_EVTCHN_ABI(PortEnable,
                                &Context->EvtchnAbi,
                                LocalPort);
@@ -342,6 +346,9 @@ fail4:
 fail3:
     Error("fail3\n");
 
+    ASSERT(IsListEmpty(&Channel->PendingListEntry));
+    RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
+
     Channel->LocalPort = 0;
     Channel->Mask = FALSE;
     RtlZeroMemory(&Channel->Parameters, sizeof (XENBUS_EVTCHN_PARAMETERS));
@@ -430,6 +437,102 @@ fail1:
     return status;
 }
 
+static BOOLEAN
+EvtchnPollCallback(
+    IN  PVOID               Argument,
+    IN  ULONG               LocalPort
+    )
+{
+    PXENBUS_EVTCHN_CONTEXT  Context = Argument;
+    ULONG                   Cpu;
+    PXENBUS_EVTCHN_CHANNEL  Channel;
+    BOOLEAN                 Pending;
+    NTSTATUS                status;
+
+    ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
+    Cpu = KeGetCurrentProcessorNumber();
+
+    status = HashTableLookup(Context->Table,
+                             LocalPort,
+                             (PULONG_PTR)&Channel);
+    if (!NT_SUCCESS(status))
+        goto done;
+
+    ASSERT3U(Channel->LocalPort, ==, LocalPort);
+
+    Pending = !IsListEmpty(&Channel->PendingListEntry);
+
+    if (!Pending)
+        InsertTailList(&Context->PendingList[Cpu],
+                       &Channel->PendingListEntry);
+
+done:
+    return FALSE;
+}
+
+static BOOLEAN
+EvtchnPoll(
+    IN  PXENBUS_EVTCHN_CONTEXT  Context,
+    IN  ULONG                   Cpu
+    )
+{
+    BOOLEAN                     DoneSomething;
+
+    (VOID) XENBUS_EVTCHN_ABI(Poll,
+                             &Context->EvtchnAbi,
+                             Cpu,
+                             EvtchnPollCallback,
+                             Context);
+
+    DoneSomething = FALSE;
+    while (!IsListEmpty(&Context->PendingList[Cpu])) {
+        PLIST_ENTRY             ListEntry;
+        PXENBUS_EVTCHN_CHANNEL  Channel;
+
+        ListEntry = RemoveHeadList(&Context->PendingList[Cpu]);
+        ASSERT(ListEntry != &Context->PendingList[Cpu]);
+
+        InitializeListHead(ListEntry);
+
+        Channel = CONTAINING_RECORD(ListEntry,
+                                    XENBUS_EVTCHN_CHANNEL,
+                                    PendingListEntry);
+        if (Channel->Mask)
+            XENBUS_EVTCHN_ABI(PortMask,
+                              &Context->EvtchnAbi,
+                              Channel->LocalPort);
+
+        XENBUS_EVTCHN_ABI(PortAck,
+                          &Context->EvtchnAbi,
+                          Channel->LocalPort);
+
+#pragma warning(suppress:6387)  // NULL argument
+        DoneSomething |= Channel->Callback(NULL, Channel->Argument);
+    }
+
+    return DoneSomething;
+}
+
+static VOID
+EvtchnFlush(
+    IN  PXENBUS_EVTCHN_CONTEXT  Context,
+    IN  ULONG                   Cpu
+    )
+{
+    PXENBUS_INTERRUPT           Interrupt;
+    KIRQL                       Irql;
+
+    Interrupt = (Context->Affinity != 0) ? // Latched available
+                Context->LatchedInterrupt[Cpu] :
+                Context->LevelSensitiveInterrupt;
+
+    Irql = FdoAcquireInterruptLock(Context->Fdo, Interrupt);
+
+    (VOID) EvtchnPoll(Context, Cpu);
+
+    FdoReleaseInterruptLock(Context->Fdo, Interrupt, Irql);
+}
+
 static
 _Function_class_(KDEFERRED_ROUTINE)
 _IRQL_requires_max_(DISPATCH_LEVEL)
@@ -437,7 +540,7 @@ _IRQL_requires_min_(DISPATCH_LEVEL)
 _IRQL_requires_(DISPATCH_LEVEL)
 _IRQL_requires_same_
 VOID
-EvtchnCallback(
+EvtchnDpc(
     IN  PKDPC               Dpc,
     IN  PVOID               _Context,
     IN  PVOID               Argument1,
@@ -445,23 +548,24 @@ EvtchnCallback(
     )
 {
     PXENBUS_EVTCHN_CONTEXT  Context = _Context;
-    PXENBUS_EVTCHN_CHANNEL  Channel = Argument1;
-    PXENBUS_INTERRUPT       Interrupt;
-    KIRQL                   Irql;
+    ULONG                   Cpu;
 
     UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(Argument1);
     UNREFERENCED_PARAMETER(Argument2);
 
-    Interrupt = (Context->Affinity != 0) ? // Latched available
-                Context->LatchedInterrupt[Channel->Cpu] :
-                Context->LevelSensitiveInterrupt;
+    ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
+    Cpu = KeGetCurrentProcessorNumber();
 
-    Irql = FdoAcquireInterruptLock(Context->Fdo, Interrupt);
+    KeAcquireSpinLockAtDpcLevel(&Context->Lock);
 
-#pragma warning(suppress:6387)  // NULL argument
-    (VOID) Channel->Callback(NULL, Channel->Argument);
+    if (Context->References == 0)
+        goto done;
 
-    FdoReleaseInterruptLock(Context->Fdo, Interrupt, Irql);
+    EvtchnFlush(Context, Cpu);
+
+done:
+    KeReleaseSpinLockFromDpcLevel(&Context->Lock);
 }
 
 static VOID
@@ -473,15 +577,35 @@ EvtchnTrigger(
     PXENBUS_EVTCHN_CONTEXT      Context = Interface->Context;
     PKDPC                       Dpc;
     KIRQL                       Irql;
+    ULONG                       Cpu;
+    PXENBUS_INTERRUPT           Interrupt;
+    BOOLEAN                     Pending;
 
     ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC);
 
     KeAcquireSpinLock(&Channel->Lock, &Irql);
+    Cpu = Channel->Cpu;
+    KeReleaseSpinLock(&Channel->Lock, Irql);
 
-    Dpc = &Context->Dpc[Channel->Cpu];
-    KeInsertQueueDpc(Dpc, Channel, NULL);
+    Interrupt = (Context->Affinity != 0) ? // Latched available
+                Context->LatchedInterrupt[Cpu] :
+                Context->LevelSensitiveInterrupt;
 
-    KeReleaseSpinLock(&Channel->Lock, Irql);
+    Irql = FdoAcquireInterruptLock(Context->Fdo, Interrupt);
+
+    Pending = !IsListEmpty(&Channel->PendingListEntry);
+
+    if (!Pending)
+        InsertTailList(&Context->PendingList[Cpu],
+                       &Channel->PendingListEntry);
+
+    FdoReleaseInterruptLock(Context->Fdo, Interrupt, Irql);
+
+    if (Pending)
+        return;
+
+    Dpc = &Context->Dpc[Cpu];
+    KeInsertQueueDpc(Dpc, NULL, NULL);
 }
 
 static VOID
@@ -597,6 +721,9 @@ EvtchnClose(
 
     Channel->Cpu = 0;
 
+    ASSERT(IsListEmpty(&Channel->PendingListEntry));
+    RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
+
     Channel->LocalPort = 0;
     Channel->Mask = FALSE;
     RtlZeroMemory(&Channel->Parameters, sizeof (XENBUS_EVTCHN_PARAMETERS));
@@ -629,49 +756,6 @@ EvtchnGetPort(
     return Channel->LocalPort;
 }
 
-static BOOLEAN
-EvtchnPollCallback(
-    IN  PVOID               Argument,
-    IN  ULONG               LocalPort
-    )
-{
-    PXENBUS_EVTCHN_CONTEXT  Context = Argument;
-    PXENBUS_EVTCHN_CHANNEL  Channel;
-    BOOLEAN                 DoneSomething;
-    NTSTATUS                status;
-
-    DoneSomething = FALSE;
-
-    status = HashTableLookup(Context->Table,
-                             LocalPort,
-                             (PULONG_PTR)&Channel);
-    
-    if (!NT_SUCCESS(status)) {
-        Warning("[%d]: INVALID PORT\n", LocalPort);
-
-        XENBUS_EVTCHN_ABI(PortMask,
-                          &Context->EvtchnAbi,
-                          LocalPort);
-
-        goto done;
-    }
-
-    if (Channel->Mask)
-        XENBUS_EVTCHN_ABI(PortMask,
-                          &Context->EvtchnAbi,
-                          LocalPort);
-
-    XENBUS_EVTCHN_ABI(PortAck,
-                      &Context->EvtchnAbi,
-                      LocalPort);
-
-#pragma warning(suppress:6387)  // NULL argument
-    DoneSomething = Channel->Callback(NULL, Channel->Argument);
-
-done:
-    return DoneSomething;
-}
-
 static
 _Function_class_(KSERVICE_ROUTINE)
 __drv_requiresIRQL(HIGH_LEVEL)
@@ -691,15 +775,10 @@ EvtchnInterruptCallback(
     Cpu = KeGetCurrentProcessorNumber();
 
     DoneSomething = FALSE;
-
     while (XENBUS_SHARED_INFO(UpcallPending,
                               &Context->SharedInfoInterface,
                               Cpu))
-        DoneSomething |= XENBUS_EVTCHN_ABI(Poll,
-                                           &Context->EvtchnAbi,
-                                           Cpu,
-                                           EvtchnPollCallback,
-                                           Context);
+        DoneSomething |= EvtchnPoll(Context, Cpu);
 
     return DoneSomething;
 }
@@ -1131,6 +1210,8 @@ EvtchnRelease(
 
     Cpu = KeNumberProcessors;
     while (--Cpu >= 0) {
+        EvtchnFlush(Context, Cpu);
+
         FdoFreeInterrupt(Fdo, Context->LatchedInterrupt[Cpu]);
         Context->LatchedInterrupt[Cpu] = NULL;
     }
@@ -1274,7 +1355,9 @@ EvtchnInitialize(
     for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
         PKDPC   Dpc = &(*Context)->Dpc[Cpu];
 
-        KeInitializeDpc(Dpc, EvtchnCallback, *Context);
+        InitializeListHead(&(*Context)->PendingList[Cpu]);
+
+        KeInitializeDpc(Dpc, EvtchnDpc, *Context);
         KeSetTargetProcessorDpc(Dpc, (CCHAR)Cpu);
     }
 
@@ -1395,6 +1478,7 @@ EvtchnTeardown(
     RtlZeroMemory(&Context->Dpc, sizeof (KDPC) * MAXIMUM_PROCESSORS);
     RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
     RtlZeroMemory(&Context->List, sizeof (LIST_ENTRY));
+    RtlZeroMemory(&Context->PendingList, sizeof (LIST_ENTRY) * 
MAXIMUM_PROCESSORS);
 
     RtlZeroMemory(&Context->SharedInfoInterface,
                   sizeof (XENBUS_SHARED_INFO_INTERFACE));
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.