use of il.ac.bgu.cs.bp.bpjs.execution.listeners.BProgramRunnerListener in project BPjs by bThink-BGU.
the class BProgramSyncSnapshot method triggerEvent.
/**
* Runs the program from the snapshot, triggering the passed event.
* @param exSvc the executor service that will advance the threads.
* @param anEvent the event selected.
* @param listeners
* @return A set of b-thread snapshots that should participate in the next cycle.
* @throws InterruptedException
*/
public BProgramSyncSnapshot triggerEvent(BEvent anEvent, ExecutorService exSvc, Iterable<BProgramRunnerListener> listeners) throws InterruptedException {
if (anEvent == null)
throw new IllegalArgumentException("Cannot trigger a null event.");
if (triggered) {
throw new IllegalStateException("A BProgramSyncSnapshot is not allowed to be triggered twice.");
}
triggered = true;
Set<BThreadSyncSnapshot> resumingThisRound = new HashSet<>(threadSnapshots.size());
Set<BThreadSyncSnapshot> sleepingThisRound = new HashSet<>(threadSnapshots.size());
Set<BThreadSyncSnapshot> nextRound = new HashSet<>(threadSnapshots.size());
List<BEvent> nextExternalEvents = new ArrayList<>(getExternalEvents());
try {
Context ctxt = Context.enter();
handleInterrupts(anEvent, listeners, bprog, ctxt);
nextExternalEvents.addAll(bprog.drainEnqueuedExternalEvents());
// Split threads to those that advance this round and those that sleep.
threadSnapshots.forEach(snapshot -> {
(snapshot.getBSyncStatement().shouldWakeFor(anEvent) ? resumingThisRound : sleepingThisRound).add(snapshot);
});
} finally {
Context.exit();
}
BPEngineTask.Listener halter = new HaltOnAssertion(exSvc);
try {
// add the run results of all those who advance this stage
nextRound.addAll(exSvc.invokeAll(resumingThisRound.stream().map(bt -> new ResumeBThread(bt, anEvent, halter)).collect(toList())).stream().map(f -> safeGet(f)).filter(Objects::nonNull).collect(toList()));
// inform listeners which b-threads completed
Set<String> nextRoundIds = nextRound.stream().map(t -> t.getName()).collect(toSet());
resumingThisRound.stream().filter(t -> !nextRoundIds.contains(t.getName())).forEach(t -> listeners.forEach(l -> l.bthreadDone(bprog, t)));
executeAllAddedBThreads(nextRound, exSvc, halter);
nextExternalEvents.addAll(bprog.drainEnqueuedExternalEvents());
// carry over BThreads that did not advance this round to next round.
nextRound.addAll(sleepingThisRound);
return new BProgramSyncSnapshot(bprog, nextRound, nextExternalEvents, violationRecord.get());
} catch (RejectedExecutionException ree) {
// The executor thread pool must have been shut down, e.g. due to program violation.
return new BProgramSyncSnapshot(bprog, Collections.emptySet(), nextExternalEvents, violationRecord.get());
}
}
use of il.ac.bgu.cs.bp.bpjs.execution.listeners.BProgramRunnerListener in project BPjs by bThink-BGU.
the class BProgramSyncSnapshot method handleInterrupts.
private void handleInterrupts(BEvent anEvent, Iterable<BProgramRunnerListener> listeners, BProgram bprog, Context ctxt) {
Set<BThreadSyncSnapshot> interrupted = threadSnapshots.stream().filter(bt -> bt.getBSyncStatement().getInterrupt().contains(anEvent)).collect(toSet());
if (!interrupted.isEmpty()) {
threadSnapshots.removeAll(interrupted);
interrupted.forEach(bt -> {
listeners.forEach(l -> l.bthreadRemoved(bprog, bt));
bt.getInterrupt().ifPresent(func -> {
final Scriptable scope = bt.getScope();
// can't call bsync from a break handler.
scope.delete("bsync");
try {
ctxt.callFunctionWithContinuations(func, scope, new Object[] { anEvent });
} catch (ContinuationPending ise) {
throw new BProgramException("Cannot call bsync from a break-upon handler. Please consider pushing an external event.");
}
});
});
}
}
Aggregations