Пример #1
0
        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;
                }
            }
Пример #4
0
        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));
        }
Пример #5
0
 public static PosixResult EPollControl(EPoll epoll, int operation, SafeHandle fd, int events, int data)
 => EPollControl(epoll.DangerousGetHandle().ToInt32(), operation, fd.DangerousGetHandle().ToInt32(), events, data);
Пример #6
0
 public static unsafe PosixResult EPollWait(EPoll epoll, epoll_event *events, int maxEvents, int timeout)
 => EPollWait(epoll.DangerousGetHandle().ToInt32(), events, maxEvents, timeout);
Пример #7
0
            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,
                });
            }
Пример #8
0
 public static extern PosixResult EPollCreate(out EPoll epoll);
Пример #9
0
 public static PosixResult EPollControl(EPoll epoll, EPollOperation operation, SafeHandle fd, EPollEvents events, long data)
 => EPollControl(epoll.DangerousGetHandle().ToInt32(), operation, fd.DangerousGetHandle().ToInt32(), events, data);