public BProgramSyncSnapshot triggerEvent ( BEvent anEvent , ExecutorService exSvc , Iterable < BProgramRunnerListener > listeners ) throws InterruptedException , BPjsRuntimeException { 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 . getSyncStatement ( ) . shouldWakeFor ( anEvent ) ? resumingThisRound : sleepingThisRound ) . add ( snapshot ) ; } ) ; } finally { Context . exit ( ) ; } BPEngineTask . Listener halter = new ViolationRecorder ( bprog , violationRecord ) ; // add the run results of all those who advance this stage try { 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 ) ; } catch ( RuntimeException re ) { Throwable cause = re ; while ( cause . getCause ( ) != null ) { cause = cause . getCause ( ) ; } if ( cause instanceof BPjsRuntimeException ) { throw ( BPjsRuntimeException ) cause ; } else if ( cause instanceof EcmaError ) { throw new BPjsRuntimeException ( "JavaScript Error: " + cause . getMessage ( ) , cause ) ; } else throw re ; } 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 ( ) ) ; }
Runs the program from the snapshot triggering the passed event .