private unsafe void AioReceive(List <TSocket> readableSockets) { long PackReceiveState(int received, int advanced, int iovLength) => ((long)received << 32) + (advanced << 8) + (iovLength); (int received, int advanced, int iovLength) UnpackReceiveState(long data) => ((int)(data >> 32), (int)((data >> 8) & 0xffffff), (int)(data & 0xff)); int readableSocketCount = readableSockets.Count; AioCb * aioCb = AioCbs; IOVector * ioVectors = IoVectorTable; PosixResult * receiveResults = stackalloc PosixResult[readableSocketCount]; Span <MemoryHandle> receiveMemoryHandles = MemoryHandles; int receiveMemoryHandleCount = 0; for (int i = 0; i < readableSocketCount; i++) { TSocket socket = readableSockets[i]; var memoryAllocation = socket.DetermineMemoryAllocationForReceive(IoVectorsPerAioSocket); int advanced = socket.FillReceiveIOVector(memoryAllocation, ioVectors, receiveMemoryHandles); aioCb->Fd = socket.Fd; aioCb->Data = PackReceiveState(0, advanced, memoryAllocation.IovLength); aioCb->OpCode = AioOpCode.PReadv; aioCb->Buffer = ioVectors; aioCb->Length = memoryAllocation.IovLength; aioCb++; ioVectors += memoryAllocation.IovLength; receiveMemoryHandleCount += memoryAllocation.IovLength; receiveMemoryHandles = receiveMemoryHandles.Slice(memoryAllocation.IovLength); } int eAgainCount = 0; while (readableSocketCount > 0) { IntPtr ctxp = _aioContext; PosixResult res = AioInterop.IoSubmit(ctxp, readableSocketCount, AioCbsTable); if (res != readableSocketCount) { throw new NotSupportedException("Unexpected IoSubmit retval " + res); } AioEvent *aioEvents = AioEvents; res = AioInterop.IoGetEvents(ctxp, readableSocketCount, aioEvents); if (res != readableSocketCount) { throw new NotSupportedException("Unexpected IoGetEvents retval " + res); } int socketsRemaining = readableSocketCount; bool allEAgain = true; AioEvent *aioEvent = aioEvents; for (int i = 0; i < readableSocketCount; i++) { PosixResult result = aioEvent->Result; int socketIndex = i; // assumes in-order events TSocket socket = readableSockets[socketIndex]; (int received, int advanced, int iovLength) = UnpackReceiveState(aioEvent->Data); (bool done, PosixResult retval) = socket.InterpretReceiveResult(result, ref received, advanced, (IOVector *)aioEvent->AioCb->Buffer, iovLength); if (done) { receiveResults[socketIndex] = retval; socketsRemaining--; aioEvent->AioCb->OpCode = AioOpCode.Noop; allEAgain = false; } else if (retval != PosixResult.EAGAIN) { aioEvent->AioCb->Data = PackReceiveState(received, advanced, iovLength); allEAgain = false; } aioEvent++; } if (socketsRemaining > 0) { if (allEAgain) { eAgainCount++; if (eAgainCount == TransportConstants.MaxEAgainCount) { throw new NotSupportedException("Too many EAGAIN, unable to receive available bytes."); } } else { aioCb = AioCbs; AioCb *aioCbWriteAt = aioCb; // The kernel doesn't handle Noop, we need to remove them from the aioCbs for (int i = 0; i < readableSocketCount; i++) { if (aioCb[i].OpCode != AioOpCode.Noop) { if (aioCbWriteAt != aioCb) { *aioCbWriteAt = *aioCb; } aioCbWriteAt++; } aioCb++; } readableSocketCount = socketsRemaining; eAgainCount = 0; } } else { readableSocketCount = 0; } } receiveMemoryHandles = MemoryHandles; for (int i = 0; i < receiveMemoryHandleCount; i++) { receiveMemoryHandles[i].Dispose(); } for (int i = 0; i < readableSockets.Count; i++) { readableSockets[i].OnReceiveFromSocket(receiveResults[i]); } readableSockets.Clear(); }