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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
            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.
                    }
                }
            }
Example #5
0
        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);
 }