|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |