package emulatorinterface; import java.util.ArrayList; import java.util.Hashtable; import java.util.LinkedList; //import org.apache.log4j.Logger; import emulatorinterface.communication.Encoding; import emulatorinterface.communication.IpcBase; public class SynchPrimitive implements Encoding { // private static final Logger logger = Logger.getLogger(SynchPrimitive.class); private static final boolean debugMode = true; LinkedList entries; long address; public SynchPrimitive(long addressSynchItem, int thread, long time, long value, IpcBase ipcType) { this.address = addressSynchItem; this.entries = new LinkedList(); entries.add(new SynchType(thread, time, value)); } private int putOnTimedWait(int thread, long time, long value) { Hashtable stateTable = IpcBase.glTable .getStateTable(); ThreadState ts = stateTable.get(thread); LinkedList others = new LinkedList(); // add dependencies bothways for (ThreadState otherThreads : stateTable.values()) { if (otherThreads.lastTimerseen < time && otherThreads.threadIndex!=thread) { otherThreads.addDep(address, time, thread); others.add(otherThreads.threadIndex); } } if (others.size()!=0) { if(debugMode) System.out.println(this.address+" "+thread+" `"+value+"`, going on a timedWait on "+others.size()+" threads"); stateTable.get((Integer)thread).countTimedSleep++; ts.addressMap.put(address, new PerAddressInfoNew(others, time, address,true)); entries.add(new SynchType(thread, time, value)); } else { if(debugMode) System.out.println(this.address+" "+thread+" `"+value+"`, no TimedWait "); ts.addressMap.remove(address); } return others.size(); } ResumeSleep sigEnter(int thread, long time, long value) { boolean done = false; //int interactingThread = -1; ResumeSleep ret = new ResumeSleep(); SynchType toBeRemoved1 = null, toBeRemoved2 = null; for (SynchType entry : entries) { // if a wait enter before if (entry.encoding == CONDWAIT && entry.time < time && entry.thread != thread) { for (SynchType exit : entries) { // if a wait exit after if (exit.encoding == CONDWAIT + 1 && exit.time > time && exit.thread == entry.thread) { if(debugMode) System.out.println(this.address+" "+thread+" sigenter, got waitenter & exit from "+exit.thread); if (done) misc.Error.shutDown("Duplicate entry in sigEnter"); //interactingThread = exit.thread; ret.addResumer(exit.thread); done = true; toBeRemoved1 = entry; toBeRemoved2 = exit; Hashtable stateTable = IpcBase.glTable.getStateTable(); stateTable.get(exit.thread).addressMap.remove(address); stateTable.get(thread).addressMap.remove(address); break; } } } if (done) break; } if (!done) { int otherThreads = putOnTimedWait(thread, time, value); if (otherThreads==0) { System.out.println("SynchPrimitive: Spurious signal received"); //interactingThread = -2; // means nobody sleeps/resumes } else ret.addSleeper(thread); } else { entries.remove(toBeRemoved1); entries.remove(toBeRemoved2); } /* if (interactingThread==-1) ret.addSleeper(thread); else if (interactingThread==-2) {} else { ret.addResumer(interactingThread); } */ return ret; } ResumeSleep waitEnter(int thread, long time, long value) { //System.out.println(this.address+" "+" waitEnter"); entries.add(new SynchType(thread, time, value)); ResumeSleep ret = new ResumeSleep(); ret.addSleeper(thread); return ret; } ResumeSleep waitExit(int thread, long time, long value) { boolean done = false; //int interactingThread = -1; ResumeSleep ret = new ResumeSleep(); SynchType toBeRemoved1 = null, toBeRemoved2 = null; for (SynchType entry : entries) { // if this thread entered if (entry.encoding == CONDWAIT && entry.time < time && entry.thread == thread) { for (SynchType sig : entries) { // if a signal by some other thread found if (sig.encoding == SIGNAL && sig.time < time && sig.time > entry.time && sig.thread!=thread) { if (done) misc.Error.shutDown("Duplicate entry in wEx"); if(debugMode) System.out.println(this.address+" "+thread+" waitexit, got signal dep on "+sig.thread); //interactingThread = sig.thread; ret.addResumer(sig.thread); ret.addResumer(thread); done = true; toBeRemoved1 = entry; toBeRemoved2 = sig; Hashtable stateTable = IpcBase.glTable .getStateTable(); stateTable.get(sig.thread).addressMap .remove(address); stateTable.get(thread).addressMap.remove(address); break; } } } if (done) break; //if (entry.encoding == BCAST && entry.time < time) } if (!done) { // XXX the only difference between lock/unlock and wait/signal is here. // as we are not going for a timedWait but original wait. entries.add(new SynchType(thread, time, value)); //interactingThread = -2; } else { entries.remove(toBeRemoved1); if (toBeRemoved2!=null) entries.remove(toBeRemoved2); } /*if (interactingThread==-1) ret.addSleeper(thread); else if (interactingThread==-2) {} else { ret.addResumer(interactingThread); ret.addResumer(thread); }*/ return ret; } ResumeSleep unlockEnter(int thread, long time, long value) { boolean done = false; ResumeSleep ret = new ResumeSleep(); // int interactingThread = -1; SynchType toBeRemoved1 = null, toBeRemoved2 = null; for (SynchType entry : entries) { // if a lock enter before if (entry.encoding == LOCK && entry.time < time && entry.thread!=thread) { for (SynchType exit : entries) { // if a lock exit after if (exit.encoding == LOCK + 1 && exit.time > time && exit.thread == entry.thread) { if(debugMode) System.out.println(this.address+" "+thread+" unlockenter, got lockenter and lockexit from "+exit.thread); if (done) misc.Error.shutDown("Duplicate entry in unlockEnter"); //XXXinteractingThread = exit.thread; ret.addResumer(exit.thread); done = true; toBeRemoved1 = entry; toBeRemoved2 = exit; Hashtable stateTable = IpcBase.glTable .getStateTable(); stateTable.get(exit.thread).addressMap .remove(address); stateTable.get(thread).addressMap.remove(address); break; } } } if (done) break; } if (!done) { //May never get a corresponding lockenter lockexit //so do a timed wait. int otherThreads = putOnTimedWait(thread, time, value); //XXX if (otherThreads==0) interactingThread = -2;// means nobody sleeps/resumes if (otherThreads!=0) ret.addSleeper(thread); } else { entries.remove(toBeRemoved1); entries.remove(toBeRemoved2); } /*XXX if (interactingThread==-1) ret.addSleeper(thread); else if (interactingThread==-2) {} else { ret.addResumer(interactingThread); }*/ return ret; } ResumeSleep lockEnter(int thread, long time, long value) { if(debugMode) System.out.println(this.address+" "+thread+" lockenter"); entries.add(new SynchType(thread, time, value)); ResumeSleep ret = new ResumeSleep(); ret.addSleeper(thread); return ret; } ResumeSleep lockExit(int thread, long time, long value) { boolean done = false; //int interactingThread = -1; ResumeSleep ret = new ResumeSleep(); SynchType toBeRemoved1 = null, toBeRemoved2 = null; for (SynchType entry : entries) { // if this thread entered if (entry.encoding == LOCK && entry.time < time && entry.thread == thread) { for (SynchType unlock : entries) { // if an unlock by some other thread found if (unlock.encoding == UNLOCK && unlock.time < time && unlock.time > entry.time && unlock.thread!=thread) { if(debugMode) System.out.println(this.address+" "+thread+" lockexit, got unlock dep on "+unlock.thread); //XXXinteractingThread = unlock.thread; ret.addResumer(unlock.thread); ret.addResumer(thread); done = true; toBeRemoved1 = entry; toBeRemoved2 = unlock; Hashtable stateTable = IpcBase.glTable .getStateTable(); stateTable.get(unlock.thread).addressMap .remove(address); stateTable.get(thread).addressMap.remove(address); break; } } } if (done) break; } if (!done) { // lock enter and lock exit seen but no unlock enter. so // wait till others pass its time int otherThreads = putOnTimedWait(thread, time, value); if (otherThreads==0) ret.addResumer(thread); /*if (otherThreads == 0) interactingThread = thread; else interactingThread = -2;*/ } else { entries.remove(toBeRemoved1); if(toBeRemoved2!=null) entries.remove(toBeRemoved2); } /* if (interactingThread==-1) ret.addSleeper(thread); else if (interactingThread==-2) {} else if (interactingThread==thread){ ret.addResumer(thread); } else { ret.addResumer(interactingThread); ret.addResumer(thread); }*/ return ret; } //check if "waitenter before" and "waitexit after/or not available" ResumeSleep broadcastResume(long broadcastTime, int thread) { ResumeSleep ret = new ResumeSleep(); ArrayList toBeRemoved = new ArrayList(); for (SynchType entry : entries) { if (entry.encoding == BCAST && entry.thread==thread) { ret.addResumer(entry.thread); toBeRemoved.add(entry); } boolean exitPresent = false; if (entry.encoding == CONDWAIT && entry.timebroadcastTime && exit.thread==entry.thread) { // resume these thread ret.addResumer(exit.thread); toBeRemoved.add(entry); } if (exit.encoding == CONDWAIT+1 && exit.time>entry.time) { exitPresent = true; // this means it is a stale entry } } if (!exitPresent) { //no exit, ONLY enter, resume these as well ret.addResumer(entry.thread); toBeRemoved.add(entry); } } } for(SynchType rem : toBeRemoved) { entries.remove(rem); } return ret; } ResumeSleep broadcastEnter(int thread, long time, long value) { if(debugMode) System.out.println(this.address+" "+thread+" broadcastenter"); ResumeSleep ret = new ResumeSleep(); Hashtable stateTable = IpcBase.glTable.getStateTable(); if (putOnTimedWait(thread, time, value)==0) { //return all threads which were waiting to resume ArrayList toBeRemoved = new ArrayList(); for (SynchType entry : entries ) { if (entry.encoding == CONDWAIT && entry.time < time && entry.thread != thread) { for (SynchType exit : entries) { if (exit.encoding == CONDWAIT+1 && exit.time > time && exit.thread==entry.thread) { ret.addResumer(exit.thread); stateTable.get(exit.thread).addressMap.remove(address); toBeRemoved.add(entry); toBeRemoved.add(exit); } } } } stateTable.get(thread).addressMap.remove(address); for (SynchType t : toBeRemoved) { entries.remove(t); } } else { PerAddressInfoNew p = stateTable.get(thread).addressMap.get(address); p.on_broadcast = true; p.broadcastTime = time; // Not all threads have passed in time. entries.add(new SynchType(thread, time, value)); ret.addSleeper(thread); } return ret; } public ResumeSleep barrierEnter(int thread, long time, long value) { if(debugMode) System.out.println(this.address+" "+thread+" barrierenter"); entries.add(new SynchType(thread, time, value)); ResumeSleep ret = new ResumeSleep(); ret.addSleeper(thread); return ret; } public ResumeSleep barrierExit(int thread, long time, long value) { if(debugMode) System.out.println(this.address+" "+thread+" barrierexit"); Hashtable stateTable = IpcBase.glTable.getStateTable(); ResumeSleep ret = new ResumeSleep(); if (putOnTimedWait(thread, time, value)==0) { ArrayList toBeRemoved = new ArrayList(); for (SynchType entry : entries ) { if (entry.encoding==BARRIERWAIT) { ret.addResumer(entry.thread); stateTable.get(entry.thread).addressMap.remove(address); toBeRemoved.add(entry); } } stateTable.get(thread).addressMap.remove(address); for (SynchType t : toBeRemoved) { entries.remove(t); } } else { PerAddressInfoNew p = stateTable.get(thread).addressMap.get(address); p.on_barrier = true; } return ret; } public ResumeSleep barrierResume() { ResumeSleep ret = new ResumeSleep(); ArrayList toBeRemoved = new ArrayList(); for (SynchType entry : entries) { if (entry.encoding == BARRIERWAIT) { ret.addResumer(entry.thread); toBeRemoved.add(entry); } } for(SynchType t : toBeRemoved) { entries.remove(t); } return ret; } }