From: jjenista Date: Fri, 8 Apr 2011 22:38:01 +0000 (+0000) Subject: detect possibly evil tasks and do the right thing if a possibly evil execution patter... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=8a563edcd624df99248fe602c8463012702c5197;p=IRC.git detect possibly evil tasks and do the right thing if a possibly evil execution pattern is detected --- diff --git a/Robust/src/Analysis/Disjoint/ProcessStateMachines.java b/Robust/src/Analysis/Disjoint/ProcessStateMachines.java index cc87d828..0008324b 100644 --- a/Robust/src/Analysis/Disjoint/ProcessStateMachines.java +++ b/Robust/src/Analysis/Disjoint/ProcessStateMachines.java @@ -22,6 +22,7 @@ public class ProcessStateMachines { computeConflictEffects(); prune(); merge(); + protectAgainstEvilTasks(); } private void merge() { @@ -305,4 +306,41 @@ public class ProcessStateMachines { } } } + + + private void protectAgainstEvilTasks() { + for( Pair machinepair: bsm.getAllMachineNames() ) { + StateMachineForEffects sm = bsm.getStateMachine( machinepair ); + protectAgainstEvilTasks( sm ); + } + } + + private void protectAgainstEvilTasks( StateMachineForEffects sm ) { + // first identify the set of pairs for which this + // traverser will both read and write, remember the read effect + Set allocAndFieldRW = new HashSet(); + for( Pair af: sm.effectsMap.keySet() ) { + Integer effectType = sm.effectsMap.get( af ); + if( (effectType & Effect.read) != 0 && + (effectType & Effect.write) != 0 + ) { + allocAndFieldRW.add( new Effect( af.getFirst(), + Effect.read, + af.getSecond() + ) + ); + } + } + + // next check the state machine: if an effect that initiates + // a transition is in the allocAndFieldRW set, then mark it + // as... POSSIBLY EVIL!!!!! + for( SMFEState state: sm.getStates() ) { + for( Effect effect: state.getTransitionEffects() ) { + if( allocAndFieldRW.contains( effect ) ) { + sm.addPossiblyEvilEffect( effect ); + } + } + } + } } \ No newline at end of file diff --git a/Robust/src/Analysis/Disjoint/SMFEState.java b/Robust/src/Analysis/Disjoint/SMFEState.java index 9f3857af..d08811ed 100644 --- a/Robust/src/Analysis/Disjoint/SMFEState.java +++ b/Robust/src/Analysis/Disjoint/SMFEState.java @@ -101,7 +101,7 @@ public class SMFEState { return conflicts; } - public Set getTransistionEffects() { + public Set getTransitionEffects() { return this.e2states.keySet(); } diff --git a/Robust/src/Analysis/Disjoint/StateMachineForEffects.java b/Robust/src/Analysis/Disjoint/StateMachineForEffects.java index c8655883..11127375 100644 --- a/Robust/src/Analysis/Disjoint/StateMachineForEffects.java +++ b/Robust/src/Analysis/Disjoint/StateMachineForEffects.java @@ -31,11 +31,23 @@ public class StateMachineForEffects { protected FlatNode fn; protected int id=0; + // We have a situation in which a task can start executing + // and "evil-ly" destroy the paths to all the objects it will + // access as it goes along. If this is the case, a traverser + // should know which effects these are, and if the traverser + // is ever running and detects that the task is also running, + // it should not continue (and therefore hold up any tasks that + // might come later, because now we might never be able to find + // the effects that should block later tasks). Should be rare! + protected Set possiblyEvilEffects; + + public StateMachineForEffects( FlatNode fnInitial ) { fn2state = new Hashtable(); effectsMap = new HashMap, Integer>(); initialState = getState( startNode ); this.fn=fnInitial; + possiblyEvilEffects = new HashSet(); } public Set getStates() { @@ -110,6 +122,16 @@ public class StateMachineForEffects { return 0; } + + public void addPossiblyEvilEffect( Effect e ) { + possiblyEvilEffects.add( e ); + } + + public Set getPossiblyEvilEffects() { + return possiblyEvilEffects; + } + + public void writeAsDOT( String graphName ) { graphName = graphName.replaceAll( "[\\W]", "" ); diff --git a/Robust/src/IR/Flat/RuntimeConflictResolver.java b/Robust/src/IR/Flat/RuntimeConflictResolver.java index 9b580b4d..96c2a536 100644 --- a/Robust/src/IR/Flat/RuntimeConflictResolver.java +++ b/Robust/src/IR/Flat/RuntimeConflictResolver.java @@ -186,7 +186,7 @@ public class RuntimeConflictResolver { cFile.println(" if(traverserState=="+state.getID()+") {"); } - printAllocChecksInsideState(state, taskOrStallSite, var, "ptr", 0, weakID); + printAllocChecksInsideState(smfe, state, taskOrStallSite, var, "ptr", 0, weakID); cFile.println(" break;"); } @@ -225,7 +225,7 @@ public class RuntimeConflictResolver { cFile.flush(); } - public void printAllocChecksInsideState(SMFEState state, FlatNode fn, TempDescriptor tmp, String prefix, int depth, int weakID) { + public void printAllocChecksInsideState(StateMachineForEffects smfe, SMFEState state, FlatNode fn, TempDescriptor tmp, String prefix, int depth, int weakID) { EffectsTable et = new EffectsTable(state); boolean needswitch=et.getAllAllocs().size()>1; if (needswitch) { @@ -239,7 +239,7 @@ public class RuntimeConflictResolver { } else { cFile.println(" if("+prefix+"->"+allocSite+"=="+a.getUniqueAllocSiteID()+") {"); } - addChecker(a, fn, tmp, state, et, prefix, depth, weakID); + addChecker(smfe, a, fn, tmp, state, et, prefix, depth, weakID); if (needswitch) { cFile.println(" }"); cFile.println(" break;"); @@ -252,7 +252,7 @@ public class RuntimeConflictResolver { cFile.println(" }"); } - public void addChecker(Alloc a, FlatNode fn, TempDescriptor tmp, SMFEState state, EffectsTable et, String prefix, int depth, int weakID) { + public void addChecker(StateMachineForEffects smfe, Alloc a, FlatNode fn, TempDescriptor tmp, SMFEState state, EffectsTable et, String prefix, int depth, int weakID) { if (depth>30) { System.out.println(fn+" "+state+" "+state.toStringDOT()); } @@ -275,7 +275,18 @@ public class RuntimeConflictResolver { cFile.println(" for(i = 0; i<((struct ArrayObject *) " + prefix + " )->___length___; i++ ) {"); first=false; } - printRefSwitch(fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID); + printRefSwitch(smfe, fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID); + + // only if we are traversing for a new task, not a stall site + if( (fn instanceof FlatSESEEnterNode) && + smfe.getPossiblyEvilEffects().contains( e ) ) { + + FlatSESEEnterNode evilTask = (FlatSESEEnterNode)fn; + + detectPossiblyEvilExecution( evilTask, + evilTask.getInVarsForDynamicCoarseConflictResolution().indexOf( tmp ) + ); + } } } if (!first) @@ -288,13 +299,24 @@ public class RuntimeConflictResolver { for(Effect e: et.getEffects(a)) { if (!state.transitionsTo(e).isEmpty()) { String childPtr = "((struct "+a.getType().getSafeSymbol()+" *)"+prefix +")->" + e.getField().getSafeSymbol(); - printRefSwitch(fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID); + printRefSwitch(smfe, fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID); + + // only if we are traversing for a new task, not a stall site + if( (fn instanceof FlatSESEEnterNode) && + smfe.getPossiblyEvilEffects().contains( e ) ) { + + FlatSESEEnterNode evilTask = (FlatSESEEnterNode)fn; + + detectPossiblyEvilExecution( evilTask, + evilTask.getInVarsForDynamicCoarseConflictResolution().indexOf( tmp ) + ); + } } } } } - private void printRefSwitch(FlatNode fn, TempDescriptor tmp, int pdepth, String childPtr, String currPtr, Set transitions, int weakID) { + private void printRefSwitch(StateMachineForEffects smfe, FlatNode fn, TempDescriptor tmp, int pdepth, String childPtr, String currPtr, Set transitions, int weakID) { for(SMFEState tr: transitions) { if(tr.getRefCount() == 1) { //in-lineable case @@ -302,7 +324,7 @@ public class RuntimeConflictResolver { cFile.println(" "+currPtr+"= (struct ___Object___ * ) " + childPtr + ";"); cFile.println(" if (" + currPtr + " != NULL) { "); - printAllocChecksInsideState(tr, fn, tmp, currPtr, pdepth+1, weakID); + printAllocChecksInsideState(smfe, tr, fn, tmp, currPtr, pdepth+1, weakID); cFile.println(" }"); //break for internal switch and if } else { //non-inlineable cases @@ -345,6 +367,36 @@ public class RuntimeConflictResolver { } } + + private void detectPossiblyEvilExecution( FlatSESEEnterNode possiblyEvilTask, + int rcrRecordIndex + ) { + // We have a situation in which a task can start executing and + // "evil-ly" destroy the paths to some objects it will access as + // it goes along. If this is the case, a traverser should not + // continue and instead intentionally hold up any tasks that might + // come later, because now we might never be able to find the + // effects that should block later tasks. This should be rare! + cFile.append("// a possibly evil task has been detected!\n"); + cFile.append("BARRIER();\n"); + cFile.append("if( unlikely( record->common.unresolvedDependencies == 0 &&"); + cFile.append( "BARRIER() &&"); + cFile.append( "record->common.doneExecuting == FALSE ) ) {\n"); + cFile.append(" // first abort this traversal, doesn't matter what the flag is because\n"); + cFile.append(" // the traverser is not going to clear the task, it's already running...\n"); + cFile.append(" int flag = LOCKXCHG32( &(record->rcrRecords["+rcrRecordIndex+"].flag), 0 );\n"); + cFile.append(" \n"); + cFile.append(" // just wait for the the task to retire...\n"); + cFile.append(" while( record->common.doneExecuting == FALSE ) {\n"); + cFile.append(" BARRIER();\n"); + cFile.append(" }\n"); + cFile.append(" \n"); + cFile.append(" // and now its safe to release the traverser to clear other tasks\n"); + cFile.append(" return;\n"); + cFile.append("}\n"); + } + + private void setupOutputFiles(String buildir) throws FileNotFoundException { cFile = new CodePrinter(new File(buildir + "RuntimeConflictResolver" + ".c")); headerFile = new CodePrinter(new File(buildir + "RuntimeConflictResolver" + ".h"));