Repository: dotnet/runtime
File: src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs (C#)

Code before:
                    {
                        throw new InternalException(err);
                    }

                    // The native shim is responsible for ensuring this condition.
                    Debug.Assert(numEvents > 0, $"Unexpected numEvents: {numEvents}");

                    if (handler.HandleSocketEvents(numEvents))
                    {
                        EnsureWorkerScheduled();
                    }
                }
            }
            catch (Exception e)
            {
                Environment.FailFast("Exception thrown from SocketAsyncEngine event loop: " + e.ToString(), e);
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void EnsureWorkerScheduled()
        {
            // Only one thread is requested at a time to mitigate Thundering Herd problem.
            // That is the minimum - we have inserted a workitem and NotScheduled
            // state requires asking for a worker.
            if (Interlocked.Exchange(
                ref _eventQueueProcessingStage,
                EventQueueProcessingStage.Scheduled) == EventQueueProcessingStage.NotScheduled)
            {
                ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false);
            }
        }

        void IThreadPoolWorkItem.Execute()
        {
            _eventQueueProcessingStage = EventQueueProcessingStage.NotScheduled;

            // Checking for items must happen after resetting the processing state.
            Interlocked.MemoryBarrier();

            ConcurrentQueue<SocketIOEvent> eventQueue = _eventQueue;
            if (!eventQueue.TryDequeue(out SocketIOEvent ev))
            {
                return;
            }

            // The batch that is currently in the queue could have asked only for one worker.
            // We are going to process a workitem, which may take unknown time or even block.
            // In a worst case the current workitem will indirectly depend on progress of other
            // items and that would lead to a deadlock if noone else checks the queue.
            // We must ensure at least one more worker is coming if the queue is not empty.

Review comment (bug):
Missing Debug.Assert to verify the queue processing stage is Scheduled before resetting it. For consistency with the other thread pool implementations (ThreadPoolTypedWorkItemQueue at line 1244), consider adding:
```csharp
Debug.Assert(_eventQueueProcessingStage == EventQueueProcessingStage.Scheduled);
```
before line 262.
```suggestion
        {
            Debug.Assert(_eventQueueProcessingStage == EventQueueProcessingStage.Scheduled);
```

Code after:
                    Debug.Assert(numEvents > 0, $"Unexpected numEvents: {numEvents}");

                    if (handler.HandleSocketEvents(numEvents))
                    {
                        EnsureWorkerScheduled();
                    }
                }
            }
            catch (Exception e)
            {
                Environment.FailFast("Exception thrown from SocketAsyncEngine event loop: " + e.ToString(), e);
            }
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void EnsureWorkerScheduled()
        {
            // Only one worker is requested at a time to mitigate Thundering Herd problem.
            if (Interlocked.Exchange(ref _hasOutstandingThreadRequest, 1) == 0)
            {
                ThreadPool.UnsafeQueueUserWorkItem(this, preferLocal: false);
            }
        }

        void IThreadPoolWorkItem.Execute()
        {
            // We are asking for one worker at a time, thus the state should be 1.
            Debug.Assert(_hasOutstandingThreadRequest == 1);
            _hasOutstandingThreadRequest = 0;

            // Checking for items must happen after resetting the processing state.
            Interlocked.MemoryBarrier();

            ConcurrentQueue<SocketIOEvent> eventQueue = _eventQueue;
            if (!eventQueue.TryDequeue(out SocketIOEvent ev))
            {
                return;
            }

            // The batch that is currently in the queue could have asked only for one worker.
            // We are going to process a workitem, which may take unknown time or even block.
            // In a worst case the current workitem will indirectly depend on progress of other
            // items and that would lead to a deadlock if no one else checks the queue.
            // We must ensure at least one more worker is coming if the queue is not empty.
            if (!eventQueue.IsEmpty)
            {
                EnsureWorkerScheduled();
            }

            int startTimeMs = Environment.TickCount;
            do