static void ts_set_preStateOnError(ShadowThread ts, FastTrackGuardState v) { Assert.panic("Bad"); }
private void error( final AccessEvent ae, final int errorCase, final String prevOp, final int prevTid, final String curOp, final int curTid) { try { if (ae instanceof FieldAccessEvent) { FieldAccessEvent fae = (FieldAccessEvent) ae; final FieldInfo fd = fae.getInfo().getField(); final ShadowThread currentThread = fae.getThread(); final Object target = fae.getTarget(); fieldErrors.error( currentThread, fd, "Guard State", fae.getOriginalShadow(), "Current Thread", toString(currentThread), "Class", target == null ? fd.getOwner() : target.getClass(), "Field", Util.objectToIdentityString(target) + "." + fd, "Prev Op", prevOp + prevTid, "Cur Op", curOp + curTid, "Case", "#" + errorCase, "Stack", ShadowThread.stackDumpForErrorMessage(currentThread)); if (!fieldErrors.stillLooking(fd)) { advance(ae); return; } } else { ArrayAccessEvent aae = (ArrayAccessEvent) ae; final ShadowThread currentThread = aae.getThread(); final Object target = aae.getTarget(); arrayErrors.error( currentThread, aae.getInfo(), "Alloc Site", ArrayAllocSiteTracker.allocSites.get(aae.getTarget()), "Guard State", aae.getOriginalShadow(), "Current Thread", toString(currentThread), "Array", Util.objectToIdentityString(target) + "[" + aae.getIndex() + "]", "Prev Op", prevOp + prevTid + ("name = " + ShadowThread.get(prevTid).getThread().getName()), "Cur Op", curOp + curTid + ("name = " + ShadowThread.get(curTid).getThread().getName()), "Case", "#" + errorCase, "Stack", ShadowThread.stackDumpForErrorMessage(currentThread)); aae.getArrayState().specialize(); if (!arrayErrors.stillLooking(aae.getInfo())) { advance(aae); return; } } } catch (Throwable e) { Assert.panic(e); } }
/** *** */ static FastTrackGuardState ts_get_preStateOnError(ShadowThread ts) { Assert.panic("Bad"); return null; }
@Override public void access(final AccessEvent fae) { final ShadowVar var = fae.getOriginalShadow(); final ShadowThread td = fae.getThread(); if (var instanceof FastTrackGuardState) { // load the error guard state set by the fast path if it exists. final FastTrackGuardState isItAnError = ts_get_preStateOnError(td); final FastTrackGuardState x = (isItAnError != null) ? isItAnError : (FastTrackGuardState) var; ts_set_preStateOnError(td, null); final int tdEpoch = ts_get_epoch(td); final CV tdCV = ts_get_cv(td); Object target = fae.getTarget(); if (target == null) { CV initTime = classInitTime.get(((FieldAccessEvent) fae).getInfo().getField().getOwner()); tdCV.max(initTime); } if (!fae.isWrite()) { // READ retry: do { final long orig = x.getWREpochs(); final int lastReadEpoch = EpochPair.read(orig); if (lastReadEpoch == tdEpoch) { break; // commit : same epoch } final int tid = td.getTid(); final int lastWriteEpoch = EpochPair.write(orig); if (lastReadEpoch == Epoch.READ_SHARED) { if (x.get(tid) != tdEpoch) { // (*) racy access -> should be fine. synchronized (x) { if (orig != x.getWREpochs()) { Yikes.yikes("concurrent mod"); continue retry; } x.set(tid, tdEpoch); } } } else { final int lastReader = Epoch.tid(lastReadEpoch); if (lastReader == tid) { if (!x.cas(orig, lastWriteEpoch, tdEpoch)) { Yikes.yikes("concurrent mod"); continue retry; } // commit: read-exclusive fast case } else if (lastReadEpoch <= tdCV.get(lastReader)) { if (!x.cas(orig, lastWriteEpoch, tdEpoch)) { Yikes.yikes("concurrent mod"); continue retry; } // commit: read-exclusive slow case } else { synchronized (x) { x.makeCV(INIT_CV_SIZE); // do first, in case we need it at (*) if (!x.cas(orig, lastWriteEpoch, Epoch.READ_SHARED)) { Yikes.yikes("concurrent mod"); continue retry; } // commit: read share x.set(lastReader, lastReadEpoch); x.set(td.getTid(), tdEpoch); } } } final int lastWriter = Epoch.tid(lastWriteEpoch); if (lastWriter != tid && lastWriteEpoch > tdCV.get(lastWriter)) { error(fae, 4, "write-by-thread-", lastWriter, "read-by-thread-", tid); } } while (false); // awesome... } else { // WRITE retry: do { final long orig = x.getWREpochs(); final int lastWriteEpoch = EpochPair.write(orig); if (lastWriteEpoch == tdEpoch) { break; // commit: same epoch } final int tid = td.getTid(); final int lastReadEpoch = EpochPair.read(orig); if (lastReadEpoch == tdEpoch) { if (!x.cas(orig, tdEpoch, tdEpoch)) { Yikes.yikes("concurrent mod"); continue retry; } // commit: write exclusive fast case } else if (lastReadEpoch != Epoch.READ_SHARED) { if (!x.cas(orig, tdEpoch, tdEpoch)) { Yikes.yikes("concurrent mod"); continue retry; } // commit: write exclusive slow case final int lastReader = Epoch.tid(lastReadEpoch); if (lastReader != tid && lastReadEpoch > tdCV.get(lastReader)) { error(fae, 2, "read-by-thread-", lastReader, "write-by-thread-", tid); } } else { synchronized (x) { if (!x.cas(orig, tdEpoch, tdEpoch)) { Yikes.yikes("concurrent mod"); continue retry; } // commit write shared if (x.anyGt(tdCV)) { int errorCount = 0; for (int prevReader = x.nextGt(tdCV, 0); prevReader > -1; prevReader = x.nextGt(tdCV, prevReader + 1)) { if (prevReader != tid) { errorCount++; error(fae, 3, "read-by-thread-", prevReader, "write-by-thread-", tid); } } if (errorCount == 0) { Assert.fail("Bad error count"); } } } } final int lastWriter = Epoch.tid(lastWriteEpoch); if (lastWriter != tid && lastWriteEpoch > tdCV.get(lastWriter)) { error(fae, 1, "write-by-thread-", lastWriter, "write-by-thread-", tid); } } while (false); } } else { super.access(fae); } }
static void ts_set_cv(ShadowThread ts, CV cv) { Assert.panic("Bad"); }
static CV ts_get_cv(ShadowThread ts) { Assert.panic("Bad"); return null; }
static void ts_set_epoch(ShadowThread ts, int v) { Assert.panic("Bad"); }
static int ts_get_epoch(ShadowThread ts) { Assert.panic("Bad"); return -1; }