internal AsyncContext CreateContext(SafeHandle handle) { lock (_asyncContexts) { if (_disposed) { ThrowHelper.ThrowObjectDisposedException <EPollThread>(); } EPollAsyncContext context = new EPollAsyncContext(this, handle); // TODO: move this outside lock. _asyncContexts.Add(context.Key, context); return(context); } }
private unsafe void EventLoop() { try { var eventBuffer = stackalloc epoll_event[EventBufferLength]; List <EPollAsyncContext?> asyncContextsForEvents = new List <EPollAsyncContext?>(); bool running = true; int epollTimeout = -1; while (running) { int rv = epoll_wait(_epollFd, eventBuffer, EventBufferLength, epollTimeout); Volatile.Write(ref _blockedState, StateNotBlocked); if (rv == -1) { if (LibC.errno == EINTR) { continue; } PlatformException.Throw(); } lock (_asyncContexts) { for (int i = 0; i < rv; i++) { int key = eventBuffer[i].data.fd; if (_asyncContexts.TryGetValue(key, out EPollAsyncContext? eventContext)) { asyncContextsForEvents.Add(eventContext); } else { if (key == PipeKey) { running = !_disposed; ReadFromPipe(_asyncExecutionQueue); } asyncContextsForEvents.Add(null); } } } for (int i = 0; i < rv; i++) { EPollAsyncContext?context = asyncContextsForEvents[i]; if (context != null) { context.HandleEvents(eventBuffer[i].events); } } asyncContextsForEvents.Clear(); bool actionsRemaining = false; // Run this twice, executions cause more executions. for (int i = 0; i < 2; i++) { // First execute scheduled actions, they can add to the exection queue. ExecuteScheduledActions(); if (_asyncExecutionQueue != null) { actionsRemaining = _asyncExecutionQueue.ExecuteOperations(); } } if (!actionsRemaining) { // Check if there are scheduled actions remaining. lock (_actionQueueGate) { actionsRemaining = _scheduledActions.Count > 0; if (!actionsRemaining) { Volatile.Write(ref _blockedState, StateBlocked); } } } epollTimeout = actionsRemaining ? 0 : -1; } // Execute actions that got posted before we were disposed. ExecuteScheduledActions(); // Complete pending async operations. _asyncExecutionQueue?.Dispose(); EPollAsyncContext[] contexts; lock (_asyncContexts) { contexts = new EPollAsyncContext[_asyncContexts.Count]; _asyncContexts.Values.CopyTo(contexts, 0); _asyncContexts.Clear(); } foreach (var context in contexts) { context.Dispose(); } FreeResources(); } catch (Exception e) { Environment.FailFast(e.ToString()); } }