1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
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
104
105
106
107
108
109
110 protected SingleThreadEventExecutor(
111 EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {
112 this(parent, new ThreadPerTaskExecutor(threadFactory), addTaskWakesUp);
113 }
114
115
116
117
118
119
120
121
122
123
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
133
134
135
136
137
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
145
146
147
148
149
150
151
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
177
178 @Deprecated
179 protected Queue<Runnable> newTaskQueue() {
180 return newTaskQueue(maxPendingTasks);
181 }
182
183
184
185
186
187
188
189 protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
190 return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
191 }
192
193
194
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
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
224
225
226
227
228
229
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
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
259 return null;
260 }
261 }
262 if (task == null) {
263
264
265
266
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
293 scheduledTaskQueue.add((ScheduledFutureTask<?>) scheduledTask);
294 return false;
295 }
296 }
297 }
298
299
300
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
319
320 protected Runnable peekTask() {
321 assert inEventLoop();
322 return taskQueue.peek();
323 }
324
325
326
327
328 protected boolean hasTasks() {
329 assert inEventLoop();
330 return !taskQueue.isEmpty();
331 }
332
333
334
335
336 public int pendingTasks() {
337 return taskQueue.size();
338 }
339
340
341
342
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
360
361 protected boolean removeTask(Runnable task) {
362 return taskQueue.remove(ObjectUtil.checkNotNull(task, "task"));
363 }
364
365
366
367
368
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);
381
382 if (ranAtLeastOne) {
383 lastExecutionTime = getCurrentTimeNanos();
384 }
385 afterRunningAllTasks();
386 return ranAtLeastOne;
387 }
388
389
390
391
392
393
394
395
396
397 protected final boolean runScheduledAndExecutorTasks(final int maxDrainAttempts) {
398 assert inEventLoop();
399 boolean ranAtLeastOneTask;
400 int drainAttempt = 0;
401 do {
402
403
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
417
418
419
420
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
438
439
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
449
450 while (remaining-- > 0 && (task = taskQueue.poll()) != null) {
451 safeExecute(task);
452 }
453 return true;
454 }
455
456
457
458
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
477
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
499
500 protected void afterRunningAllTasks() { }
501
502
503
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
518
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
530
531
532
533
534
535 protected void updateLastExecutionTime() {
536 lastExecutionTime = getCurrentTimeNanos();
537 }
538
539
540
541
542
543
544
545
546
547
548
549
550
551 protected abstract void run();
552
553
554
555
556 protected void cleanup() {
557
558 }
559
560 protected void wakeup(boolean inEventLoop) {
561 if (!inEventLoop) {
562
563
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
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
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
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
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
775 return true;
776 }
777
778
779
780
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
796
797 taskQueue.offer(WAKEUP_TASK);
798 try {
799 Thread.sleep(100);
800 } catch (InterruptedException e) {
801
802 }
803
804 return false;
805 }
806
807
808
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
856
857
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
905
906
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
930
931 @Deprecated
932 protected interface NonWakeupRunnable extends LazyRunnable { }
933
934
935
936
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
948
949
950
951 protected final void reject(Runnable task) {
952 rejectedExecutionHandler.rejected(task, this);
953 }
954
955
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
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
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
1032
1033
1034 for (;;) {
1035 if (confirmShutdown()) {
1036 break;
1037 }
1038 }
1039
1040
1041
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
1051
1052 confirmShutdown();
1053 } finally {
1054 try {
1055 cleanup();
1056 } finally {
1057
1058
1059
1060
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
1090
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 }