private bool ConfirmShutdownSlow() { if (!InEventLoop) { ThrowHelper.ThrowInvalidOperationException_Must_be_invoked_from_an_event_loop(); } CancelScheduledTasks(); if (0ul >= (ulong)_gracefulShutdownStartTime) { _gracefulShutdownStartTime = GetTimeFromStart(); } if (RunAllTasks() || RunShutdownHooks()) { if (IsShutdown) { // Executor shut down - no new tasks anymore. return(true); } // There were tasks in the queue. Wait a little bit more until no tasks are queued for the quiet period or // terminate if the quiet period is 0. // See https://github.com/netty/netty/issues/4241 if (0ul >= (ulong)Volatile.Read(ref v_gracefulShutdownQuietPeriod)) { return(true); } _taskQueue.TryEnqueue(WakeupTask); return(false); } long nanoTime = GetTimeFromStart(); if (IsShutdown || (nanoTime - _gracefulShutdownStartTime > Volatile.Read(ref v_gracefulShutdownTimeout))) { return(true); } if (nanoTime - _lastExecutionTime <= Volatile.Read(ref v_gracefulShutdownQuietPeriod)) { // Check if any tasks were added to the queue every 100ms. // TODO: Change the behavior of takeTask() so that it returns on timeout. _taskQueue.TryEnqueue(WakeupTask); Thread.Sleep(100); return(false); } // No tasks were added for last quiet period - hopefully safe to shut down. // (Hopefully because we really cannot make a guarantee that there will be no execute() calls by a user.) return(true); }
protected bool ConfirmShutdownSlow() { Debug.Assert(InEventLoop, "must be invoked from an event loop"); CancelScheduledTasks(); if (_gracefulShutdownStartTime == PreciseTimeSpan.Zero) { _gracefulShutdownStartTime = PreciseTimeSpan.FromStart; } if (RunAllTasks() || RunShutdownHooks()) { if (IsShutdown) { // Executor shut down - no new tasks anymore. return(true); } // There were tasks in the queue. Wait a little bit more until no tasks are queued for the quiet period or // terminate if the quiet period is 0. // See https://github.com/netty/netty/issues/4241 if (_gracefulShutdownQuietPeriod == PreciseTimeSpan.Zero) { return(true); } WakeUp(true); return(false); } PreciseTimeSpan nanoTime = PreciseTimeSpan.FromStart; if (IsShutdown || (nanoTime - _gracefulShutdownStartTime > _gracefulShutdownTimeout)) { return(true); } if (nanoTime - _lastExecutionTime <= _gracefulShutdownQuietPeriod) { // Check if any tasks were added to the queue every 100ms. // TODO: Change the behavior of takeTask() so that it returns on timeout. // todo: ??? WakeUp(true); Thread.Sleep(100); return(false); } // No tasks were added for last quiet period - hopefully safe to shut down. // (Hopefully because we really cannot make a guarantee that there will be no execute() calls by a user.) return(true); }
protected bool ConfirmShutdown() { if (!this.IsShuttingDown) { return(false); } Contract.Assert(this.InEventLoop, "must be invoked from an event loop"); this.CancelScheduledTasks(); if (this.gracefulShutdownStartTime == PreciseTimeSpan.Zero) { this.gracefulShutdownStartTime = PreciseTimeSpan.FromStart; } if (this.RunAllTasks() || this.RunShutdownHooks()) { if (this.IsShutdown) { // Executor shut down - no new tasks anymore. return(true); } // There were tasks in the queue. Wait a little bit more until no tasks are queued for the quiet period. this.WakeUp(true); return(false); } PreciseTimeSpan nanoTime = PreciseTimeSpan.FromStart; if (this.IsShutdown || (nanoTime - this.gracefulShutdownStartTime > this.gracefulShutdownTimeout)) { return(true); } if (nanoTime - this.lastExecutionTime <= this.gracefulShutdownQuietPeriod) { // Check if any tasks were added to the queue every 100ms. // TODO: Change the behavior of takeTask() so that it returns on timeout. // todo: ??? this.WakeUp(true); Thread.Sleep(100); return(false); } // No tasks were added for last quiet period - hopefully safe to shut down. // (Hopefully because we really cannot make a guarantee that there will be no execute() calls by a user.) return(true); }
public void Run() { for (;;) { this.FetchWatchees(); this.NotifyWatchees(); // Try once again just in case notifyWatchees() triggered watch() or unwatch(). this.FetchWatchees(); this.NotifyWatchees(); Thread.Sleep(1000); if (this.watchees.Count == 0 && PendingEntries.IsEmpty) { // Mark the current worker thread as stopped. // The following CAS must always success and must be uncontended, // because only one watcher thread should be running at the same time. bool stopped = Interlocked.CompareExchange(ref started, 0, 1) == 1; Contract.Assert(stopped); // Check if there are pending entries added by watch() while we do CAS above. if (PendingEntries.IsEmpty) { // A) watch() was not invoked and thus there's nothing to handle // -> safe to terminate because there's nothing left to do // B) a new watcher thread started and handled them all // -> safe to terminate the new watcher thread will take care the rest break; } // There are pending entries again, added by watch() if (Interlocked.CompareExchange(ref started, 1, 0) != 0) { // watch() started a new watcher thread and set 'started' to true. // -> terminate this thread so that the new watcher reads from pendingEntries exclusively. break; } // watch() added an entry, but this worker was faster to set 'started' to true. // i.e. a new watcher thread was not started // -> keep this thread alive to handle the newly added entries. } } }
public async Task TestStagedExecution() { IEventLoopGroup l = new DefaultEventLoopGroup(4, new DefaultThreadFactory("l")); IEventExecutorGroup e1 = new DefaultEventExecutorGroup(4, new DefaultThreadFactory("e1")); IEventExecutorGroup e2 = new DefaultEventExecutorGroup(4, new DefaultThreadFactory("e2")); ThreadNameAuditor h1 = new ThreadNameAuditor(); ThreadNameAuditor h2 = new ThreadNameAuditor(); ThreadNameAuditor h3 = new ThreadNameAuditor(true); IChannel ch = new LocalChannel(); // With no EventExecutor specified, h1 will be always invoked by EventLoop 'l'. ch.Pipeline.AddLast(h1); // h2 will be always invoked by EventExecutor 'e1'. ch.Pipeline.AddLast(e1, h2); // h3 will be always invoked by EventExecutor 'e2'. ch.Pipeline.AddLast(e2, h3); await l.RegisterAsync(ch); await ch.ConnectAsync(_localAddr); // Fire inbound events from all possible starting points. ch.Pipeline.FireChannelRead("1"); ch.Pipeline.Context(h1).FireChannelRead("2"); ch.Pipeline.Context(h2).FireChannelRead("3"); ch.Pipeline.Context(h3).FireChannelRead("4"); // Fire outbound events from all possible starting points. ch.Pipeline.WriteAsync("5").Ignore(); ch.Pipeline.Context(h3).WriteAsync("6").Ignore(); ch.Pipeline.Context(h2).WriteAsync("7").Ignore(); await ch.Pipeline.Context(h1).WriteAndFlushAsync("8"); await ch.CloseAsync(); // Wait until all events are handled completely. while (h1._outboundThreadNames.Count < 3 || h3._inboundThreadNames.Count < 3 || h1._removalThreadNames.Count < 1) { if (h1._exception.Value != null) { throw h1._exception.Value; } if (h2._exception.Value != null) { throw h2._exception.Value; } if (h3._exception.Value != null) { throw h3._exception.Value; } Thread.Sleep(10); } string currentName = Thread.CurrentThread.Name; try { // Events should never be handled from the current thread. Assert.DoesNotContain(currentName, h1._inboundThreadNames); Assert.DoesNotContain(currentName, h2._inboundThreadNames); Assert.DoesNotContain(currentName, h3._inboundThreadNames); Assert.DoesNotContain(currentName, h1._outboundThreadNames); Assert.DoesNotContain(currentName, h2._outboundThreadNames); Assert.DoesNotContain(currentName, h3._outboundThreadNames); Assert.DoesNotContain(currentName, h1._removalThreadNames); Assert.DoesNotContain(currentName, h2._removalThreadNames); Assert.DoesNotContain(currentName, h3._removalThreadNames); // Assert that events were handled by the correct executor. foreach (string name in h1._inboundThreadNames) { Assert.StartsWith("l-", name); } foreach (string name in h2._inboundThreadNames) { Assert.StartsWith("e1-", name); } foreach (string name in h3._inboundThreadNames) { Assert.StartsWith("e2-", name); } foreach (string name in h1._outboundThreadNames) { Assert.StartsWith("l-", name); } foreach (string name in h2._outboundThreadNames) { Assert.StartsWith("e1-", name); } foreach (string name in h3._outboundThreadNames) { Assert.StartsWith("e2-", name); } foreach (string name in h1._removalThreadNames) { Assert.StartsWith("l-", name); } foreach (string name in h2._removalThreadNames) { Assert.StartsWith("e1-", name); } foreach (string name in h3._removalThreadNames) { Assert.StartsWith("e2-", name); } // Assert that the events for the same handler were handled by the same thread. HashSet <string> names = new HashSet <string>(); names.UnionWith(h1._inboundThreadNames); names.UnionWith(h1._outboundThreadNames); names.UnionWith(h1._removalThreadNames); Assert.Single(names); names.Clear(); names.UnionWith(h2._inboundThreadNames); names.UnionWith(h2._outboundThreadNames); names.UnionWith(h2._removalThreadNames); Assert.Single(names); names.Clear(); names.UnionWith(h3._inboundThreadNames); names.UnionWith(h3._outboundThreadNames); names.UnionWith(h3._removalThreadNames); Assert.Single(names); // Count the number of events Assert.Single(h1._inboundThreadNames); Assert.Equal(2, h2._inboundThreadNames.Count); Assert.Equal(3, h3._inboundThreadNames.Count); Assert.Equal(3, h1._outboundThreadNames.Count); Assert.Equal(2, h2._outboundThreadNames.Count); Assert.Single(h3._outboundThreadNames); Assert.Single(h1._removalThreadNames); Assert.Single(h2._removalThreadNames); Assert.Single(h3._removalThreadNames); } catch (Exception) { //System.out.println("H1I: " + h1.inboundThreadNames); //System.out.println("H2I: " + h2.inboundThreadNames); //System.out.println("H3I: " + h3.inboundThreadNames); //System.out.println("H1O: " + h1.outboundThreadNames); //System.out.println("H2O: " + h2.outboundThreadNames); //System.out.println("H3O: " + h3.outboundThreadNames); //System.out.println("H1R: " + h1.removalThreadNames); //System.out.println("H2R: " + h2.removalThreadNames); //System.out.println("H3R: " + h3.removalThreadNames); throw; } finally { Task.WaitAll( l.ShutdownGracefullyAsync(), e1.ShutdownGracefullyAsync(), e2.ShutdownGracefullyAsync()); } }
protected virtual void TaskDelay(int millisecondsTimeout) { Thread.Sleep(millisecondsTimeout); }