View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.util.concurrent;
17  
18  import io.netty.util.internal.ObjectUtil;
19  import io.netty.util.internal.PlatformDependent;
20  import io.netty.util.internal.SystemPropertyUtil;
21  import io.netty.util.internal.ThreadExecutorMap;
22  import io.netty.util.internal.logging.InternalLogger;
23  import io.netty.util.internal.logging.InternalLoggerFactory;
24  import org.jetbrains.annotations.Async.Schedule;
25  
26  import java.lang.Thread.State;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Queue;
32  import java.util.Set;
33  import java.util.concurrent.BlockingQueue;
34  import java.util.concurrent.Callable;
35  import java.util.concurrent.CountDownLatch;
36  import java.util.concurrent.ExecutionException;
37  import java.util.concurrent.Executor;
38  import java.util.concurrent.LinkedBlockingQueue;
39  import java.util.concurrent.RejectedExecutionException;
40  import java.util.concurrent.ThreadFactory;
41  import java.util.concurrent.TimeUnit;
42  import java.util.concurrent.TimeoutException;
43  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
44  import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
45  
46  /**
47   * Abstract base class for {@link OrderedEventExecutor}'s that execute all its submitted tasks in a single thread.
48   *
49   */
50  public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
51  
52      static final int DEFAULT_MAX_PENDING_EXECUTOR_TASKS = Math.max(16,
53              SystemPropertyUtil.getInt("io.netty.eventexecutor.maxPendingTasks", Integer.MAX_VALUE));
54  
55      private static final InternalLogger logger =
56              InternalLoggerFactory.getInstance(SingleThreadEventExecutor.class);
57  
58      private static final int ST_NOT_STARTED = 1;
59      private static final int ST_STARTED = 2;
60      private static final int ST_SHUTTING_DOWN = 3;
61      private static final int ST_SHUTDOWN = 4;
62      private static final int ST_TERMINATED = 5;
63  
64      private static final Runnable NOOP_TASK = new Runnable() {
65          @Override
66          public void run() {
67              // Do nothing.
68          }
69      };
70  
71      private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
72              AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
73      private static final AtomicReferenceFieldUpdater<SingleThreadEventExecutor, ThreadProperties> PROPERTIES_UPDATER =
74              AtomicReferenceFieldUpdater.newUpdater(
75                      SingleThreadEventExecutor.class, ThreadProperties.class, "threadProperties");
76  
77      private final Queue<Runnable> taskQueue;
78  
79      private volatile Thread thread;
80      @SuppressWarnings("unused")
81      private volatile ThreadProperties threadProperties;
82      private final Executor executor;
83      private volatile boolean interrupted;
84  
85      private final CountDownLatch threadLock = new CountDownLatch(1);
86      private final Set<Runnable> shutdownHooks = new LinkedHashSet<Runnable>();
87      private final boolean addTaskWakesUp;
88      private final int maxPendingTasks;
89      private final RejectedExecutionHandler rejectedExecutionHandler;
90  
91      private long lastExecutionTime;
92  
93      @SuppressWarnings({ "FieldMayBeFinal", "unused" })
94      private volatile int state = ST_NOT_STARTED;
95  
96      private volatile long gracefulShutdownQuietPeriod;
97      private volatile long gracefulShutdownTimeout;
98      private long gracefulShutdownStartTime;
99  
100     private final Promise<?> terminationFuture = new DefaultPromise<Void>(GlobalEventExecutor.INSTANCE);
101 
102     /**
103      * Create a new instance
104      *
105      * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
106      * @param threadFactory     the {@link ThreadFactory} which will be used for the used {@link Thread}
107      * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
108      *                          executor thread
109      */
110     protected SingleThreadEventExecutor(
111             EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {
112         this(parent, new ThreadPerTaskExecutor(threadFactory), addTaskWakesUp);
113     }
114 
115     /**
116      * Create a new instance
117      *
118      * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
119      * @param threadFactory     the {@link ThreadFactory} which will be used for the used {@link Thread}
120      * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
121      *                          executor thread
122      * @param maxPendingTasks   the maximum number of pending tasks before new tasks will be rejected.
123      * @param rejectedHandler   the {@link RejectedExecutionHandler} to use.
124      */
125     protected SingleThreadEventExecutor(
126             EventExecutorGroup parent, ThreadFactory threadFactory,
127             boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
128         this(parent, new ThreadPerTaskExecutor(threadFactory), addTaskWakesUp, maxPendingTasks, rejectedHandler);
129     }
130 
131     /**
132      * Create a new instance
133      *
134      * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
135      * @param executor          the {@link Executor} which will be used for executing
136      * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
137      *                          executor thread
138      */
139     protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp) {
140         this(parent, executor, addTaskWakesUp, DEFAULT_MAX_PENDING_EXECUTOR_TASKS, RejectedExecutionHandlers.reject());
141     }
142 
143     /**
144      * Create a new instance
145      *
146      * @param parent            the {@link EventExecutorGroup} which is the parent of this instance and belongs to it
147      * @param executor          the {@link Executor} which will be used for executing
148      * @param addTaskWakesUp    {@code true} if and only if invocation of {@link #addTask(Runnable)} will wake up the
149      *                          executor thread
150      * @param maxPendingTasks   the maximum number of pending tasks before new tasks will be rejected.
151      * @param rejectedHandler   the {@link RejectedExecutionHandler} to use.
152      */
153     protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
154                                         boolean addTaskWakesUp, int maxPendingTasks,
155                                         RejectedExecutionHandler rejectedHandler) {
156         super(parent);
157         this.addTaskWakesUp = addTaskWakesUp;
158         this.maxPendingTasks = Math.max(16, maxPendingTasks);
159         this.executor = ThreadExecutorMap.apply(executor, this);
160         taskQueue = newTaskQueue(this.maxPendingTasks);
161         rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
162     }
163 
164     protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
165                                         boolean addTaskWakesUp, Queue<Runnable> taskQueue,
166                                         RejectedExecutionHandler rejectedHandler) {
167         super(parent);
168         this.addTaskWakesUp = addTaskWakesUp;
169         this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS;
170         this.executor = ThreadExecutorMap.apply(executor, this);
171         this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue");
172         this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
173     }
174 
175     /**
176      * @deprecated Please use and override {@link #newTaskQueue(int)}.
177      */
178     @Deprecated
179     protected Queue<Runnable> newTaskQueue() {
180         return newTaskQueue(maxPendingTasks);
181     }
182 
183     /**
184      * Create a new {@link Queue} which will holds the tasks to execute. This default implementation will return a
185      * {@link LinkedBlockingQueue} but if your sub-class of {@link SingleThreadEventExecutor} will not do any blocking
186      * calls on the this {@link Queue} it may make sense to {@code @Override} this and return some more performant
187      * implementation that does not support blocking operations at all.
188      */
189     protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
190         return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
191     }
192 
193     /**
194      * Interrupt the current running {@link Thread}.
195      */
196     protected void interruptThread() {
197         Thread currentThread = thread;
198         if (currentThread == null) {
199             interrupted = true;
200         } else {
201             currentThread.interrupt();
202         }
203     }
204 
205     /**
206      * @see Queue#poll()
207      */
208     protected Runnable pollTask() {
209         assert inEventLoop();
210         return pollTaskFrom(taskQueue);
211     }
212 
213     protected static Runnable pollTaskFrom(Queue<Runnable> taskQueue) {
214         for (;;) {
215             Runnable task = taskQueue.poll();
216             if (task != WAKEUP_TASK) {
217                 return task;
218             }
219         }
220     }
221 
222     /**
223      * Take the next {@link Runnable} from the task queue and so will block if no task is currently present.
224      * <p>
225      * Be aware that this method will throw an {@link UnsupportedOperationException} if the task queue, which was
226      * created via {@link #newTaskQueue()}, does not implement {@link BlockingQueue}.
227      * </p>
228      *
229      * @return {@code null} if the executor thread has been interrupted or waken up.
230      */
231     protected Runnable takeTask() {
232         assert inEventLoop();
233         if (!(taskQueue instanceof BlockingQueue)) {
234             throw new UnsupportedOperationException();
235         }
236 
237         BlockingQueue<Runnable> taskQueue = (BlockingQueue<Runnable>) this.taskQueue;
238         for (;;) {
239             ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
240             if (scheduledTask == null) {
241                 Runnable task = null;
242                 try {
243                     task = taskQueue.take();
244                     if (task == WAKEUP_TASK) {
245                         task = null;
246                     }
247                 } catch (InterruptedException e) {
248                     // Ignore
249                 }
250                 return task;
251             } else {
252                 long delayNanos = scheduledTask.delayNanos();
253                 Runnable task = null;
254                 if (delayNanos > 0) {
255                     try {
256                         task = taskQueue.poll(delayNanos, TimeUnit.NANOSECONDS);
257                     } catch (InterruptedException e) {
258                         // Waken up.
259                         return null;
260                     }
261                 }
262                 if (task == null) {
263                     // We need to fetch the scheduled tasks now as otherwise there may be a chance that
264                     // scheduled tasks are never executed if there is always one task in the taskQueue.
265                     // This is for example true for the read task of OIO Transport
266                     // See https://github.com/netty/netty/issues/1614
267                     fetchFromScheduledTaskQueue();
268                     task = taskQueue.poll();
269                 }
270 
271                 if (task != null) {
272                     if (task == WAKEUP_TASK) {
273                         return null;
274                     }
275                     return task;
276                 }
277             }
278         }
279     }
280 
281     private boolean fetchFromScheduledTaskQueue() {
282         if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
283             return true;
284         }
285         long nanoTime = getCurrentTimeNanos();
286         for (;;) {
287             Runnable scheduledTask = pollScheduledTask(nanoTime);
288             if (scheduledTask == null) {
289                 return true;
290             }
291             if (!taskQueue.offer(scheduledTask)) {
292                 // No space left in the task queue add it back to the scheduledTaskQueue so we pick it up again.
293                 scheduledTaskQueue.add((ScheduledFutureTask<?>) scheduledTask);
294                 return false;
295             }
296         }
297     }
298 
299     /**
300      * @return {@code true} if at least one scheduled task was executed.
301      */
302     private boolean executeExpiredScheduledTasks() {
303         if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
304             return false;
305         }
306         long nanoTime = getCurrentTimeNanos();
307         Runnable scheduledTask = pollScheduledTask(nanoTime);
308         if (scheduledTask == null) {
309             return false;
310         }
311         do {
312             safeExecute(scheduledTask);
313         } while ((scheduledTask = pollScheduledTask(nanoTime)) != null);
314         return true;
315     }
316 
317     /**
318      * @see Queue#peek()
319      */
320     protected Runnable peekTask() {
321         assert inEventLoop();
322         return taskQueue.peek();
323     }
324 
325     /**
326      * @see Queue#isEmpty()
327      */
328     protected boolean hasTasks() {
329         assert inEventLoop();
330         return !taskQueue.isEmpty();
331     }
332 
333     /**
334      * Return the number of tasks that are pending for processing.
335      */
336     public int pendingTasks() {
337         return taskQueue.size();
338     }
339 
340     /**
341      * Add a task to the task queue, or throws a {@link RejectedExecutionException} if this instance was shutdown
342      * before.
343      */
344     protected void addTask(Runnable task) {
345         ObjectUtil.checkNotNull(task, "task");
346         if (!offerTask(task)) {
347             reject(task);
348         }
349     }
350 
351     final boolean offerTask(Runnable task) {
352         if (isShutdown()) {
353             reject();
354         }
355         return taskQueue.offer(task);
356     }
357 
358     /**
359      * @see Queue#remove(Object)
360      */
361     protected boolean removeTask(Runnable task) {
362         return taskQueue.remove(ObjectUtil.checkNotNull(task, "task"));
363     }
364 
365     /**
366      * Poll all tasks from the task queue and run them via {@link Runnable#run()} method.
367      *
368      * @return {@code true} if and only if at least one task was run
369      */
370     protected boolean runAllTasks() {
371         assert inEventLoop();
372         boolean fetchedAll;
373         boolean ranAtLeastOne = false;
374 
375         do {
376             fetchedAll = fetchFromScheduledTaskQueue();
377             if (runAllTasksFrom(taskQueue)) {
378                 ranAtLeastOne = true;
379             }
380         } while (!fetchedAll); // keep on processing until we fetched all scheduled tasks.
381 
382         if (ranAtLeastOne) {
383             lastExecutionTime = getCurrentTimeNanos();
384         }
385         afterRunningAllTasks();
386         return ranAtLeastOne;
387     }
388 
389     /**
390      * Execute all expired scheduled tasks and all current tasks in the executor queue until both queues are empty,
391      * or {@code maxDrainAttempts} has been exceeded.
392      * @param maxDrainAttempts The maximum amount of times this method attempts to drain from queues. This is to prevent
393      *                         continuous task execution and scheduling from preventing the EventExecutor thread to
394      *                         make progress and return to the selector mechanism to process inbound I/O events.
395      * @return {@code true} if at least one task was run.
396      */
397     protected final boolean runScheduledAndExecutorTasks(final int maxDrainAttempts) {
398         assert inEventLoop();
399         boolean ranAtLeastOneTask;
400         int drainAttempt = 0;
401         do {
402             // We must run the taskQueue tasks first, because the scheduled tasks from outside the EventLoop are queued
403             // here because the taskQueue is thread safe and the scheduledTaskQueue is not thread safe.
404             ranAtLeastOneTask = runExistingTasksFrom(taskQueue) | executeExpiredScheduledTasks();
405         } while (ranAtLeastOneTask && ++drainAttempt < maxDrainAttempts);
406 
407         if (drainAttempt > 0) {
408             lastExecutionTime = getCurrentTimeNanos();
409         }
410         afterRunningAllTasks();
411 
412         return drainAttempt > 0;
413     }
414 
415     /**
416      * Runs all tasks from the passed {@code taskQueue}.
417      *
418      * @param taskQueue To poll and execute all tasks.
419      *
420      * @return {@code true} if at least one task was executed.
421      */
422     protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
423         Runnable task = pollTaskFrom(taskQueue);
424         if (task == null) {
425             return false;
426         }
427         for (;;) {
428             safeExecute(task);
429             task = pollTaskFrom(taskQueue);
430             if (task == null) {
431                 return true;
432             }
433         }
434     }
435 
436     /**
437      * What ever tasks are present in {@code taskQueue} when this method is invoked will be {@link Runnable#run()}.
438      * @param taskQueue the task queue to drain.
439      * @return {@code true} if at least {@link Runnable#run()} was called.
440      */
441     private boolean runExistingTasksFrom(Queue<Runnable> taskQueue) {
442         Runnable task = pollTaskFrom(taskQueue);
443         if (task == null) {
444             return false;
445         }
446         int remaining = Math.min(maxPendingTasks, taskQueue.size());
447         safeExecute(task);
448         // Use taskQueue.poll() directly rather than pollTaskFrom() since the latter may
449         // silently consume more than one item from the queue (skips over WAKEUP_TASK instances)
450         while (remaining-- > 0 && (task = taskQueue.poll()) != null) {
451             safeExecute(task);
452         }
453         return true;
454     }
455 
456     /**
457      * Poll all tasks from the task queue and run them via {@link Runnable#run()} method.  This method stops running
458      * the tasks in the task queue and returns if it ran longer than {@code timeoutNanos}.
459      */
460     protected boolean runAllTasks(long timeoutNanos) {
461         fetchFromScheduledTaskQueue();
462         Runnable task = pollTask();
463         if (task == null) {
464             afterRunningAllTasks();
465             return false;
466         }
467 
468         final long deadline = timeoutNanos > 0 ? getCurrentTimeNanos() + timeoutNanos : 0;
469         long runTasks = 0;
470         long lastExecutionTime;
471         for (;;) {
472             safeExecute(task);
473 
474             runTasks ++;
475 
476             // Check timeout every 64 tasks because nanoTime() is relatively expensive.
477             // XXX: Hard-coded value - will make it configurable if it is really a problem.
478             if ((runTasks & 0x3F) == 0) {
479                 lastExecutionTime = getCurrentTimeNanos();
480                 if (lastExecutionTime >= deadline) {
481                     break;
482                 }
483             }
484 
485             task = pollTask();
486             if (task == null) {
487                 lastExecutionTime = getCurrentTimeNanos();
488                 break;
489             }
490         }
491 
492         afterRunningAllTasks();
493         this.lastExecutionTime = lastExecutionTime;
494         return true;
495     }
496 
497     /**
498      * Invoked before returning from {@link #runAllTasks()} and {@link #runAllTasks(long)}.
499      */
500     protected void afterRunningAllTasks() { }
501 
502     /**
503      * Returns the amount of time left until the scheduled task with the closest dead line is executed.
504      */
505     protected long delayNanos(long currentTimeNanos) {
506         currentTimeNanos -= initialNanoTime();
507 
508         ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
509         if (scheduledTask == null) {
510             return SCHEDULE_PURGE_INTERVAL;
511         }
512 
513         return scheduledTask.delayNanos(currentTimeNanos);
514     }
515 
516     /**
517      * Returns the absolute point in time (relative to {@link #getCurrentTimeNanos()}) at which the next
518      * closest scheduled task should run.
519      */
520     protected long deadlineNanos() {
521         ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
522         if (scheduledTask == null) {
523             return getCurrentTimeNanos() + SCHEDULE_PURGE_INTERVAL;
524         }
525         return scheduledTask.deadlineNanos();
526     }
527 
528     /**
529      * Updates the internal timestamp that tells when a submitted task was executed most recently.
530      * {@link #runAllTasks()} and {@link #runAllTasks(long)} updates this timestamp automatically, and thus there's
531      * usually no need to call this method.  However, if you take the tasks manually using {@link #takeTask()} or
532      * {@link #pollTask()}, you have to call this method at the end of task execution loop for accurate quiet period
533      * checks.
534      */
535     protected void updateLastExecutionTime() {
536         lastExecutionTime = getCurrentTimeNanos();
537     }
538 
539     /**
540      * Runs the task-processing loop until {@link #confirmShutdown()} returns {@code true}.
541      *
542      * <p>Implementations <strong>must not let a {@link Throwable} thrown by a task escape this
543      * method</strong>: any uncaught {@link Throwable} terminates the executor (logged at {@code WARN}
544      * and surfaced via {@link #terminationFuture()}), at which point every {@code Channel}
545      * registered with this executor stops processing I/O and new task submissions are rejected.
546      * The supplied helpers - {@link #runAllTasks()}, {@link #runAllTasks(long)}, and
547      * {@link #safeExecute(Runnable)} - catch {@code Throwable} for you; custom loops built on
548      * {@link #pollTask()} or {@link #takeTask()} are responsible for wrapping each task
549      * invocation accordingly.
550      */
551     protected abstract void run();
552 
553     /**
554      * Do nothing, sub-classes may override
555      */
556     protected void cleanup() {
557         // NOOP
558     }
559 
560     protected void wakeup(boolean inEventLoop) {
561         if (!inEventLoop) {
562             // Use offer as we actually only need this to unblock the thread and if offer fails we do not care as there
563             // is already something in the queue.
564             taskQueue.offer(WAKEUP_TASK);
565         }
566     }
567 
568     @Override
569     public boolean inEventLoop(Thread thread) {
570         return thread == this.thread;
571     }
572 
573     /**
574      * Add a {@link Runnable} which will be executed on shutdown of this instance
575      */
576     public void addShutdownHook(final Runnable task) {
577         if (inEventLoop()) {
578             shutdownHooks.add(task);
579         } else {
580             execute(new Runnable() {
581                 @Override
582                 public void run() {
583                     shutdownHooks.add(task);
584                 }
585             });
586         }
587     }
588 
589     /**
590      * Remove a previous added {@link Runnable} as a shutdown hook
591      */
592     public void removeShutdownHook(final Runnable task) {
593         if (inEventLoop()) {
594             shutdownHooks.remove(task);
595         } else {
596             execute(new Runnable() {
597                 @Override
598                 public void run() {
599                     shutdownHooks.remove(task);
600                 }
601             });
602         }
603     }
604 
605     private boolean runShutdownHooks() {
606         boolean ran = false;
607         // Note shutdown hooks can add / remove shutdown hooks.
608         while (!shutdownHooks.isEmpty()) {
609             List<Runnable> copy = new ArrayList<Runnable>(shutdownHooks);
610             shutdownHooks.clear();
611             for (Runnable task: copy) {
612                 try {
613                     runTask(task);
614                 } catch (Throwable t) {
615                     logger.warn("Shutdown hook raised an exception.", t);
616                 } finally {
617                     ran = true;
618                 }
619             }
620         }
621 
622         if (ran) {
623             lastExecutionTime = getCurrentTimeNanos();
624         }
625 
626         return ran;
627     }
628 
629     @Override
630     public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
631         ObjectUtil.checkPositiveOrZero(quietPeriod, "quietPeriod");
632         if (timeout < quietPeriod) {
633             throw new IllegalArgumentException(
634                     "timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
635         }
636         ObjectUtil.checkNotNull(unit, "unit");
637 
638         if (isShuttingDown()) {
639             return terminationFuture();
640         }
641 
642         boolean inEventLoop = inEventLoop();
643         boolean wakeup;
644         int oldState;
645         for (;;) {
646             if (isShuttingDown()) {
647                 return terminationFuture();
648             }
649             int newState;
650             wakeup = true;
651             oldState = state;
652             if (inEventLoop) {
653                 newState = ST_SHUTTING_DOWN;
654             } else {
655                 switch (oldState) {
656                     case ST_NOT_STARTED:
657                     case ST_STARTED:
658                         newState = ST_SHUTTING_DOWN;
659                         break;
660                     default:
661                         newState = oldState;
662                         wakeup = false;
663                 }
664             }
665             if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
666                 break;
667             }
668         }
669         gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod);
670         gracefulShutdownTimeout = unit.toNanos(timeout);
671 
672         if (ensureThreadStarted(oldState)) {
673             return terminationFuture;
674         }
675 
676         if (wakeup) {
677             taskQueue.offer(WAKEUP_TASK);
678             if (!addTaskWakesUp) {
679                 wakeup(inEventLoop);
680             }
681         }
682 
683         return terminationFuture();
684     }
685 
686     @Override
687     public Future<?> terminationFuture() {
688         return terminationFuture;
689     }
690 
691     @Override
692     @Deprecated
693     public void shutdown() {
694         if (isShutdown()) {
695             return;
696         }
697 
698         boolean inEventLoop = inEventLoop();
699         boolean wakeup;
700         int oldState;
701         for (;;) {
702             if (isShuttingDown()) {
703                 return;
704             }
705             int newState;
706             wakeup = true;
707             oldState = state;
708             if (inEventLoop) {
709                 newState = ST_SHUTDOWN;
710             } else {
711                 switch (oldState) {
712                     case ST_NOT_STARTED:
713                     case ST_STARTED:
714                     case ST_SHUTTING_DOWN:
715                         newState = ST_SHUTDOWN;
716                         break;
717                     default:
718                         newState = oldState;
719                         wakeup = false;
720                 }
721             }
722             if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
723                 break;
724             }
725         }
726 
727         if (ensureThreadStarted(oldState)) {
728             return;
729         }
730 
731         if (wakeup) {
732             taskQueue.offer(WAKEUP_TASK);
733             if (!addTaskWakesUp) {
734                 wakeup(inEventLoop);
735             }
736         }
737     }
738 
739     @Override
740     public boolean isShuttingDown() {
741         return state >= ST_SHUTTING_DOWN;
742     }
743 
744     @Override
745     public boolean isShutdown() {
746         return state >= ST_SHUTDOWN;
747     }
748 
749     @Override
750     public boolean isTerminated() {
751         return state == ST_TERMINATED;
752     }
753 
754     /**
755      * Confirm that the shutdown if the instance should be done now!
756      */
757     protected boolean confirmShutdown() {
758         if (!isShuttingDown()) {
759             return false;
760         }
761 
762         if (!inEventLoop()) {
763             throw new IllegalStateException("must be invoked from an event loop");
764         }
765 
766         cancelScheduledTasks();
767 
768         if (gracefulShutdownStartTime == 0) {
769             gracefulShutdownStartTime = getCurrentTimeNanos();
770         }
771 
772         if (runAllTasks() || runShutdownHooks()) {
773             if (isShutdown()) {
774                 // Executor shut down - no new tasks anymore.
775                 return true;
776             }
777 
778             // There were tasks in the queue. Wait a little bit more until no tasks are queued for the quiet period or
779             // terminate if the quiet period is 0.
780             // See https://github.com/netty/netty/issues/4241
781             if (gracefulShutdownQuietPeriod == 0) {
782                 return true;
783             }
784             taskQueue.offer(WAKEUP_TASK);
785             return false;
786         }
787 
788         final long nanoTime = getCurrentTimeNanos();
789 
790         if (isShutdown() || nanoTime - gracefulShutdownStartTime > gracefulShutdownTimeout) {
791             return true;
792         }
793 
794         if (nanoTime - lastExecutionTime <= gracefulShutdownQuietPeriod) {
795             // Check if any tasks were added to the queue every 100ms.
796             // TODO: Change the behavior of takeTask() so that it returns on timeout.
797             taskQueue.offer(WAKEUP_TASK);
798             try {
799                 Thread.sleep(100);
800             } catch (InterruptedException e) {
801                 // Ignore
802             }
803 
804             return false;
805         }
806 
807         // No tasks were added for last quiet period - hopefully safe to shut down.
808         // (Hopefully because we really cannot make a guarantee that there will be no execute() calls by a user.)
809         return true;
810     }
811 
812     @Override
813     public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
814         ObjectUtil.checkNotNull(unit, "unit");
815         if (inEventLoop()) {
816             throw new IllegalStateException("cannot await termination of the current thread");
817         }
818 
819         threadLock.await(timeout, unit);
820 
821         return isTerminated();
822     }
823 
824     @Override
825     public void execute(Runnable task) {
826         execute0(task);
827     }
828 
829     @Override
830     public void lazyExecute(Runnable task) {
831         lazyExecute0(task);
832     }
833 
834     private void execute0(@Schedule Runnable task) {
835         ObjectUtil.checkNotNull(task, "task");
836         execute(task, wakesUpForTask(task));
837     }
838 
839     private void lazyExecute0(@Schedule Runnable task) {
840         execute(ObjectUtil.checkNotNull(task, "task"), false);
841     }
842 
843     private void execute(Runnable task, boolean immediate) {
844         boolean inEventLoop = inEventLoop();
845         addTask(task);
846         if (!inEventLoop) {
847             startThread();
848             if (isShutdown()) {
849                 boolean reject = false;
850                 try {
851                     if (removeTask(task)) {
852                         reject = true;
853                     }
854                 } catch (UnsupportedOperationException e) {
855                     // The task queue does not support removal so the best thing we can do is to just move on and
856                     // hope we will be able to pick-up the task before its completely terminated.
857                     // In worst case we will log on termination.
858                 }
859                 if (reject) {
860                     reject();
861                 }
862             }
863         }
864 
865         if (!addTaskWakesUp && immediate) {
866             wakeup(inEventLoop);
867         }
868     }
869 
870     @Override
871     public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
872         throwIfInEventLoop("invokeAny");
873         return super.invokeAny(tasks);
874     }
875 
876     @Override
877     public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
878             throws InterruptedException, ExecutionException, TimeoutException {
879         throwIfInEventLoop("invokeAny");
880         return super.invokeAny(tasks, timeout, unit);
881     }
882 
883     @Override
884     public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
885             throws InterruptedException {
886         throwIfInEventLoop("invokeAll");
887         return super.invokeAll(tasks);
888     }
889 
890     @Override
891     public <T> List<java.util.concurrent.Future<T>> invokeAll(
892             Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
893         throwIfInEventLoop("invokeAll");
894         return super.invokeAll(tasks, timeout, unit);
895     }
896 
897     private void throwIfInEventLoop(String method) {
898         if (inEventLoop()) {
899             throw new RejectedExecutionException("Calling " + method + " from within the EventLoop is not allowed");
900         }
901     }
902 
903     /**
904      * Returns the {@link ThreadProperties} of the {@link Thread} that powers the {@link SingleThreadEventExecutor}.
905      * If the {@link SingleThreadEventExecutor} is not started yet, this operation will start it and block until
906      * it is fully started.
907      */
908     public final ThreadProperties threadProperties() {
909         ThreadProperties threadProperties = this.threadProperties;
910         if (threadProperties == null) {
911             Thread thread = this.thread;
912             if (thread == null) {
913                 assert !inEventLoop();
914                 submit(NOOP_TASK).syncUninterruptibly();
915                 thread = this.thread;
916                 assert thread != null;
917             }
918 
919             threadProperties = new DefaultThreadProperties(thread);
920             if (!PROPERTIES_UPDATER.compareAndSet(this, null, threadProperties)) {
921                 threadProperties = this.threadProperties;
922             }
923         }
924 
925         return threadProperties;
926     }
927 
928     /**
929      * @deprecated override {@link SingleThreadEventExecutor#wakesUpForTask} to re-create this behaviour
930      */
931     @Deprecated
932     protected interface NonWakeupRunnable extends LazyRunnable { }
933 
934     /**
935      * Can be overridden to control which tasks require waking the {@link EventExecutor} thread
936      * if it is waiting so that they can be run immediately.
937      */
938     protected boolean wakesUpForTask(Runnable task) {
939         return true;
940     }
941 
942     protected static void reject() {
943         throw new RejectedExecutionException("event executor terminated");
944     }
945 
946     /**
947      * Offers the task to the associated {@link RejectedExecutionHandler}.
948      *
949      * @param task to reject.
950      */
951     protected final void reject(Runnable task) {
952         rejectedExecutionHandler.rejected(task, this);
953     }
954 
955     // ScheduledExecutorService implementation
956 
957     private static final long SCHEDULE_PURGE_INTERVAL = TimeUnit.SECONDS.toNanos(1);
958 
959     private void startThread() {
960         if (state == ST_NOT_STARTED) {
961             if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {
962                 boolean success = false;
963                 try {
964                     doStartThread();
965                     success = true;
966                 } finally {
967                     if (!success) {
968                         STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
969                     }
970                 }
971             }
972         }
973     }
974 
975     private boolean ensureThreadStarted(int oldState) {
976         if (oldState == ST_NOT_STARTED) {
977             try {
978                 doStartThread();
979             } catch (Throwable cause) {
980                 STATE_UPDATER.set(this, ST_TERMINATED);
981                 terminationFuture.tryFailure(cause);
982 
983                 if (!(cause instanceof Exception)) {
984                     // Also rethrow as it may be an OOME for example
985                     PlatformDependent.throwException(cause);
986                 }
987                 return true;
988             }
989         }
990         return false;
991     }
992 
993     private void doStartThread() {
994         assert thread == null;
995         executor.execute(new Runnable() {
996             @Override
997             public void run() {
998                 thread = Thread.currentThread();
999                 if (interrupted) {
1000                     thread.interrupt();
1001                 }
1002 
1003                 boolean success = false;
1004                 Throwable unexpectedException = null;
1005                 updateLastExecutionTime();
1006                 try {
1007                     SingleThreadEventExecutor.this.run();
1008                     success = true;
1009                 } catch (Throwable t) {
1010                     unexpectedException = t;
1011                     logger.warn("Unexpected exception from an event executor: ", t);
1012                 } finally {
1013                     for (;;) {
1014                         int oldState = state;
1015                         if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
1016                                 SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
1017                             break;
1018                         }
1019                     }
1020 
1021                     // Check if confirmShutdown() was called at the end of the loop.
1022                     if (success && gracefulShutdownStartTime == 0) {
1023                         if (logger.isErrorEnabled()) {
1024                             logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
1025                                     SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
1026                                     "be called before run() implementation terminates.");
1027                         }
1028                     }
1029 
1030                     try {
1031                         // Run all remaining tasks and shutdown hooks. At this point the event loop
1032                         // is in ST_SHUTTING_DOWN state still accepting tasks which is needed for
1033                         // graceful shutdown with quietPeriod.
1034                         for (;;) {
1035                             if (confirmShutdown()) {
1036                                 break;
1037                             }
1038                         }
1039 
1040                         // Now we want to make sure no more tasks can be added from this point. This is
1041                         // achieved by switching the state. Any new tasks beyond this point will be rejected.
1042                         for (;;) {
1043                             int oldState = state;
1044                             if (oldState >= ST_SHUTDOWN || STATE_UPDATER.compareAndSet(
1045                                     SingleThreadEventExecutor.this, oldState, ST_SHUTDOWN)) {
1046                                 break;
1047                             }
1048                         }
1049 
1050                         // We have the final set of tasks in the queue now, no more can be added, run all remaining.
1051                         // No need to loop here, this is the final pass.
1052                         confirmShutdown();
1053                     } finally {
1054                         try {
1055                             cleanup();
1056                         } finally {
1057                             // Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
1058                             // the future. The user may block on the future and once it unblocks the JVM may terminate
1059                             // and start unloading classes.
1060                             // See https://github.com/netty/netty/issues/6596.
1061                             FastThreadLocal.removeAll();
1062 
1063                             STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
1064                             threadLock.countDown();
1065                             int numUserTasks = drainTasks();
1066                             if (numUserTasks > 0 && logger.isWarnEnabled()) {
1067                                 logger.warn("An event executor terminated with " +
1068                                         "non-empty task queue (" + numUserTasks + ')');
1069                             }
1070                             if (unexpectedException == null) {
1071                                 terminationFuture.setSuccess(null);
1072                             } else {
1073                                 terminationFuture.setFailure(unexpectedException);
1074                             }
1075                         }
1076                     }
1077                 }
1078             }
1079         });
1080     }
1081 
1082     final int drainTasks() {
1083         int numTasks = 0;
1084         for (;;) {
1085             Runnable runnable = taskQueue.poll();
1086             if (runnable == null) {
1087                 break;
1088             }
1089             // WAKEUP_TASK should be just discarded as these are added internally.
1090             // The important bit is that we not have any user tasks left.
1091             if (WAKEUP_TASK != runnable) {
1092                 numTasks++;
1093             }
1094         }
1095         return numTasks;
1096     }
1097 
1098     private static final class DefaultThreadProperties implements ThreadProperties {
1099         private final Thread t;
1100 
1101         DefaultThreadProperties(Thread t) {
1102             this.t = t;
1103         }
1104 
1105         @Override
1106         public State state() {
1107             return t.getState();
1108         }
1109 
1110         @Override
1111         public int priority() {
1112             return t.getPriority();
1113         }
1114 
1115         @Override
1116         public boolean isInterrupted() {
1117             return t.isInterrupted();
1118         }
1119 
1120         @Override
1121         public boolean isDaemon() {
1122             return t.isDaemon();
1123         }
1124 
1125         @Override
1126         public String name() {
1127             return t.getName();
1128         }
1129 
1130         @Override
1131         public long id() {
1132             return t.getId();
1133         }
1134 
1135         @Override
1136         public StackTraceElement[] stackTrace() {
1137             return t.getStackTrace();
1138         }
1139 
1140         @Override
1141         public boolean isAlive() {
1142             return t.isAlive();
1143         }
1144     }
1145 }