Spin for a bit before falling back to event object

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2019-07-16 16:09:17 +00:00
parent 66e51bd08f
commit 1914547ab3

View File

@ -330,6 +330,7 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock); KIRQL Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
TUN_RING *Ring = Ctx->Device.Receive.Ring; TUN_RING *Ring = Ctx->Device.Receive.Ring;
ULONG RingCapacity = Ctx->Device.Receive.Capacity; ULONG RingCapacity = Ctx->Device.Receive.Capacity;
const ULONG SpinMax = 10000 * 50 / KeQueryTimeIncrement(); /* 50ms */
for (;;) for (;;)
{ {
@ -345,18 +346,40 @@ TunProcessReceiveData(_Inout_ TUN_CTX *Ctx)
ULONG RingTail = InterlockedGetU(&Ring->Tail); ULONG RingTail = InterlockedGetU(&Ring->Tail);
if (RingHead == RingTail) if (RingHead == RingTail)
{ {
InterlockedExchange(&Ring->Alertable, TRUE); ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql);
RingTail = InterlockedGetU(&Ring->Tail); ULONG64 SpinStart;
KeQueryTickCount(&SpinStart);
for (;;)
{
RingTail = InterlockedGetU(&Ring->Tail);
if (RingTail != RingHead)
break;
if (!(InterlockedGet(&Ctx->Flags) & TUN_FLAGS_CONNECTED))
break;
ULONG64 SpinNow;
KeQueryTickCount(&SpinNow);
if (SpinNow - SpinStart >= SpinMax)
break;
/* This should really call KeYieldProcessorEx(&zero), so it does the Hyper-V paravirtualization call,
* but it's not exported. */
YieldProcessor();
}
if (RingHead == RingTail) if (RingHead == RingTail)
{ {
ExReleaseSpinLockShared(&Ctx->TransitionLock, Irql); InterlockedExchange(&Ring->Alertable, TRUE);
KeWaitForSingleObject(Ctx->Device.Receive.TailMoved, Executive, KernelMode, FALSE, NULL); RingTail = InterlockedGetU(&Ring->Tail);
if (RingHead == RingTail)
{
KeWaitForSingleObject(Ctx->Device.Receive.TailMoved, Executive, KernelMode, FALSE, NULL);
InterlockedExchange(&Ring->Alertable, FALSE);
Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
continue;
}
InterlockedExchange(&Ring->Alertable, FALSE); InterlockedExchange(&Ring->Alertable, FALSE);
Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock); KeClearEvent(Ctx->Device.Receive.TailMoved);
continue;
} }
InterlockedExchange(&Ring->Alertable, FALSE); Irql = ExAcquireSpinLockShared(&Ctx->TransitionLock);
KeClearEvent(Ctx->Device.Receive.TailMoved);
} }
if (RingTail >= RingCapacity) if (RingTail >= RingCapacity)
break; break;