@Override public final ShadowVar makeShadowVar(final AccessEvent fae) { if (fae.getKind() == Kind.VOLATILE) { FastTrackVolatileData vd = get(((VolatileAccessEvent) fae).getShadowVolatile()); ShadowThread currentThread = fae.getThread(); vd.cv.max(ts_get_cv(currentThread)); return super.makeShadowVar(fae); } else { return createHelper(fae); } }
@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); } }
protected FastTrackGuardState createHelper(AccessEvent e) { return new FastTrackGuardState(e.isWrite(), ts_get_epoch(e.getThread())); }