Add description of IO_CSQ algorithms
Remove this file when this is done. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
9704a4d11f
commit
ce9936089c
173
csq_psuedo_description.c
Normal file
173
csq_psuedo_description.c
Normal file
@ -0,0 +1,173 @@
|
||||
typedef struct _PACKET_QUEUE {
|
||||
KSPIN_LOCK Lock;
|
||||
NET_BUFFER_LIST *FirstNbl, *LastNbl;
|
||||
volatile NET_BUFFER_LIST *FirstToFree;
|
||||
NET_BUFFER *NextNb;
|
||||
UINT NumNbl;
|
||||
} PACKET_QUEUE, *PPACKET_QUEUE;
|
||||
|
||||
// Annotation: requires Queue->Lock
|
||||
void AddToFreeList(PACKET_QUEUE *Queue, NET_BUFFER_LIST *Nbl)
|
||||
{
|
||||
if (!Queue->FirstToFree)
|
||||
Queue->FirstToFree = Nbl;
|
||||
else {
|
||||
NET_BUFFER_LIST_NEXT_NBL(Nbl) = Queue->FirstToFree;
|
||||
Queue->FirstToFree = Nbl;
|
||||
}
|
||||
--Queue->NumNbl;
|
||||
}
|
||||
|
||||
// Annotation: requires Queue->Lock
|
||||
void FreeFreeList(PACKET_QUEUE *Queue)
|
||||
{
|
||||
NET_BUFFER_LIST *Next;
|
||||
|
||||
while (Queue->FirstToFree) {
|
||||
Next = NET_BUFFER_LIST_NEXT_NBL(Queue->FirstToFree);
|
||||
FreeNbl(Queue->FirstToFree);
|
||||
Queue->FirstToFree = Next;
|
||||
}
|
||||
}
|
||||
|
||||
// Annotation: requires Queue->Lock
|
||||
NET_BUFFER *RemoveFromQueue(PACKET_QUEUE *Queue, NET_BUFFER_LIST **DetachedNbl)
|
||||
{
|
||||
NET_BUFFER_LIST *Top;
|
||||
NET_BUFFER *Ret;
|
||||
|
||||
Top = Queue->FirstNbl;
|
||||
if (!Top)
|
||||
return NULL;
|
||||
if (!Queue->NextNb)
|
||||
Queue->NextNb = NET_BUFFER_LIST_FIRST_NB(Top);
|
||||
Ret = Queue->NextNb;
|
||||
Queue->NextNb = NET_BUFFER_NEXT_NB(Ret);
|
||||
if (!Queue->NextNb) {
|
||||
Queue->FirstNbl = NET_BUFFER_LIST_NEXT_NBL(Top);
|
||||
if (!Queue->FirstNbl)
|
||||
Queue->LastNbl = NULL;
|
||||
NET_BUFFER_LIST_NEXT_NBL(Top) = NULL;
|
||||
AddToFreeList(Queue, Top);
|
||||
if (DetachedNbl)
|
||||
*DetachedNbl = Top;
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// Annotation: requires Queue->Lock
|
||||
void AppendToQueue(PACKET_QUEUE *Queue, NET_BUFFER_LIST *Nbl)
|
||||
{
|
||||
NET_BUFFER_LIST *Next;
|
||||
|
||||
for (; Nbl; Nbl = Next) {
|
||||
Next = NET_BUFFER_LIST_NEXT_NBL(Nbl);
|
||||
if (!NET_BUFFER_LIST_FIRST_NB(Nbl->FirstNb)) {
|
||||
FreeNbl(Nbl);
|
||||
continue;
|
||||
}
|
||||
if (!Queue->FirstNbl)
|
||||
Queue->FirstNbl = Queue->LastNbl = Nbl;
|
||||
else {
|
||||
NET_BUFFER_LIST_NEXT_NBL(Queue->LastNbl) = Nbl;
|
||||
Queue->LastNbl = Nbl;
|
||||
}
|
||||
++Queue->NumNbl;
|
||||
}
|
||||
}
|
||||
|
||||
// Annotation: requires Queue->Lock
|
||||
// Note: Must be called immediately after RemoveFromQueue without dropping Queue->Lock.
|
||||
void PrependToQueue(PACKET_QUEUE *Queue, NET_BUFFER *Nb, NET_BUFFER_LIST *DetachedNbl)
|
||||
{
|
||||
Queue->NextNb = Nb;
|
||||
|
||||
if (!DetachedNbl)
|
||||
return;
|
||||
|
||||
if (DetachedNbl == Queue->FirstToFree)
|
||||
Queue->FirstToFree = NET_BUFFER_LIST_NEXT_NBL(DetachedNbl);
|
||||
|
||||
if (!Queue->FirstNbl)
|
||||
Queue->FirstNbl = Queue->LastNbl = DetachedNbl;
|
||||
else {
|
||||
NET_BUFFER_LIST_NEXT_NBL(DetachedNbl) = Queue->FirstNbl;
|
||||
Queue->FirstNbl = DetachedNbl;
|
||||
}
|
||||
++Queue->NumNbl;
|
||||
}
|
||||
|
||||
// Annotation: requires Queue->Lock
|
||||
void TrimQueueToNItems(PACKET_QUEUE *Queue, UINT MaxNbls)
|
||||
{
|
||||
NET_BUFFER_LIST *Next;
|
||||
|
||||
while (Queue->NumNbl > MaxNbls) {
|
||||
if (!Queue->FirstNbl)
|
||||
return;
|
||||
Next = NET_BUFFER_LIST_NEXT_NBL(Queue->FirstNbl);
|
||||
AddToFreeList(Queue->FirstNbl);
|
||||
Queue->NextNb = NULL;
|
||||
Queue->FirstNbl = Next;
|
||||
if (!Queue->FirstNbl)
|
||||
Queue->LastNbl = NULL;
|
||||
}
|
||||
FreeFreeList(Queue);
|
||||
}
|
||||
|
||||
void TunDispatchRead(IRP *Irp)
|
||||
{
|
||||
IoCsqInsertIrpEx(IoCsq, Irp, NULL, NULL);
|
||||
ProcessQueuedPackets();
|
||||
}
|
||||
|
||||
void ProcessQueuedPackets(void)
|
||||
{
|
||||
IRP *Irp;
|
||||
NET_BUFFER *Nb;
|
||||
KLOCK_QUEUE_HANDLE LockHandle;
|
||||
|
||||
for (;;) {
|
||||
if (!Irp) {
|
||||
NET_BUFFER_LIST *DetachedNbl = NULL;
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
Nb = RemoveFromQueue(Queue, &DetachedNbl);
|
||||
if (!Nb) {
|
||||
KeReleaseInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
return;
|
||||
}
|
||||
Irp = IoCsqRemoveNextIrp(IoCsq, NULL);
|
||||
if (!Irp) {
|
||||
PrependToQueue(Queue, Nb, DetachedNbl);
|
||||
KeReleaseInStackQueuedSpinLock(Queue, &LockHandle);
|
||||
return;
|
||||
}
|
||||
KeReleaseInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
} else {
|
||||
KeAcquireInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
Nb = RemoveFromQueue(Queue, NULL);
|
||||
KeReleaseInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
}
|
||||
if (!Nb || WriteIntoIrp(Irp, Nb) == IRP_HAD_NO_ROOM_FOR_IT) {
|
||||
TunCompleteRequest(Irp, 0, STATUS_SUCCESS);
|
||||
Irp = NULL;
|
||||
}
|
||||
if (Queue->FirstToFree) {
|
||||
KeAcquireInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
FreeFreeList(Queue);
|
||||
KeReleaseInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TunSendNetBufferLists(NET_BUFFER_LIST *Nbl)
|
||||
{
|
||||
KLOCK_QUEUE_HANDLE LockHandle;
|
||||
|
||||
KeAcquireInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
AppendToQueue(Queue, Nbl);
|
||||
TrimQueueToNItems(Queue, 1000);
|
||||
KeReleaseInStackQueuedSpinLock(Queue->Lock, &LockHandle);
|
||||
ProcessQueuedPackets();
|
||||
}
|
Loading…
Reference in New Issue
Block a user