public void Start(Func<SynchronizationContext> syncContext, int concurrentAccepts, int maxDelayMS = 0) { if (concurrentAccepts <= 0) { throw new ArgumentOutOfRangeException("concurrentAccepts", "Expected >0 concurrent accepts"); } m_logger.Info("Listening on {0} with {1} concurrent accepts", m_listener.Prefixes.First(), concurrentAccepts); m_listener.Start(); for (var i = 0; i < concurrentAccepts; i++) { var context = syncContext(); var state = new EventLoopState(maxDelayMS); Task.Run(() => MainLoop(context, state)); if (maxDelayMS > 0 && context is EventLoopContext) Task.Run(() => CalcDelay(context, state)); } }
private async Task MainLoop(SynchronizationContext syncContext, EventLoopState state) { while (true) { try { HttpListenerContext context; try { context = await m_listener.GetContextAsync(); } catch (ObjectDisposedException) { return; } catch (HttpListenerException ex) { // IO error due to our request, means we're probably exiting if (ex.NativeErrorCode == 995) continue; throw; } m_resetEvent.Wait(); syncContext.Post(async unused => { var wrapper = new Context(context); wrapper.Response.KeepAlive = m_keepAlive && wrapper.Request.KeepAlive; await m_processor.Process(wrapper, state.Delay > state.MaxDelay); }, null); } catch (Exception ex) { m_logger.Error("Error in accept loop: " + ex); } } }
private void CalcDelay(SynchronizationContext context, EventLoopState state) { context.Post(async unused => { var timer = Stopwatch.StartNew(); while (true) { // Yield back to the event loop await Task.Yield(); // Find out how long it took for the event loop to handle our request var elapsed = (int)timer.ElapsedMilliseconds; state.Delay = elapsed; await Task.Delay(Math.Max(0, 500 - elapsed)); timer.Restart(); } }, null); }