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

[win-pv-devel] [PATCH] Add Wait method to XENBUS_EVTCHN and use it in XENBUS_STORE



This patch adds a Wait method to the XENBUS_EVTCHN interface to allow
a subscriber to wait for an event channel to be signalled. This is useful
in XENBUS_STORE to avoid polling the ring state too often.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/evtchn_interface.h |  36 +++++++++++++++-
 include/revision.h         |   5 ++-
 src/xenbus/evtchn.c        | 103 ++++++++++++++++++++++++++++++++++++++++++++-
 src/xenbus/store.c         |  56 +++++++++++++++++++++---
 4 files changed, 189 insertions(+), 11 deletions(-)

diff --git a/include/evtchn_interface.h b/include/evtchn_interface.h
index 6f8fe42..a9952d6 100644
--- a/include/evtchn_interface.h
+++ b/include/evtchn_interface.h
@@ -180,6 +180,20 @@ typedef VOID
     IN  PXENBUS_EVTCHN_CHANNEL  Channel
     );
 
+/*! \typedef XENBUS_EVTCHN_WAIT
+    \brief Wait for an event to the local end of the channel
+
+    \param Interface The interface header
+    \param Channel The channel handle
+    \param Timeout An optional timeout value (similar to 
KeWaitForSingleObject(), but non-zero values are allowed at DISPATCH_LEVEL).
+*/
+typedef NTSTATUS
+(*XENBUS_EVTCHN_WAIT)(
+    IN  PINTERFACE              Interface,
+    IN  PXENBUS_EVTCHN_CHANNEL  Channel,
+    IN  PLARGE_INTEGER          Timeout OPTIONAL
+    );
+
 /*! \typedef XENBUS_EVTCHN_GET_PORT
     \brief Get the local port number bound to the channel
 
@@ -276,7 +290,25 @@ struct _XENBUS_EVTCHN_INTERFACE_V4 {
     XENBUS_EVTCHN_CLOSE     EvtchnClose;
 };
 
-typedef struct _XENBUS_EVTCHN_INTERFACE_V4 XENBUS_EVTCHN_INTERFACE, 
*PXENBUS_EVTCHN_INTERFACE;
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V5
+    \brief EVTCHN interface version 5
+    \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V5 {
+    INTERFACE               Interface;
+    XENBUS_EVTCHN_ACQUIRE   EvtchnAcquire;
+    XENBUS_EVTCHN_RELEASE   EvtchnRelease;
+    XENBUS_EVTCHN_OPEN      EvtchnOpen;
+    XENBUS_EVTCHN_BIND      EvtchnBind;
+    XENBUS_EVTCHN_UNMASK    EvtchnUnmask;
+    XENBUS_EVTCHN_SEND      EvtchnSend;
+    XENBUS_EVTCHN_TRIGGER   EvtchnTrigger;
+    XENBUS_EVTCHN_WAIT      EvtchnWait;
+    XENBUS_EVTCHN_GET_PORT  EvtchnGetPort;
+    XENBUS_EVTCHN_CLOSE     EvtchnClose;
+};
+
+typedef struct _XENBUS_EVTCHN_INTERFACE_V5 XENBUS_EVTCHN_INTERFACE, 
*PXENBUS_EVTCHN_INTERFACE;
 
 /*! \def XENBUS_EVTCHN
     \brief Macro at assist in method invocation
@@ -287,7 +319,7 @@ typedef struct _XENBUS_EVTCHN_INTERFACE_V4 
XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVT
 #endif  // _WINDLL
 
 #define XENBUS_EVTCHN_INTERFACE_VERSION_MIN 1
-#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 4
+#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 5
 
 #endif  // _XENBUS_EVTCHN_INTERFACE_H
 
diff --git a/include/revision.h b/include/revision.h
index dfe4995..7f261fc 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -44,7 +44,8 @@
 // EM - XENFILT_EMULATED_INTERFACE
 
 //                    REVISION   S  SI   E   D  ST   R   C   G   U  EM
-#define DEFINE_REVISION_TABLE                                           \
-    DEFINE_REVISION(0x08000009,  1,  2,  4,  1,  1,  1,  1,  1,  1,  1)
+#define DEFINE_REVISION_TABLE                                               \
+    DEFINE_REVISION(0x08000009,  1,  2,  4,  1,  1,  1,  1,  1,  1,  1),    \
+    DEFINE_REVISION(0x0800000A,  1,  2,  5,  1,  1,  1,  1,  1,  1,  1)
 
 #endif  // _REVISION_H
diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index 051ec1f..4a6ebd2 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -81,6 +81,7 @@ struct _XENBUS_EVTCHN_CHANNEL {
     PKSERVICE_ROUTINE           Callback;
     PVOID                       Argument;
     BOOLEAN                     Active; // Must be tested at >= DISPATCH_LEVEL
+    ULONG                       Events;
     XENBUS_EVTCHN_TYPE          Type;
     XENBUS_EVTCHN_PARAMETERS    Parameters;
     BOOLEAN                     Mask;
@@ -400,6 +401,8 @@ EvtchnReap(
 
     Trace("%u\n", LocalPort);
 
+    Channel->Events = 0;
+
     ASSERT(Channel->Closed);
     Channel->Closed = FALSE;
 
@@ -504,6 +507,8 @@ EvtchnPoll(
 
         KeMemoryBarrier();
         if (!Channel->Closed) {
+            Channel->Events++;
+
             RemoveEntryList(&Channel->PendingListEntry);
             InitializeListHead(&Channel->PendingListEntry);
 
@@ -879,6 +884,66 @@ EvtchnGetPort(
     return Channel->LocalPort;
 }
 
+static NTSTATUS
+EvtchnWait(
+    IN  PINTERFACE              Interface,
+    IN  PXENBUS_EVTCHN_CHANNEL  Channel,
+    IN  PLARGE_INTEGER          Timeout
+    )
+{
+    KIRQL                       Irql;
+    ULONG                       Events;
+    LARGE_INTEGER               Start;
+    NTSTATUS                    status;
+
+    UNREFERENCED_PARAMETER(Interface);
+
+    ASSERT3U(KeGetCurrentIrql(), <=, DISPATCH_LEVEL);
+    KeRaiseIrql(DISPATCH_LEVEL, &Irql); // Prevent suspend
+
+    Events = Channel->Events;
+    KeMemoryBarrier();
+
+    KeQuerySystemTime(&Start);
+
+    for (;;) {
+        status = STATUS_SUCCESS;
+        if (Channel->Events != Events)
+            break;
+
+        if (Timeout != NULL) {
+            LARGE_INTEGER   Now;
+
+            KeQuerySystemTime(&Now);
+
+            status = STATUS_TIMEOUT;
+            if (Timeout->QuadPart > 0) {
+                // Absolute timeout
+                if (Now.QuadPart > Timeout->QuadPart)
+                    break;
+            } else if (Timeout->QuadPart < 0) {
+                LONGLONG   Delta;
+
+                // Relative timeout
+                Delta = Now.QuadPart - Start.QuadPart;
+                if (Delta > -Timeout->QuadPart)
+                    break;
+            } else {
+                // Immediate timeout
+                ASSERT(Timeout->QuadPart == 0);
+                break;
+            }
+        }
+
+        _mm_pause();
+        KeMemoryBarrier();
+    }
+
+    KeLowerIrql(Irql);
+
+    return status;
+}
+
 static
 _Function_class_(KSERVICE_ROUTINE)
 __drv_requiresIRQL(HIGH_LEVEL)
@@ -1018,8 +1083,6 @@ EvtchnReset(
     }
 }
 
-
-
 static NTSTATUS
 EvtchnAbiAcquire(
     IN  PXENBUS_EVTCHN_CONTEXT  Context
@@ -1286,6 +1349,11 @@ EvtchnDebugCallback(
             default:
                 break;
             }
+
+            XENBUS_DEBUG(Printf,
+                         &Context->DebugInterface,
+                         "Events = %lu\n",
+                         Channel->Events);
         }
     }
 }
@@ -1597,6 +1665,20 @@ static struct _XENBUS_EVTCHN_INTERFACE_V4 
EvtchnInterfaceVersion4 = {
     EvtchnClose
 };
 
+static struct _XENBUS_EVTCHN_INTERFACE_V5 EvtchnInterfaceVersion5 = {
+    { sizeof (struct _XENBUS_EVTCHN_INTERFACE_V5), 5, NULL, NULL, NULL },
+    EvtchnAcquire,
+    EvtchnRelease,
+    EvtchnOpen,
+    EvtchnBind,
+    EvtchnUnmask,
+    EvtchnSend,
+    EvtchnTrigger,
+    EvtchnWait,
+    EvtchnGetPort,
+    EvtchnClose,
+};
+
 NTSTATUS
 EvtchnInitialize(
     IN  PXENBUS_FDO             Fdo,
@@ -1773,6 +1855,23 @@ EvtchnGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 5: {
+        struct _XENBUS_EVTCHN_INTERFACE_V5  *EvtchnInterface;
+
+        EvtchnInterface = (struct _XENBUS_EVTCHN_INTERFACE_V5 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENBUS_EVTCHN_INTERFACE_V5))
+            break;
+
+        *EvtchnInterface = EvtchnInterfaceVersion5;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;
diff --git a/src/xenbus/store.c b/src/xenbus/store.c
index 16ca37b..c54b0f0 100644
--- a/src/xenbus/store.c
+++ b/src/xenbus/store.c
@@ -131,6 +131,9 @@ struct _XENBUS_STORE_CONTEXT {
     LIST_ENTRY                          WatchList;
     LIST_ENTRY                          BufferList;
     KDPC                                Dpc;
+    ULONG                               Polls;
+    ULONG                               Dpcs;
+    ULONG                               Events;
     XENBUS_STORE_RESPONSE               Response;
     XENBUS_EVTCHN_INTERFACE             EvtchnInterface;
     PHYSICAL_ADDRESS                    Address;
@@ -828,6 +831,8 @@ StorePollLocked(
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
+    Context->Polls++;
+
     do {
         Read = Written = 0;
 
@@ -877,6 +882,13 @@ StoreDpc(
     KeReleaseSpinLockFromDpcLevel(&Context->Lock);
 }
 
+#define TIME_US(_us)        ((_us) * 10)
+#define TIME_MS(_ms)        (TIME_US((_ms) * 1000))
+#define TIME_S(_s)          (TIME_MS((_s) * 1000))
+#define TIME_RELATIVE(_t)   (-(_t))
+
+#define XENBUS_STORE_POLL_PERIOD 5
+
 static PXENBUS_STORE_RESPONSE
 StoreSubmitRequest(
     IN  PXENBUS_STORE_CONTEXT   Context,
@@ -885,6 +897,7 @@ StoreSubmitRequest(
 {
     PXENBUS_STORE_RESPONSE      Response;
     KIRQL                       Irql;
+    LARGE_INTEGER               Timeout;
 
     ASSERT3U(Request->State, ==, XENBUS_STORE_REQUEST_PREPARED);
 
@@ -895,11 +908,25 @@ StoreSubmitRequest(
     KeAcquireSpinLockAtDpcLevel(&Context->Lock);
 
     InsertTailList(&Context->SubmittedList, &Request->ListEntry);
+
     Request->State = XENBUS_STORE_REQUEST_SUBMITTED;
+    StorePollLocked(Context);
+    KeMemoryBarrier();
+
+    Timeout.QuadPart = TIME_RELATIVE(TIME_S(XENBUS_STORE_POLL_PERIOD));
 
     while (Request->State != XENBUS_STORE_REQUEST_COMPLETED) {
+        NTSTATUS    status;
+
+        status = XENBUS_EVTCHN(Wait,
+                               &Context->EvtchnInterface,
+                               Context->Channel,
+                               &Timeout);
+        if (status == STATUS_TIMEOUT)
+            Warning("TIMED OUT\n");
+
         StorePollLocked(Context);
-        SchedYield();
+        KeMemoryBarrier();
     }
 
     KeReleaseSpinLockFromDpcLevel(&Context->Lock);
@@ -1778,13 +1805,14 @@ fail1:
 
 static VOID
 StorePoll(
-    IN  PINTERFACE  Interface
+    IN  PINTERFACE          Interface
     )
 {
-    PXENBUS_STORE_CONTEXT  Context = Interface->Context;
+    PXENBUS_STORE_CONTEXT   Context = Interface->Context;
 
     KeAcquireSpinLockAtDpcLevel(&Context->Lock);
-    StorePollLocked(Context);
+    if (Context->References != 0)
+        StorePollLocked(Context);
     KeReleaseSpinLockFromDpcLevel(&Context->Lock);
 }
 
@@ -1804,7 +1832,10 @@ StoreEvtchnCallback(
 
     ASSERT(Context != NULL);
 
-    KeInsertQueueDpc(&Context->Dpc, NULL, NULL);
+    Context->Events++;
+
+    if (KeInsertQueueDpc(&Context->Dpc, NULL, NULL))
+        Context->Dpcs++;
 
     return TRUE;
 }
@@ -1851,6 +1882,9 @@ StoreEnable(
                   &Context->EvtchnInterface,
                   Context->Channel,
                   FALSE);
+
+    // Trigger an initial poll
+    KeInsertQueueDpc(&Context->Dpc, NULL, NULL);
 }
 
 static PHYSICAL_ADDRESS
@@ -1973,6 +2007,13 @@ StoreDebugCallback(
                      Shared->rsp_prod);
     }
 
+    XENBUS_DEBUG(Printf,
+                 &Context->DebugInterface,
+                 "Events = %lu Dpcs = %lu Polls = %lu\n",
+                 Context->Events,
+                 Context->Dpcs,
+                 Context->Polls);
+
     if (!IsListEmpty(&Context->BufferList)) {
         PLIST_ENTRY ListEntry;
 
@@ -2254,6 +2295,7 @@ StoreRelease(
     XENBUS_SUSPEND(Release, &Context->SuspendInterface);
 
     StoreDisable(Context);
+    StorePollLocked(Context);
     RtlZeroMemory(&Context->Response, sizeof (XENBUS_STORE_RESPONSE));
 
     XENBUS_EVTCHN(Release, &Context->EvtchnInterface);
@@ -2402,6 +2444,10 @@ StoreTeardown(
     ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
     KeFlushQueuedDpcs();
 
+    Context->Polls = 0;
+    Context->Dpcs = 0;
+    Context->Events = 0;
+
     Context->Fdo = NULL;
 
     RtlZeroMemory(&Context->Dpc, sizeof (KDPC));
-- 
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®.