private unsafe void AcceptThreadStart(object state) { try { var socket = _socket; using (socket) { using (EPoll epoll = EPoll.Create()) { int epollFd = epoll.DangerousGetHandle().ToInt32(); const int acceptKey = 0; const int pipeKey = 1; // accept socket epoll.Control(EPollOperation.Add, _socket, EPollEvents.Readable, new EPollData { Int1 = acceptKey, Int2 = acceptKey }); // add pipe epoll.Control(EPollOperation.Add, _pipeEnds.ReadEnd, EPollEvents.Readable, new EPollData { Int1 = pipeKey, Int2 = pipeKey }); const int EventBufferLength = 1; int notPacked = !EPoll.PackedEvents ? 1 : 0; var buffer = stackalloc int[EventBufferLength * (3 + notPacked)]; int * key = &buffer[2]; bool running = true; int nextHandler = 0; var handlers = _handlers; do { int numEvents = EPollInterop.EPollWait(epollFd, buffer, EventBufferLength, timeout: EPoll.TimeoutInfinite).Value; if (numEvents == 1) { if (*key == acceptKey) { var handler = handlers[nextHandler]; nextHandler = (nextHandler + 1) % handlers.Length; socket.TryAcceptAndSendHandleTo(handler); } else { running = false; } } } while (running); } } _stoppedTcs.TrySetResult(null); } catch (Exception e) { _stoppedTcs.SetException(e); } finally { Cleanup(); } }
private unsafe void AcceptThreadStart(object state) { try { var socket = _socket; using (socket) { using (EPoll epoll = EPoll.Create()) { int epollFd = epoll.DangerousGetHandle().ToInt32(); const int acceptKey = 0; const int pipeKey = 1; // accept socket epoll.Control(EPOLL_CTL_ADD, _socket, EPOLLIN, acceptKey); // add pipe epoll.Control(EPOLL_CTL_ADD, _pipeEnds.ReadEnd, EPOLLIN, pipeKey); epoll_event ev; bool running = true; int nextHandler = 0; var handlers = _handlers; do { int numEvents = EPollInterop.EPollWait(epollFd, &ev, 1, timeout: EPoll.TimeoutInfinite).IntValue; if (numEvents == 1) { if (ev.data.fd == acceptKey) { var handler = handlers[nextHandler]; nextHandler = (nextHandler + 1) % handlers.Length; socket.TryAcceptAndSendHandleTo(handler); } else { running = false; } } } while (running); } } _stoppedTcs.TrySetResult(null); } catch (Exception e) { _stoppedTcs.SetException(e); } finally { Cleanup(); } }
public unsafe ThreadContext(TransportThread transportThread) { _transportThread = transportThread; _connectionDispatcher = transportThread.ConnectionDispatcher; _sockets = new Dictionary <int, TSocket>(); _logger = _transportThread.LoggerFactory.CreateLogger($"{nameof(RedHat)}.{nameof(TransportThread)}.{_transportThread.ThreadId}"); _acceptSockets = new List <TSocket>(); _transportOptions = transportThread.TransportOptions; _scheduledSendAdding = new List <ScheduledSend>(1024); _scheduledSendRunning = new List <ScheduledSend>(1024); _epollState = EPollBlocked; if (_transportOptions.AioReceive | _transportOptions.AioSend) { _aioEventsMemory = AllocMemory(sizeof(io_event) * EventBufferLength); _aioCbsMemory = AllocMemory(sizeof(iocb) * EventBufferLength); _aioCbsTableMemory = AllocMemory(IntPtr.Size * EventBufferLength); _ioVectorTableMemory = AllocMemory(SizeOf.iovec * IoVectorsPerAioSocket * EventBufferLength); for (int i = 0; i < EventBufferLength; i++) { AioCbsTable[i] = &AioCbs[i]; } if (_transportOptions.AioSend) { _aioSendBuffers = new ReadOnlySequence <byte> [EventBufferLength]; } } int maxMemoryHandleCount = TSocket.MaxIOVectorReceiveLength; if (_transportOptions.AioReceive || _transportOptions.AioSend) { maxMemoryHandleCount = Math.Max(maxMemoryHandleCount, EventBufferLength); } if (_transportOptions.DeferSend) { maxMemoryHandleCount = Math.Max(maxMemoryHandleCount, TSocket.MaxIOVectorSendLength); } MemoryHandles = new MemoryHandle[maxMemoryHandleCount]; // These members need to be Disposed _epoll = EPoll.Create(); _epollFd = _epoll.DangerousGetHandle().ToInt32(); MemoryPool = CreateMemoryPool(); _pipeEnds = PipeEnd.CreatePair(blocking: false); if (_aioEventsMemory != IntPtr.Zero) { aio_context_t ctx; AioInterop.IoSetup(EventBufferLength, &ctx).ThrowOnError(); _aioContext = ctx; } }
public static PosixResult EPollCreate(out EPoll epoll) { epoll = new EPoll(); int rv = epoll_create1(EPOLL_CLOEXEC); if (rv == -1) { epoll = null; } else { epoll.SetHandle(rv); } return(PosixResult.FromReturnValue(rv)); }
public static PosixResult EPollControl(EPoll epoll, int operation, SafeHandle fd, int events, int data) => EPollControl(epoll.DangerousGetHandle().ToInt32(), operation, fd.DangerousGetHandle().ToInt32(), events, data);
public static unsafe PosixResult EPollWait(EPoll epoll, epoll_event *events, int maxEvents, int timeout) => EPollWait(epoll.DangerousGetHandle().ToInt32(), events, maxEvents, timeout);
public unsafe ThreadContext(TransportThread transportThread) { _transportThread = transportThread; _sockets = new Dictionary <int, TSocket>(); _logger = _transportThread.LoggerFactory.CreateLogger($"{nameof(RedHat)}.{nameof(TransportThread)}.{_transportThread.ThreadId}"); _acceptSockets = new List <TSocket>(); _transportOptions = transportThread.TransportOptions; _scheduledSendAdding = new List <ScheduledSend>(1024); _scheduledSendRunning = new List <ScheduledSend>(1024); _epollState = EPollBlocked; if (_transportOptions.AioReceive | _transportOptions.AioSend) { _aioEventsMemory = AllocMemory(sizeof(io_event) * EventBufferLength); _aioCbsMemory = AllocMemory(sizeof(iocb) * EventBufferLength); _aioCbsTableMemory = AllocMemory(IntPtr.Size * EventBufferLength); _ioVectorTableMemory = AllocMemory(SizeOf.iovec * IoVectorsPerAioSocket * EventBufferLength); for (int i = 0; i < EventBufferLength; i++) { AioCbsTable[i] = &AioCbs[i]; } if (_transportOptions.AioSend) { _aioSendBuffers = new ReadOnlySequence <byte> [EventBufferLength]; } } int maxMemoryHandleCount = TSocket.MaxIOVectorReceiveLength; if (_transportOptions.AioReceive || _transportOptions.AioSend) { maxMemoryHandleCount = Math.Max(maxMemoryHandleCount, EventBufferLength); } if (_transportOptions.DeferSend) { maxMemoryHandleCount = Math.Max(maxMemoryHandleCount, TSocket.MaxIOVectorSendLength); } MemoryHandles = new MemoryHandle[maxMemoryHandleCount]; // These members need to be Disposed _epoll = EPoll.Create(); _epollFd = _epoll.DangerousGetHandle().ToInt32(); MemoryPool = CreateMemoryPool(); _pipeEnds = PipeEnd.CreatePair(blocking: false); if (_aioEventsMemory != IntPtr.Zero) { aio_context_t ctx; AioInterop.IoSetup(EventBufferLength, &ctx).ThrowOnError(); _aioContext = ctx; } // Single reader, single writer queue since all writes happen from the TransportThread and reads happen sequentially // This channel is unbounded which means there's nothing limiting the number of sockets we're accepting. // This is similar to having an unbounded number of thread pool work items queued to invoke a ConnectionHandler // which was the previous pattern, but now it's more explicit. // TODO: Find a reasonable limit and start applying accept backpressure once the channel reaches that limit. _acceptQueue = Channel.CreateUnbounded <TSocket>(new UnboundedChannelOptions { SingleReader = true, SingleWriter = true, AllowSynchronousContinuations = _transportOptions.ApplicationSchedulingMode == PipeScheduler.Inline, }); }
public static extern PosixResult EPollCreate(out EPoll epoll);
public static PosixResult EPollControl(EPoll epoll, EPollOperation operation, SafeHandle fd, EPollEvents events, long data) => EPollControl(epoll.DangerousGetHandle().ToInt32(), operation, fd.DangerousGetHandle().ToInt32(), events, data);