[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 |