1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.util.concurrent;
18
19 import io.netty.util.internal.DefaultPriorityQueue;
20 import io.netty.util.internal.PriorityQueueNode;
21
22 import java.util.concurrent.Callable;
23 import java.util.concurrent.Delayed;
24 import java.util.concurrent.TimeUnit;
25
26 @SuppressWarnings("ComparableImplementedButEqualsNotOverridden")
27 final class ScheduledFutureTask<V> extends PromiseTask<V> implements ScheduledFuture<V>, PriorityQueueNode {
28
29 private long id;
30
31 private long deadlineNanos;
32
33 private final long periodNanos;
34
35 private int queueIndex = INDEX_NOT_IN_QUEUE;
36
37 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
38 Runnable runnable, long nanoTime) {
39
40 super(executor, runnable);
41 deadlineNanos = nanoTime;
42 periodNanos = 0;
43 }
44
45 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
46 Runnable runnable, long nanoTime, long period) {
47
48 super(executor, runnable);
49 deadlineNanos = nanoTime;
50 periodNanos = validatePeriod(period);
51 }
52
53 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
54 Callable<V> callable, long nanoTime, long period) {
55
56 super(executor, callable);
57 deadlineNanos = nanoTime;
58 periodNanos = validatePeriod(period);
59 }
60
61 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
62 Callable<V> callable, long nanoTime) {
63
64 super(executor, callable);
65 deadlineNanos = nanoTime;
66 periodNanos = 0;
67 }
68
69 private static long validatePeriod(long period) {
70 if (period == 0) {
71 throw new IllegalArgumentException("period: 0 (expected: != 0)");
72 }
73 return period;
74 }
75
76 ScheduledFutureTask<V> setId(long id) {
77 if (this.id == 0L) {
78 this.id = id;
79 }
80 return this;
81 }
82
83 @Override
84 protected EventExecutor executor() {
85 return super.executor();
86 }
87
88 public long deadlineNanos() {
89 return deadlineNanos;
90 }
91
92 void setConsumed() {
93
94
95 if (periodNanos == 0) {
96 assert scheduledExecutor().getCurrentTimeNanos() >= deadlineNanos;
97 deadlineNanos = 0L;
98 }
99 }
100
101 public long delayNanos() {
102 return delayNanos(scheduledExecutor().getCurrentTimeNanos());
103 }
104
105 static long deadlineToDelayNanos(long currentTimeNanos, long deadlineNanos) {
106 return deadlineNanos == 0L ? 0L : Math.max(0L, deadlineNanos - currentTimeNanos);
107 }
108
109 public long delayNanos(long currentTimeNanos) {
110 return deadlineToDelayNanos(currentTimeNanos, deadlineNanos);
111 }
112
113 @Override
114 public long getDelay(TimeUnit unit) {
115 return unit.convert(delayNanos(), TimeUnit.NANOSECONDS);
116 }
117
118 @Override
119 public int compareTo(Delayed o) {
120 if (this == o) {
121 return 0;
122 }
123
124 ScheduledFutureTask<?> that = (ScheduledFutureTask<?>) o;
125 long d = deadlineNanos() - that.deadlineNanos();
126 if (d < 0) {
127 return -1;
128 } else if (d > 0) {
129 return 1;
130 } else if (id < that.id) {
131 return -1;
132 } else {
133 assert id != that.id;
134 return 1;
135 }
136 }
137
138 @Override
139 public void run() {
140 assert executor().inEventLoop();
141 try {
142 if (delayNanos() > 0L) {
143
144 if (isCancelled()) {
145 scheduledExecutor().scheduledTaskQueue().removeTyped(this);
146 } else {
147 scheduledExecutor().scheduleFromEventLoop(this);
148 }
149 return;
150 }
151 if (periodNanos == 0) {
152 if (setUncancellableInternal()) {
153 V result = runTask();
154 setSuccessInternal(result);
155 }
156 } else {
157
158 if (!isCancelled()) {
159 runTask();
160 if (!executor().isShutdown()) {
161 if (periodNanos > 0) {
162 deadlineNanos += periodNanos;
163 } else {
164 deadlineNanos = scheduledExecutor().getCurrentTimeNanos() - periodNanos;
165 }
166 if (!isCancelled()) {
167 scheduledExecutor().scheduledTaskQueue().add(this);
168 }
169 }
170 }
171 }
172 } catch (Throwable cause) {
173 setFailureInternal(cause);
174 }
175 }
176
177 private AbstractScheduledEventExecutor scheduledExecutor() {
178 return (AbstractScheduledEventExecutor) executor();
179 }
180
181
182
183
184
185
186 @Override
187 public boolean cancel(boolean mayInterruptIfRunning) {
188 boolean canceled = super.cancel(mayInterruptIfRunning);
189 if (canceled) {
190 scheduledExecutor().removeScheduled(this);
191 }
192 return canceled;
193 }
194
195 boolean cancelWithoutRemove(boolean mayInterruptIfRunning) {
196 return super.cancel(mayInterruptIfRunning);
197 }
198
199 @Override
200 protected StringBuilder toStringBuilder() {
201 StringBuilder buf = super.toStringBuilder();
202 buf.setCharAt(buf.length() - 1, ',');
203
204 return buf.append(" deadline: ")
205 .append(deadlineNanos)
206 .append(", period: ")
207 .append(periodNanos)
208 .append(')');
209 }
210
211 @Override
212 public int priorityQueueIndex(DefaultPriorityQueue<?> queue) {
213 return queueIndex;
214 }
215
216 @Override
217 public void priorityQueueIndex(DefaultPriorityQueue<?> queue, int i) {
218 queueIndex = i;
219 }
220 }