@Override public Continuation newCall(Object fn, Object... args) { return Call.init(stateContext, returnBufferFactory, fn, args).getCurrentContinuation(); }
private static int newPausedVersion(int oldVersion) { int v; Random versionSource = ThreadLocalRandom.current(); do { v = versionSource.nextInt(); } while (!isPaused(v) || v == oldVersion); return v; }
/** * Returns the current state of the call. * * @return the state of the call */ public State getState() { return versionToState(currentVersion.get()); }
/** * Returns the current continuation of this call. * * <p>The call must be in the paused state; otherwise, an {@link IllegalStateException} is * thrown.</p> * * @return the current continuation of the call * * @throws IllegalStateException if this call is not in the paused state */ public OneShotContinuation getCurrentContinuation() { int version = currentVersion.get(); if (!isPaused(version)) { State s = versionToState(version); throw new IllegalStateException("Cannot get continuation of a " + s + " call"); } else { return new CallContinuation(version); } }
private Call( StateContext stateContext, ReturnBuffer returnBuffer, Coroutine mainCoroutine) { this.stateContext = Objects.requireNonNull(stateContext); this.returnBuffer = Objects.requireNonNull(returnBuffer); this.coroutineStack = new Cons<>(Objects.requireNonNull(mainCoroutine)); int startingVersion = newPausedVersion(0); this.currentVersion = new AtomicInteger(startingVersion); }
/** * Constructs a new {@code Call} object representing the call to the object {@code fn} * with the arguments stored in {@code args}, in the context of the Lua state {@code state}. * * <p>The call will be initialised in the {@link State#PAUSED paused state}.</p> * * @param stateContext state context used by the call, must not be {@code null} * @param returnBufferFactory return buffer factory used by the call, must not be {@code null} * @param fn the call target, may be any value * @param args the array of call arguments, must not be {@code null} * @return a new {@code Call} object * * @throws NullPointerException if {@code stateContext}, {@code returnBufferFactory} * or {@code args} is {@code null} */ public static Call init( StateContext stateContext, ReturnBufferFactory returnBufferFactory, Object fn, Object... args) { ReturnBuffer returnBuffer = returnBufferFactory.newInstance(); Coroutine c = new Coroutine(fn); returnBuffer.setToContentsOf(args); return new Call(stateContext, returnBuffer, c); }
private void resume(CallEventHandler handler, SchedulingContext schedulingContext, int version) { Objects.requireNonNull(handler); Objects.requireNonNull(schedulingContext); if (version == VERSION_RUNNING || version == VERSION_TERMINATED) { throw new IllegalArgumentException("Illegal version: " + version); } // claim this version if (!currentVersion.compareAndSet(version, VERSION_RUNNING)) { throw new InvalidContinuationException("Cannot resume call: not in the expected state (0x" + Integer.toHexString(version) + ")"); } int newVersion = VERSION_TERMINATED; ResumeResult rr = null; OneShotContinuation cont = null; try { Resumer resumer = new Resumer(schedulingContext); rr = resumer.resume(); assert (rr != null); if (rr.pause || rr.asyncTask != null) { newVersion = newPausedVersion(version); cont = new CallContinuation(newVersion); } } finally { int old = currentVersion.getAndSet(newVersion); assert (old == VERSION_RUNNING); } assert (rr != null); rr.fire(handler, this, cont); }