@@ -53,47 +53,67 @@ public AsyncCallbackLoop(final LoopState state, final AsyncCallbackRunnable body
5353
5454 @ Override
5555 public void run (final SingleResultCallback <Void > callback ) {
56- body .loop ( new ReusableLoopCallback (callback ));
56+ body .initiateIteration ( false , new ReusableLoopCallback (callback ));
5757 }
5858
5959 private static final class Body {
6060 private final AsyncCallbackRunnable wrapped ;
6161 private final LoopState state ;
62- private boolean reenteredLoopMethod ;
62+ private final ThreadLocal <Boolean > iterationIsExecutingSynchronously ;
63+ private final ThreadLocal <Status > status ;
64+
65+ private enum Status {
66+ ITERATION_INITIATED ,
67+ LAST_ITERATION_COMPLETED ,
68+ ANOTHER_ITERATION_NEEDED
69+ }
6370
6471 private Body (final LoopState state , final AsyncCallbackRunnable body ) {
6572 this .wrapped = body ;
6673 this .state = state ;
67- reenteredLoopMethod = false ;
74+ iterationIsExecutingSynchronously = ThreadLocal .withInitial (() -> false );
75+ status = ThreadLocal .withInitial (() -> Status .ITERATION_INITIATED );
6876 }
6977
7078 /**
71- * @return {@code true} to indicate that the looping completed;
72- * {@code false} to indicate that the looping is still executing, potentially asynchronously.
79+ * Invoking this method initiates a new iteration of the loop. An iteration may be executed either
80+ * synchronously or asynchronously with the execution of this method:
81+ *
82+ * <ul>
83+ * <li>synchronous execution: iteration completes before (in the happens-before order) the method completes;</li>
84+ * <li>asynchronous execution: the aforementioned relation does not exist.</li>
85+ * </ul>
86+ *
87+ * @return {@code true} iff it is known that another iteration must be initiated.
88+ * Such information is available to this method only if the iteration it initiated has completed synchronously.
7389 */
74- boolean loop ( final ReusableLoopCallback callback ) {
75- boolean [] done = { true } ;
90+ Status initiateIteration ( final boolean trampolining , final ReusableLoopCallback callback ) {
91+ iterationIsExecutingSynchronously . set ( true ) ;
7692 wrapped .run ((r , t ) -> {
77- boolean localDone = callback . onResult ( state , r , t );
78- if (localDone ) {
79- done [ 0 ] = localDone ;
93+ boolean localIterationIsExecutingSynchronously = iterationIsExecutingSynchronously . get ( );
94+ if (callback . onResult ( state , r , t ) ) {
95+ status . set ( Status . LAST_ITERATION_COMPLETED ) ;
8096 return ;
8197 }
82- if (!reenteredLoopMethod ) {
83- reenteredLoopMethod = true ;
84- try {
85- do {
86- localDone = loop (callback );
87- } while (!localDone );
88- done [0 ] = assertTrue (localDone );
89- } finally {
90- reenteredLoopMethod = false ;
91- }
92- } else {
93- done [0 ] = localDone ;
98+ if (trampolining && localIterationIsExecutingSynchronously ) {
99+ // bounce
100+ status .set (Status .ANOTHER_ITERATION_NEEDED );
101+ return ;
94102 }
103+ Status localStatus ;
104+ do {
105+ localStatus = initiateIteration (true , callback );
106+ } while (localStatus .equals (Status .ANOTHER_ITERATION_NEEDED ));
107+ status .set (localStatus );
108+
109+ // VAKOTODO remove thread-locals if executed asynchronously
95110 });
96- return done [0 ];
111+ try {
112+ return status .get ();
113+ } finally {
114+ status .remove ();
115+ iterationIsExecutingSynchronously .remove ();
116+ }
97117 }
98118 }
99119
0 commit comments