1
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 private static final long START_TIME = System.nanoTime();
29
30 static long nanoTime() {
31 return System.nanoTime() - START_TIME;
32 }
33
34 static long deadlineNanos(long delay) {
35 long deadlineNanos = nanoTime() + delay;
36
37 return deadlineNanos < 0 ? Long.MAX_VALUE : deadlineNanos;
38 }
39
40 static long initialNanoTime() {
41 return START_TIME;
42 }
43
44
45 private long id;
46
47 private long deadlineNanos;
48
49 private final long periodNanos;
50
51 private int queueIndex = INDEX_NOT_IN_QUEUE;
52
53 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
54 Runnable runnable, long nanoTime) {
55
56 super(executor, runnable);
57 deadlineNanos = nanoTime;
58 periodNanos = 0;
59 }
60
61 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
62 Runnable runnable, long nanoTime, long period) {
63
64 super(executor, runnable);
65 deadlineNanos = nanoTime;
66 periodNanos = validatePeriod(period);
67 }
68
69 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
70 Callable<V> callable, long nanoTime, long period) {
71
72 super(executor, callable);
73 deadlineNanos = nanoTime;
74 periodNanos = validatePeriod(period);
75 }
76
77 ScheduledFutureTask(AbstractScheduledEventExecutor executor,
78 Callable<V> callable, long nanoTime) {
79
80 super(executor, callable);
81 deadlineNanos = nanoTime;
82 periodNanos = 0;
83 }
84
85 private static long validatePeriod(long period) {
86 if (period == 0) {
87 throw new IllegalArgumentException("period: 0 (expected: != 0)");
88 }
89 return period;
90 }
91
92 ScheduledFutureTask<V> setId(long id) {
93 if (this.id == 0L) {
94 this.id = id;
95 }
96 return this;
97 }
98
99 @Override
100 protected EventExecutor executor() {
101 return super.executor();
102 }
103
104 public long deadlineNanos() {
105 return deadlineNanos;
106 }
107
108 void setConsumed() {
109
110
111 if (periodNanos == 0) {
112 assert nanoTime() >= deadlineNanos;
113 deadlineNanos = 0L;
114 }
115 }
116
117 public long delayNanos() {
118 return deadlineToDelayNanos(deadlineNanos());
119 }
120
121 static long deadlineToDelayNanos(long deadlineNanos) {
122 return deadlineNanos == 0L ? 0L : Math.max(0L, deadlineNanos - nanoTime());
123 }
124
125 public long delayNanos(long currentTimeNanos) {
126 return deadlineNanos == 0L ? 0L
127 : Math.max(0L, deadlineNanos() - (currentTimeNanos - START_TIME));
128 }
129
130 @Override
131 public long getDelay(TimeUnit unit) {
132 return unit.convert(delayNanos(), TimeUnit.NANOSECONDS);
133 }
134
135 @Override
136 public int compareTo(Delayed o) {
137 if (this == o) {
138 return 0;
139 }
140
141 ScheduledFutureTask<?> that = (ScheduledFutureTask<?>) o;
142 long d = deadlineNanos() - that.deadlineNanos();
143 if (d < 0) {
144 return -1;
145 } else if (d > 0) {
146 return 1;
147 } else if (id < that.id) {
148 return -1;
149 } else {
150 assert id != that.id;
151 return 1;
152 }
153 }
154
155 @Override
156 public void run() {
157 assert executor().inEventLoop();
158 try {
159 if (delayNanos() > 0L) {
160
161 if (isCancelled()) {
162 scheduledExecutor().scheduledTaskQueue().removeTyped(this);
163 } else {
164 scheduledExecutor().scheduleFromEventLoop(this);
165 }
166 return;
167 }
168 if (periodNanos == 0) {
169 if (setUncancellableInternal()) {
170 V result = runTask();
171 setSuccessInternal(result);
172 }
173 } else {
174
175 if (!isCancelled()) {
176 runTask();
177 if (!executor().isShutdown()) {
178 if (periodNanos > 0) {
179 deadlineNanos += periodNanos;
180 } else {
181 deadlineNanos = nanoTime() - periodNanos;
182 }
183 if (!isCancelled()) {
184 scheduledExecutor().scheduledTaskQueue().add(this);
185 }
186 }
187 }
188 }
189 } catch (Throwable cause) {
190 setFailureInternal(cause);
191 }
192 }
193
194 private AbstractScheduledEventExecutor scheduledExecutor() {
195 return (AbstractScheduledEventExecutor) executor();
196 }
197
198
203 @Override
204 public boolean cancel(boolean mayInterruptIfRunning) {
205 boolean canceled = super.cancel(mayInterruptIfRunning);
206 if (canceled) {
207 scheduledExecutor().removeScheduled(this);
208 }
209 return canceled;
210 }
211
212 boolean cancelWithoutRemove(boolean mayInterruptIfRunning) {
213 return super.cancel(mayInterruptIfRunning);
214 }
215
216 @Override
217 protected StringBuilder toStringBuilder() {
218 StringBuilder buf = super.toStringBuilder();
219 buf.setCharAt(buf.length() - 1, ',');
220
221 return buf.append(" deadline: ")
222 .append(deadlineNanos)
223 .append(", period: ")
224 .append(periodNanos)
225 .append(')');
226 }
227
228 @Override
229 public int priorityQueueIndex(DefaultPriorityQueue<?> queue) {
230 return queueIndex;
231 }
232
233 @Override
234 public void priorityQueueIndex(DefaultPriorityQueue<?> queue, int i) {
235 queueIndex = i;
236 }
237 }
238