use of com.cloudbees.groovy.cps.impl.CpsCallableInvocation in project groovy-cps by cloudbees.
the class GreenThread method start.
/**
* Creates a new green thread that executes the given closure.
*/
public void start() {
Block b;
try {
run();
// closure had run synchronously.
b = Block.NOOP;
} catch (CpsCallableInvocation inv) {
// this will create a thread, and resume with the newly created thread
b = inv.asBlock();
} catch (Throwable t) {
// closure had run synchronously and failed
b = new ThrowBlock(new ConstantBlock(t));
}
final Block bb = b;
invoke(new ThreadTask() {
public Result eval(GreenWorld w) {
w = w.withNewThread(new GreenThreadState(GreenThread.this, bb));
return new Result(w, new Outcome(GreenThread.this, null), false);
}
});
// thus the code will never reach here
throw new AssertionError();
}
use of com.cloudbees.groovy.cps.impl.CpsCallableInvocation in project groovy-cps by cloudbees.
the class BasicTest method exceptionStackUnwinding.
/**
* An exception thrown in a function caught by another function
*/
@Test
public void exceptionStackUnwinding() {
class Op {
/**
* if (0<depth)
* throw_(depth-1,message);
* else
* throw new IllegalArgumentException(message)
*/
public void throw_(int depth, String message) {
Block $depth = b.localVariable("depth");
CpsFunction f = new CpsFunction(asList("depth", "message"), b.block(b.if_(b.lessThan(0, b.zero(), $depth), b.functionCall(0, b.this_(), "throw_", b.minus(0, $depth, b.one()), b.localVariable("message")), // else
b.throw_(0, b.new_(0, IllegalArgumentException.class, b.localVariable("message"))))));
throw new CpsCallableInvocation(f, this, depth, message);
}
}
/*
int x;
try {
x = 1;
new Op().throw_(3,"hello")
x = 2; // make sure this line gets skipped
} catch (Exception e) {
return e.message + x;
}
*/
assertEquals("hello1", run(// part of the test is to ensure this 'z' is separated from 'z' in the add function
b.setLocalVariable(0, "x", b.zero()), b.tryCatch(b.block(b.setLocalVariable(0, "x", b.one()), b.functionCall(0, b.constant(new Op()), "throw_", b.constant(3), b.constant("hello")), b.setLocalVariable(0, "x", b.two())), null, new CatchExpression(Exception.class, "e", b.return_(b.plus(0, b.property(0, b.localVariable("e"), "message"), b.localVariable("x")))))));
}
use of com.cloudbees.groovy.cps.impl.CpsCallableInvocation in project groovy-cps by cloudbees.
the class Continuable method wrap.
private static Next wrap(Script s, Env env, Continuation k) {
try {
Method m = s.getClass().getMethod("run");
if (!m.isAnnotationPresent(WorkflowTransformed.class))
throw new IllegalArgumentException(s + " is not CPS-transformed");
s.run();
throw new AssertionError("I'm confused if Script is CPS-transformed or not!");
} catch (CpsCallableInvocation e) {
return e.invoke(env, null, k);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
use of com.cloudbees.groovy.cps.impl.CpsCallableInvocation in project workflow-cps-plugin by jenkinsci.
the class CpsBodyExecution method launch.
/**
* Starts evaluating the body.
*
* If the body is a synchronous closure, this method evaluates the closure synchronously.
* Otherwise, the body is asynchronous and the method schedules another thread to evaluate the body.
*
* @param currentThread
* The thread whose context the new thread will inherit.
*/
@CpsVmThreadOnly
/*package*/
void launch(CpsBodyInvoker params, CpsThread currentThread, FlowHead head) {
if (isLaunched())
throw new IllegalStateException("Already launched");
StepStartNode sn = addBodyStartFlowNode(head);
for (Action a : params.startNodeActions) {
if (a != null)
sn.addAction(a);
}
head.setNewHead(sn);
CpsFlowExecution.maybeAutoPersistNode(sn);
StepContext sc = new CpsBodySubContext(context, sn);
for (BodyExecutionCallback c : callbacks) {
c.onStart(sc);
}
try {
// TODO: handle arguments to closure
Object x = params.body.getBody(currentThread).call();
// pointless synchronization to make findbugs happy. This is already done, so there's no cancelling this anyway.
synchronized (this) {
this.thread = currentThread;
}
onSuccess.receive(x);
} catch (CpsCallableInvocation e) {
// execute this closure asynchronously
// TODO: does it make sense that the new thread shares the same head?
CpsThread t = currentThread.group.addThread(createContinuable(currentThread, e), head, ContextVariableSet.from(currentThread.getContextVariables(), params.contextOverrides));
// due to earlier cancellation
synchronized (this) {
t.resume(new Outcome(null, stopped));
assert this.thread == null;
this.thread = t;
}
} catch (Throwable t) {
// body has completed synchronously and abnormally
synchronized (this) {
this.thread = currentThread;
}
onFailure.receive(t);
}
}
Aggregations