1 /* |
1 /* |
2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
153 /** The body of the task. */ |
153 /** The body of the task. */ |
154 protected abstract void run(); |
154 protected abstract void run(); |
155 } |
155 } |
156 |
156 |
157 /** |
157 /** |
158 * A RestartableTask that runs its main loop within a |
158 * A task that runs its main loop within a synchronized block to provide |
159 * synchronized block to place a memory barrier around it. |
159 * memory visibility between runs. Since the main loop can't run concurrently, |
160 * Because the main loop can't run concurrently in two treads, |
160 * the lock shouldn't be contended and no deadlock should ever be possible. |
161 * then the lock shouldn't be contended and no deadlock should |
|
162 * ever be possible. |
|
163 */ |
161 */ |
164 public static final class SynchronizedRestartableTask |
162 public static final class SynchronizedRestartableTask |
165 extends CompleteRestartableTask { |
163 extends CompleteRestartableTask { |
|
164 |
166 private final Runnable mainLoop; |
165 private final Runnable mainLoop; |
167 private final Object lock = new Object(); |
166 private final Object lock = new Object(); |
|
167 |
168 public SynchronizedRestartableTask(Runnable mainLoop) { |
168 public SynchronizedRestartableTask(Runnable mainLoop) { |
169 this.mainLoop = mainLoop; |
169 this.mainLoop = mainLoop; |
170 } |
170 } |
171 |
171 |
172 @Override |
172 @Override |
187 private final RestartableTask restartableTask; |
187 private final RestartableTask restartableTask; |
188 private final DeferredCompleter completer; |
188 private final DeferredCompleter completer; |
189 private final SchedulableTask schedulableTask; |
189 private final SchedulableTask schedulableTask; |
190 |
190 |
191 /** |
191 /** |
192 * A simple task that can be pushed on an executor to execute |
192 * An auxiliary task that starts the restartable task: |
193 * {@code restartableTask.run(completer)}. |
193 * {@code restartableTask.run(completer)}. |
194 */ |
194 */ |
195 private final class SchedulableTask implements Runnable { |
195 private final class SchedulableTask implements Runnable { |
196 @Override |
196 @Override |
197 public void run() { |
197 public void run() { |
223 public void runOrSchedule() { |
223 public void runOrSchedule() { |
224 runOrSchedule(schedulableTask, null); |
224 runOrSchedule(schedulableTask, null); |
225 } |
225 } |
226 |
226 |
227 /** |
227 /** |
228 * Runs or schedules the task to be run in the provided executor. |
228 * Executes or schedules the task to be executed in the provided executor. |
229 * |
229 * |
230 * <p> This method can be used when potential executing from a calling |
230 * <p> This method can be used when potential executing from a calling |
231 * thread is not desirable. |
231 * thread is not desirable. |
232 * |
232 * |
233 * @param executor |
233 * @param executor |
234 * An executor in which to execute the task, if the task needs |
234 * An executor in which to execute the task, if the task needs |
235 * to be executed. |
235 * to be executed. |
236 * |
236 * |
237 * @apiNote The given executor can be {@code null} in which case calling |
237 * @apiNote The given executor can be {@code null} in which case calling |
238 * {@code deferOrSchedule(null)} is strictly equivalent to calling |
238 * {@code runOrSchedule(null)} is strictly equivalent to calling |
239 * {@code runOrSchedule()}. |
239 * {@code runOrSchedule()}. |
240 */ |
240 */ |
241 public void deferOrSchedule(Executor executor) { // TODO: why this name? why not runOrSchedule? |
241 public void runOrSchedule(Executor executor) { |
242 runOrSchedule(schedulableTask, executor); |
242 runOrSchedule(schedulableTask, executor); |
243 } |
243 } |
244 |
244 |
245 private void runOrSchedule(SchedulableTask task, Executor executor) { |
245 private void runOrSchedule(SchedulableTask task, Executor executor) { |
246 while (true) { |
246 while (true) { |
346 |
346 |
347 /** |
347 /** |
348 * Returns a new {@code SequentialScheduler} that executes the provided |
348 * Returns a new {@code SequentialScheduler} that executes the provided |
349 * {@code mainLoop} from within a {@link SynchronizedRestartableTask}. |
349 * {@code mainLoop} from within a {@link SynchronizedRestartableTask}. |
350 * |
350 * |
351 * @apiNote |
351 * @apiNote This is equivalent to calling |
352 * This is equivalent to calling |
352 * {@code new SequentialScheduler(new SynchronizedRestartableTask(mainLoop))} |
353 * {@code new SequentialScheduler(new SynchronizedRestartableTask(mainloop));} |
353 * The main loop must not perform any blocking operation. |
354 * The main loop must not do any blocking operation. |
354 * |
355 * |
355 * @param mainLoop The main loop of the new sequential scheduler |
356 * @param mainloop The main loop of the new sequential scheduler. |
|
357 * @return a new {@code SequentialScheduler} that executes the provided |
356 * @return a new {@code SequentialScheduler} that executes the provided |
358 * {@code mainLoop} from within a {@link SynchronizedRestartableTask}. |
357 * {@code mainLoop} from within a {@link SynchronizedRestartableTask}. |
359 */ |
358 */ |
360 public static SequentialScheduler synchronizedScheduler(Runnable mainloop) { |
359 public static SequentialScheduler synchronizedScheduler(Runnable mainLoop) { |
361 return new SequentialScheduler(new SynchronizedRestartableTask(mainloop)); |
360 return new SequentialScheduler(new SynchronizedRestartableTask(mainLoop)); |
362 } |
361 } |
363 |
|
364 } |
362 } |