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.AtomicInteger;
44 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
45 import java.util.concurrent.atomic.AtomicLong;
46 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
47 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
48 import java.util.concurrent.locks.Lock;
49 import java.util.concurrent.locks.ReentrantLock;
50
51
52
53
54
55 public abstract class SingleThreadEventExecutor extends AbstractScheduledEventExecutor implements OrderedEventExecutor {
56
57 static final int DEFAULT_MAX_PENDING_EXECUTOR_TASKS = Math.max(16,
58 SystemPropertyUtil.getInt("io.netty.eventexecutor.maxPendingTasks", Integer.MAX_VALUE));
59
60 private static final InternalLogger logger =
61 InternalLoggerFactory.getInstance(SingleThreadEventExecutor.class);
62
63 private static final int ST_NOT_STARTED = 1;
64 private static final int ST_SUSPENDING = 2;
65 private static final int ST_SUSPENDED = 3;
66 private static final int ST_STARTED = 4;
67 private static final int ST_SHUTTING_DOWN = 5;
68 private static final int ST_SHUTDOWN = 6;
69 private static final int ST_TERMINATED = 7;
70
71 private static final Runnable NOOP_TASK = new Runnable() {
72 @Override
73 public void run() {
74
75 }
76 };
77
78 private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
79 AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
80 private static final AtomicReferenceFieldUpdater<SingleThreadEventExecutor, ThreadProperties> PROPERTIES_UPDATER =
81 AtomicReferenceFieldUpdater.newUpdater(
82 SingleThreadEventExecutor.class, ThreadProperties.class, "threadProperties");
83 private static final AtomicLongFieldUpdater<SingleThreadEventExecutor> ACCUMULATED_ACTIVE_TIME_NANOS_UPDATER =
84 AtomicLongFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "accumulatedActiveTimeNanos");
85 private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> CONSECUTIVE_IDLE_CYCLES_UPDATER =
86 AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "consecutiveIdleCycles");
87 private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> CONSECUTIVE_BUSY_CYCLES_UPDATER =
88 AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "consecutiveBusyCycles");
89 private final Queue<Runnable> taskQueue;
90
91 private volatile Thread thread;
92 @SuppressWarnings("unused")
93 private volatile ThreadProperties threadProperties;
94 private final Executor executor;
95 private volatile boolean interrupted;
96
97 private final Lock processingLock = new ReentrantLock();
98 private final CountDownLatch threadLock = new CountDownLatch(1);
99 private final Set<Runnable> shutdownHooks = new LinkedHashSet<Runnable>();
100 private final boolean addTaskWakesUp;
101 private final int maxPendingTasks;
102 private final RejectedExecutionHandler rejectedExecutionHandler;
103 private final boolean supportSuspension;
104
105
106 private volatile long accumulatedActiveTimeNanos;
107
108 private volatile long lastActivityTimeNanos;
109
110
111
112
113 private volatile int consecutiveIdleCycles;
114
115
116
117
118
119 private volatile int consecutiveBusyCycles;
120 private long lastExecutionTime;
121
122 @SuppressWarnings({ "FieldMayBeFinal", "unused" })
123 private volatile int state = ST_NOT_STARTED;
124
125 private volatile long gracefulShutdownQuietPeriod;
126 private volatile long gracefulShutdownTimeout;
127 private long gracefulShutdownStartTime;
128
129 private final Promise<?> terminationFuture = new DefaultPromise<Void>(GlobalEventExecutor.INSTANCE);
130
131
132
133
134
135
136
137
138
139 protected SingleThreadEventExecutor(
140 EventExecutorGroup parent, ThreadFactory threadFactory, boolean addTaskWakesUp) {
141 this(parent, new ThreadPerTaskExecutor(threadFactory), addTaskWakesUp);
142 }
143
144
145
146
147
148
149
150
151
152
153
154 protected SingleThreadEventExecutor(
155 EventExecutorGroup parent, ThreadFactory threadFactory,
156 boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
157 this(parent, new ThreadPerTaskExecutor(threadFactory), addTaskWakesUp, maxPendingTasks, rejectedHandler);
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171 protected SingleThreadEventExecutor(
172 EventExecutorGroup parent, ThreadFactory threadFactory,
173 boolean addTaskWakesUp, boolean supportSuspension,
174 int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
175 this(parent, new ThreadPerTaskExecutor(threadFactory), addTaskWakesUp, supportSuspension,
176 maxPendingTasks, rejectedHandler);
177 }
178
179
180
181
182
183
184
185
186
187 protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp) {
188 this(parent, executor, addTaskWakesUp, DEFAULT_MAX_PENDING_EXECUTOR_TASKS, RejectedExecutionHandlers.reject());
189 }
190
191
192
193
194
195
196
197
198
199
200
201 protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
202 boolean addTaskWakesUp, int maxPendingTasks,
203 RejectedExecutionHandler rejectedHandler) {
204 this(parent, executor, addTaskWakesUp, false, maxPendingTasks, rejectedHandler);
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218 protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
219 boolean addTaskWakesUp, boolean supportSuspension,
220 int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
221 super(parent);
222 this.addTaskWakesUp = addTaskWakesUp;
223 this.supportSuspension = supportSuspension;
224 this.maxPendingTasks = Math.max(16, maxPendingTasks);
225 this.executor = ThreadExecutorMap.apply(executor, this);
226 taskQueue = newTaskQueue(this.maxPendingTasks);
227 rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
228 lastActivityTimeNanos = ticker().nanoTime();
229 }
230
231 protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
232 boolean addTaskWakesUp, Queue<Runnable> taskQueue,
233 RejectedExecutionHandler rejectedHandler) {
234 this(parent, executor, addTaskWakesUp, false, taskQueue, rejectedHandler);
235 }
236
237 protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
238 boolean addTaskWakesUp, boolean supportSuspension,
239 Queue<Runnable> taskQueue, RejectedExecutionHandler rejectedHandler) {
240 super(parent);
241 this.addTaskWakesUp = addTaskWakesUp;
242 this.supportSuspension = supportSuspension;
243 this.maxPendingTasks = DEFAULT_MAX_PENDING_EXECUTOR_TASKS;
244 this.executor = ThreadExecutorMap.apply(executor, this);
245 this.taskQueue = ObjectUtil.checkNotNull(taskQueue, "taskQueue");
246 this.rejectedExecutionHandler = ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
247 }
248
249
250
251
252 @Deprecated
253 protected Queue<Runnable> newTaskQueue() {
254 return newTaskQueue(maxPendingTasks);
255 }
256
257
258
259
260
261
262
263 protected Queue<Runnable> newTaskQueue(int maxPendingTasks) {
264 return new LinkedBlockingQueue<Runnable>(maxPendingTasks);
265 }
266
267
268
269
270 protected void interruptThread() {
271 Thread currentThread = thread;
272 if (currentThread == null) {
273 interrupted = true;
274 } else {
275 currentThread.interrupt();
276 }
277 }
278
279
280
281
282 protected Runnable pollTask() {
283 assert inEventLoop();
284 return pollTaskFrom(taskQueue);
285 }
286
287 protected static Runnable pollTaskFrom(Queue<Runnable> taskQueue) {
288 for (;;) {
289 Runnable task = taskQueue.poll();
290 if (task != WAKEUP_TASK) {
291 return task;
292 }
293 }
294 }
295
296
297
298
299
300
301
302
303
304
305 protected Runnable takeTask() {
306 assert inEventLoop();
307 if (!(taskQueue instanceof BlockingQueue)) {
308 throw new UnsupportedOperationException();
309 }
310
311 BlockingQueue<Runnable> taskQueue = (BlockingQueue<Runnable>) this.taskQueue;
312 for (;;) {
313 ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
314 if (scheduledTask == null) {
315 Runnable task = null;
316 try {
317 task = taskQueue.take();
318 if (task == WAKEUP_TASK) {
319 task = null;
320 }
321 } catch (InterruptedException e) {
322
323 }
324 return task;
325 } else {
326 long delayNanos = scheduledTask.delayNanos();
327 Runnable task = null;
328 if (delayNanos > 0) {
329 try {
330 task = taskQueue.poll(delayNanos, TimeUnit.NANOSECONDS);
331 } catch (InterruptedException e) {
332
333 return null;
334 }
335 }
336 if (task == null) {
337
338
339
340
341 fetchFromScheduledTaskQueue();
342 task = taskQueue.poll();
343 }
344
345 if (task != null) {
346 if (task == WAKEUP_TASK) {
347 return null;
348 }
349 return task;
350 }
351 }
352 }
353 }
354
355 private boolean fetchFromScheduledTaskQueue() {
356 return fetchFromScheduledTaskQueue(taskQueue);
357 }
358
359
360
361
362 private boolean executeExpiredScheduledTasks() {
363 if (scheduledTaskQueue == null || scheduledTaskQueue.isEmpty()) {
364 return false;
365 }
366 long nanoTime = getCurrentTimeNanos();
367 Runnable scheduledTask = pollScheduledTask(nanoTime);
368 if (scheduledTask == null) {
369 return false;
370 }
371 do {
372 safeExecute(scheduledTask);
373 } while ((scheduledTask = pollScheduledTask(nanoTime)) != null);
374 return true;
375 }
376
377
378
379
380 protected Runnable peekTask() {
381 assert inEventLoop();
382 return taskQueue.peek();
383 }
384
385
386
387
388 protected boolean hasTasks() {
389 assert inEventLoop();
390 return !taskQueue.isEmpty();
391 }
392
393
394
395
396 public int pendingTasks() {
397 return taskQueue.size();
398 }
399
400
401
402
403
404 protected void addTask(Runnable task) {
405 ObjectUtil.checkNotNull(task, "task");
406 if (!offerTask(task)) {
407 reject(task);
408 }
409 }
410
411 final boolean offerTask(Runnable task) {
412 if (isShutdown()) {
413 reject();
414 }
415 return taskQueue.offer(task);
416 }
417
418
419
420
421 protected boolean removeTask(Runnable task) {
422 return taskQueue.remove(ObjectUtil.checkNotNull(task, "task"));
423 }
424
425
426
427
428
429
430 protected boolean runAllTasks() {
431 assert inEventLoop();
432 boolean fetchedAll;
433 boolean ranAtLeastOne = false;
434
435 do {
436 fetchedAll = fetchFromScheduledTaskQueue(taskQueue);
437 if (runAllTasksFrom(taskQueue)) {
438 ranAtLeastOne = true;
439 }
440 } while (!fetchedAll);
441
442 if (ranAtLeastOne) {
443 lastExecutionTime = getCurrentTimeNanos();
444 }
445 afterRunningAllTasks();
446 return ranAtLeastOne;
447 }
448
449
450
451
452
453
454
455
456
457 protected final boolean runScheduledAndExecutorTasks(final int maxDrainAttempts) {
458 assert inEventLoop();
459 boolean ranAtLeastOneTask;
460 int drainAttempt = 0;
461 do {
462
463
464 ranAtLeastOneTask = runExistingTasksFrom(taskQueue) | executeExpiredScheduledTasks();
465 } while (ranAtLeastOneTask && ++drainAttempt < maxDrainAttempts);
466
467 if (drainAttempt > 0) {
468 lastExecutionTime = getCurrentTimeNanos();
469 }
470 afterRunningAllTasks();
471
472 return drainAttempt > 0;
473 }
474
475
476
477
478
479
480
481
482 protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
483 Runnable task = pollTaskFrom(taskQueue);
484 if (task == null) {
485 return false;
486 }
487 for (;;) {
488 safeExecute(task);
489 task = pollTaskFrom(taskQueue);
490 if (task == null) {
491 return true;
492 }
493 }
494 }
495
496
497
498
499
500
501 private boolean runExistingTasksFrom(Queue<Runnable> taskQueue) {
502 Runnable task = pollTaskFrom(taskQueue);
503 if (task == null) {
504 return false;
505 }
506 int remaining = Math.min(maxPendingTasks, taskQueue.size());
507 safeExecute(task);
508
509
510 while (remaining-- > 0 && (task = taskQueue.poll()) != null) {
511 safeExecute(task);
512 }
513 return true;
514 }
515
516
517
518
519
520 @SuppressWarnings("NonAtomicOperationOnVolatileField")
521 protected boolean runAllTasks(long timeoutNanos) {
522 fetchFromScheduledTaskQueue(taskQueue);
523 Runnable task = pollTask();
524 if (task == null) {
525 afterRunningAllTasks();
526 return false;
527 }
528
529 final long deadline = timeoutNanos > 0 ? getCurrentTimeNanos() + timeoutNanos : 0;
530 long runTasks = 0;
531 long lastExecutionTime;
532
533 long workStartTime = ticker().nanoTime();
534 for (;;) {
535 safeExecute(task);
536
537 runTasks ++;
538
539
540
541 if ((runTasks & 0x3F) == 0) {
542 lastExecutionTime = getCurrentTimeNanos();
543 if (lastExecutionTime >= deadline) {
544 break;
545 }
546 }
547
548 task = pollTask();
549 if (task == null) {
550 lastExecutionTime = getCurrentTimeNanos();
551 break;
552 }
553 }
554
555 long workEndTime = ticker().nanoTime();
556 accumulatedActiveTimeNanos += workEndTime - workStartTime;
557 lastActivityTimeNanos = workEndTime;
558
559 afterRunningAllTasks();
560 this.lastExecutionTime = lastExecutionTime;
561 return true;
562 }
563
564
565
566
567 protected void afterRunningAllTasks() { }
568
569
570
571
572 protected long delayNanos(long currentTimeNanos) {
573 currentTimeNanos -= ticker().initialNanoTime();
574
575 ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
576 if (scheduledTask == null) {
577 return SCHEDULE_PURGE_INTERVAL;
578 }
579
580 return scheduledTask.delayNanos(currentTimeNanos);
581 }
582
583
584
585
586
587 protected long deadlineNanos() {
588 ScheduledFutureTask<?> scheduledTask = peekScheduledTask();
589 if (scheduledTask == null) {
590 return getCurrentTimeNanos() + SCHEDULE_PURGE_INTERVAL;
591 }
592 return scheduledTask.deadlineNanos();
593 }
594
595
596
597
598
599
600
601
602 protected void updateLastExecutionTime() {
603 long now = getCurrentTimeNanos();
604 lastExecutionTime = now;
605 lastActivityTimeNanos = now;
606 }
607
608
609
610
611
612
613
614 protected int getNumOfRegisteredChannels() {
615 return -1;
616 }
617
618
619
620
621
622
623
624
625
626 @SuppressWarnings("NonAtomicOperationOnVolatileField")
627 protected void reportActiveIoTime(long nanos) {
628 assert inEventLoop();
629 if (nanos > 0) {
630 accumulatedActiveTimeNanos += nanos;
631 lastActivityTimeNanos = ticker().nanoTime();
632 }
633 }
634
635
636
637
638 protected long getAndResetAccumulatedActiveTimeNanos() {
639 return ACCUMULATED_ACTIVE_TIME_NANOS_UPDATER.getAndSet(this, 0);
640 }
641
642
643
644
645 protected long getLastActivityTimeNanos() {
646 return lastActivityTimeNanos;
647 }
648
649
650
651
652
653
654
655 protected int getAndIncrementIdleCycles() {
656 return CONSECUTIVE_IDLE_CYCLES_UPDATER.getAndIncrement(this);
657 }
658
659
660
661
662
663 protected void resetIdleCycles() {
664 CONSECUTIVE_IDLE_CYCLES_UPDATER.set(this, 0);
665 }
666
667
668
669
670
671
672
673 protected int getAndIncrementBusyCycles() {
674 return CONSECUTIVE_BUSY_CYCLES_UPDATER.getAndIncrement(this);
675 }
676
677
678
679
680
681 protected void resetBusyCycles() {
682 CONSECUTIVE_BUSY_CYCLES_UPDATER.set(this, 0);
683 }
684
685
686
687
688 protected boolean isSuspensionSupported() {
689 return supportSuspension;
690 }
691
692
693
694
695
696
697
698
699
700
701
702
703
704 protected abstract void run();
705
706
707
708
709 protected void cleanup() {
710
711 }
712
713 protected void wakeup(boolean inEventLoop) {
714 if (!inEventLoop) {
715
716
717 taskQueue.offer(WAKEUP_TASK);
718 }
719 }
720
721 @Override
722 public boolean inEventLoop(Thread thread) {
723 return thread == this.thread;
724 }
725
726
727
728
729 public void addShutdownHook(final Runnable task) {
730 if (inEventLoop()) {
731 shutdownHooks.add(task);
732 } else {
733 execute(new Runnable() {
734 @Override
735 public void run() {
736 shutdownHooks.add(task);
737 }
738 });
739 }
740 }
741
742
743
744
745 public void removeShutdownHook(final Runnable task) {
746 if (inEventLoop()) {
747 shutdownHooks.remove(task);
748 } else {
749 execute(new Runnable() {
750 @Override
751 public void run() {
752 shutdownHooks.remove(task);
753 }
754 });
755 }
756 }
757
758 private boolean runShutdownHooks() {
759 boolean ran = false;
760
761 while (!shutdownHooks.isEmpty()) {
762 List<Runnable> copy = new ArrayList<Runnable>(shutdownHooks);
763 shutdownHooks.clear();
764 for (Runnable task: copy) {
765 try {
766 runTask(task);
767 } catch (Throwable t) {
768 logger.warn("Shutdown hook raised an exception.", t);
769 } finally {
770 ran = true;
771 }
772 }
773 }
774
775 if (ran) {
776 lastExecutionTime = getCurrentTimeNanos();
777 }
778
779 return ran;
780 }
781
782 private void shutdown0(long quietPeriod, long timeout, int shutdownState) {
783 if (isShuttingDown()) {
784 return;
785 }
786
787 boolean inEventLoop = inEventLoop();
788 boolean wakeup;
789 int oldState;
790 for (;;) {
791 if (isShuttingDown()) {
792 return;
793 }
794 int newState;
795 wakeup = true;
796 oldState = state;
797 if (inEventLoop) {
798 newState = shutdownState;
799 } else {
800 switch (oldState) {
801 case ST_NOT_STARTED:
802 case ST_STARTED:
803 case ST_SUSPENDING:
804 case ST_SUSPENDED:
805 newState = shutdownState;
806 break;
807 default:
808 newState = oldState;
809 wakeup = false;
810 }
811 }
812 if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
813 break;
814 }
815 }
816 if (quietPeriod != -1) {
817 gracefulShutdownQuietPeriod = quietPeriod;
818 }
819 if (timeout != -1) {
820 gracefulShutdownTimeout = timeout;
821 }
822
823 if (ensureThreadStarted(oldState)) {
824 return;
825 }
826
827 if (wakeup) {
828 taskQueue.offer(WAKEUP_TASK);
829 if (!addTaskWakesUp) {
830 wakeup(inEventLoop);
831 }
832 }
833 }
834
835 @Override
836 public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
837 ObjectUtil.checkPositiveOrZero(quietPeriod, "quietPeriod");
838 if (timeout < quietPeriod) {
839 throw new IllegalArgumentException(
840 "timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
841 }
842 ObjectUtil.checkNotNull(unit, "unit");
843
844 shutdown0(unit.toNanos(quietPeriod), unit.toNanos(timeout), ST_SHUTTING_DOWN);
845 return terminationFuture();
846 }
847
848 @Override
849 public Future<?> terminationFuture() {
850 return terminationFuture;
851 }
852
853 @Override
854 @Deprecated
855 public void shutdown() {
856 shutdown0(-1, -1, ST_SHUTDOWN);
857 }
858
859 @Override
860 public boolean isShuttingDown() {
861 return state >= ST_SHUTTING_DOWN;
862 }
863
864 @Override
865 public boolean isShutdown() {
866 return state >= ST_SHUTDOWN;
867 }
868
869 @Override
870 public boolean isTerminated() {
871 return state == ST_TERMINATED;
872 }
873
874 @Override
875 public boolean isSuspended() {
876 int currentState = state;
877 return currentState == ST_SUSPENDED || currentState == ST_SUSPENDING;
878 }
879
880 @Override
881 public boolean trySuspend() {
882 if (supportSuspension) {
883 if (STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_SUSPENDING)) {
884 wakeup(inEventLoop());
885 return true;
886 } else if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_SUSPENDED)) {
887 return true;
888 }
889 int currentState = state;
890 return currentState == ST_SUSPENDED || currentState == ST_SUSPENDING;
891 }
892 return false;
893 }
894
895
896
897
898
899
900
901 protected boolean canSuspend() {
902 return canSuspend(state);
903 }
904
905
906
907
908
909
910
911
912
913
914 protected boolean canSuspend(int state) {
915 assert inEventLoop();
916 return supportSuspension && (state == ST_SUSPENDED || state == ST_SUSPENDING)
917 && !hasTasks() && nextScheduledTaskDeadlineNanos() == -1;
918 }
919
920
921
922
923 protected boolean confirmShutdown() {
924 if (!isShuttingDown()) {
925 return false;
926 }
927
928 if (!inEventLoop()) {
929 throw new IllegalStateException("must be invoked from an event loop");
930 }
931
932 cancelScheduledTasks();
933
934 if (gracefulShutdownStartTime == 0) {
935 gracefulShutdownStartTime = getCurrentTimeNanos();
936 }
937
938 if (runAllTasks() || runShutdownHooks()) {
939 if (isShutdown()) {
940
941 return true;
942 }
943
944
945
946
947 if (gracefulShutdownQuietPeriod == 0) {
948 return true;
949 }
950 taskQueue.offer(WAKEUP_TASK);
951 return false;
952 }
953
954 final long nanoTime = getCurrentTimeNanos();
955
956 if (isShutdown() || nanoTime - gracefulShutdownStartTime > gracefulShutdownTimeout) {
957 return true;
958 }
959
960 if (nanoTime - lastExecutionTime <= gracefulShutdownQuietPeriod) {
961
962
963 taskQueue.offer(WAKEUP_TASK);
964 try {
965 Thread.sleep(100);
966 } catch (InterruptedException e) {
967
968 }
969
970 return false;
971 }
972
973
974
975 return true;
976 }
977
978 @Override
979 public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
980 ObjectUtil.checkNotNull(unit, "unit");
981 if (inEventLoop()) {
982 throw new IllegalStateException("cannot await termination of the current thread");
983 }
984
985 threadLock.await(timeout, unit);
986
987 return isTerminated();
988 }
989
990 @Override
991 public void execute(Runnable task) {
992 execute0(task);
993 }
994
995 @Override
996 public void lazyExecute(Runnable task) {
997 lazyExecute0(task);
998 }
999
1000 private void execute0(@Schedule Runnable task) {
1001 ObjectUtil.checkNotNull(task, "task");
1002 execute(task, wakesUpForTask(task));
1003 }
1004
1005 private void lazyExecute0(@Schedule Runnable task) {
1006 execute(ObjectUtil.checkNotNull(task, "task"), false);
1007 }
1008
1009 @Override
1010 void scheduleRemoveScheduled(final ScheduledFutureTask<?> task) {
1011 ObjectUtil.checkNotNull(task, "task");
1012 int currentState = state;
1013 if (supportSuspension && currentState == ST_SUSPENDED) {
1014
1015
1016
1017 execute(new Runnable() {
1018 @Override
1019 public void run() {
1020 task.run();
1021 if (canSuspend(ST_SUSPENDED)) {
1022
1023
1024 trySuspend();
1025 }
1026 }
1027 }, true);
1028 } else {
1029
1030 execute(task, false);
1031 }
1032 }
1033
1034 private void execute(Runnable task, boolean immediate) {
1035 boolean inEventLoop = inEventLoop();
1036 addTask(task);
1037 if (!inEventLoop) {
1038 startThread();
1039 if (isShutdown()) {
1040 boolean reject = false;
1041 try {
1042 if (removeTask(task)) {
1043 reject = true;
1044 }
1045 } catch (UnsupportedOperationException e) {
1046
1047
1048
1049 }
1050 if (reject) {
1051 reject();
1052 }
1053 }
1054 }
1055
1056 if (!addTaskWakesUp && immediate) {
1057 wakeup(inEventLoop);
1058 }
1059 }
1060
1061 @Override
1062 public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
1063 throwIfInEventLoop("invokeAny");
1064 return super.invokeAny(tasks);
1065 }
1066
1067 @Override
1068 public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
1069 throws InterruptedException, ExecutionException, TimeoutException {
1070 throwIfInEventLoop("invokeAny");
1071 return super.invokeAny(tasks, timeout, unit);
1072 }
1073
1074 @Override
1075 public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
1076 throws InterruptedException {
1077 throwIfInEventLoop("invokeAll");
1078 return super.invokeAll(tasks);
1079 }
1080
1081 @Override
1082 public <T> List<java.util.concurrent.Future<T>> invokeAll(
1083 Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
1084 throwIfInEventLoop("invokeAll");
1085 return super.invokeAll(tasks, timeout, unit);
1086 }
1087
1088 private void throwIfInEventLoop(String method) {
1089 if (inEventLoop()) {
1090 throw new RejectedExecutionException("Calling " + method + " from within the EventLoop is not allowed");
1091 }
1092 }
1093
1094
1095
1096
1097
1098
1099 public final ThreadProperties threadProperties() {
1100 ThreadProperties threadProperties = this.threadProperties;
1101 if (threadProperties == null) {
1102 Thread thread = this.thread;
1103 if (thread == null) {
1104 assert !inEventLoop();
1105 submit(NOOP_TASK).syncUninterruptibly();
1106 thread = this.thread;
1107 assert thread != null;
1108 }
1109
1110 threadProperties = new DefaultThreadProperties(thread);
1111 if (!PROPERTIES_UPDATER.compareAndSet(this, null, threadProperties)) {
1112 threadProperties = this.threadProperties;
1113 }
1114 }
1115
1116 return threadProperties;
1117 }
1118
1119
1120
1121
1122 @Deprecated
1123 protected interface NonWakeupRunnable extends LazyRunnable { }
1124
1125
1126
1127
1128
1129 protected boolean wakesUpForTask(Runnable task) {
1130 return true;
1131 }
1132
1133 protected static void reject() {
1134 throw new RejectedExecutionException("event executor terminated");
1135 }
1136
1137
1138
1139
1140
1141
1142 protected final void reject(Runnable task) {
1143 rejectedExecutionHandler.rejected(task, this);
1144 }
1145
1146
1147
1148 private static final long SCHEDULE_PURGE_INTERVAL = TimeUnit.SECONDS.toNanos(1);
1149
1150 private void startThread() {
1151 int currentState = state;
1152 if (currentState == ST_NOT_STARTED || currentState == ST_SUSPENDED) {
1153 if (STATE_UPDATER.compareAndSet(this, currentState, ST_STARTED)) {
1154 resetIdleCycles();
1155 resetBusyCycles();
1156 boolean success = false;
1157 try {
1158 doStartThread();
1159 success = true;
1160 } finally {
1161 if (!success) {
1162 STATE_UPDATER.compareAndSet(this, ST_STARTED, ST_NOT_STARTED);
1163 }
1164 }
1165 }
1166 }
1167 }
1168
1169 private boolean ensureThreadStarted(int oldState) {
1170 if (oldState == ST_NOT_STARTED || oldState == ST_SUSPENDED) {
1171 try {
1172 doStartThread();
1173 } catch (Throwable cause) {
1174 STATE_UPDATER.set(this, ST_TERMINATED);
1175 terminationFuture.tryFailure(cause);
1176
1177 if (!(cause instanceof Exception)) {
1178
1179 PlatformDependent.throwException(cause);
1180 }
1181 return true;
1182 }
1183 }
1184 return false;
1185 }
1186
1187 private void doStartThread() {
1188 executor.execute(new Runnable() {
1189 @Override
1190 public void run() {
1191 processingLock.lock();
1192 assert thread == null;
1193 thread = Thread.currentThread();
1194 if (interrupted) {
1195 thread.interrupt();
1196 interrupted = false;
1197 }
1198 boolean success = false;
1199 Throwable unexpectedException = null;
1200 updateLastExecutionTime();
1201 boolean suspend = false;
1202 try {
1203 for (;;) {
1204 SingleThreadEventExecutor.this.run();
1205 success = true;
1206
1207 int currentState = state;
1208 if (canSuspend(currentState)) {
1209 if (!STATE_UPDATER.compareAndSet(SingleThreadEventExecutor.this,
1210 ST_SUSPENDING, ST_SUSPENDED)) {
1211
1212 continue;
1213 }
1214
1215 if (!canSuspend(ST_SUSPENDED) && STATE_UPDATER.compareAndSet(SingleThreadEventExecutor.this,
1216 ST_SUSPENDED, ST_STARTED)) {
1217
1218
1219 continue;
1220 }
1221 suspend = true;
1222 }
1223 break;
1224 }
1225 } catch (Throwable t) {
1226 unexpectedException = t;
1227 logger.warn("Unexpected exception from an event executor: ", t);
1228 } finally {
1229 boolean shutdown = !suspend;
1230 if (shutdown) {
1231 for (;;) {
1232
1233 int oldState = state;
1234 if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
1235 SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
1236 break;
1237 }
1238 }
1239 if (success && gracefulShutdownStartTime == 0) {
1240
1241 if (logger.isErrorEnabled()) {
1242 logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
1243 SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
1244 "be called before run() implementation terminates.");
1245 }
1246 }
1247 }
1248
1249 try {
1250 if (shutdown) {
1251
1252
1253
1254 for (;;) {
1255 if (confirmShutdown()) {
1256 break;
1257 }
1258 }
1259
1260
1261
1262 for (;;) {
1263 int currentState = state;
1264 if (currentState >= ST_SHUTDOWN || STATE_UPDATER.compareAndSet(
1265 SingleThreadEventExecutor.this, currentState, ST_SHUTDOWN)) {
1266 break;
1267 }
1268 }
1269
1270
1271
1272 confirmShutdown();
1273 }
1274 } finally {
1275 try {
1276 if (shutdown) {
1277 try {
1278 cleanup();
1279 } finally {
1280
1281
1282
1283
1284 FastThreadLocal.removeAll();
1285
1286 STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
1287 threadLock.countDown();
1288 int numUserTasks = drainTasks();
1289 if (numUserTasks > 0 && logger.isWarnEnabled()) {
1290 logger.warn("An event executor terminated with " +
1291 "non-empty task queue (" + numUserTasks + ')');
1292 }
1293 if (unexpectedException == null) {
1294 terminationFuture.setSuccess(null);
1295 } else {
1296 terminationFuture.setFailure(unexpectedException);
1297 }
1298 }
1299 } else {
1300
1301 FastThreadLocal.removeAll();
1302
1303
1304 threadProperties = null;
1305 }
1306 } finally {
1307 thread = null;
1308
1309 processingLock.unlock();
1310 }
1311 }
1312 }
1313 }
1314 });
1315 }
1316
1317 final int drainTasks() {
1318 int numTasks = 0;
1319 for (;;) {
1320 Runnable runnable = taskQueue.poll();
1321 if (runnable == null) {
1322 break;
1323 }
1324
1325
1326 if (WAKEUP_TASK != runnable) {
1327 numTasks++;
1328 }
1329 }
1330 return numTasks;
1331 }
1332
1333 private static final class DefaultThreadProperties implements ThreadProperties {
1334 private final Thread t;
1335
1336 DefaultThreadProperties(Thread t) {
1337 this.t = t;
1338 }
1339
1340 @Override
1341 public State state() {
1342 return t.getState();
1343 }
1344
1345 @Override
1346 public int priority() {
1347 return t.getPriority();
1348 }
1349
1350 @Override
1351 public boolean isInterrupted() {
1352 return t.isInterrupted();
1353 }
1354
1355 @Override
1356 public boolean isDaemon() {
1357 return t.isDaemon();
1358 }
1359
1360 @Override
1361 public String name() {
1362 return t.getName();
1363 }
1364
1365 @Override
1366 public long id() {
1367 return t.getId();
1368 }
1369
1370 @Override
1371 public StackTraceElement[] stackTrace() {
1372 return t.getStackTrace();
1373 }
1374
1375 @Override
1376 public boolean isAlive() {
1377 return t.isAlive();
1378 }
1379 }
1380 }