7 #include "clockvector.h"
9 struct ShadowTable *root;
10 std::vector<struct DataRace *> unrealizedraces;
12 /** This function initialized the data race detector. */
13 void initRaceDetector() {
14 root = (struct ShadowTable *)snapshot_calloc(sizeof(struct ShadowTable), 1);
17 /** This function looks up the entry in the shadow table corresponding to a
19 static uint64_t * lookupAddressEntry(void * address) {
20 struct ShadowTable *currtable=root;
22 currtable=(struct ShadowTable *) currtable->array[(((uintptr_t)address)>>32)&MASK16BIT];
23 if (currtable==NULL) {
24 currtable = (struct ShadowTable *)(root->array[(((uintptr_t)address)>>32)&MASK16BIT] = snapshot_calloc(sizeof(struct ShadowTable), 1));
28 struct ShadowBaseTable * basetable=(struct ShadowBaseTable *) currtable->array[(((uintptr_t)address)>>16)&MASK16BIT];
29 if (basetable==NULL) {
30 basetable = (struct ShadowBaseTable *)(currtable->array[(((uintptr_t)address)>>16)&MASK16BIT] = snapshot_calloc(sizeof(struct ShadowBaseTable), 1));
32 return &basetable->array[((uintptr_t)address)&MASK16BIT];
36 * Compares a current clock-vector/thread-ID pair with a clock/thread-ID pair
37 * to check the potential for a data race.
38 * @param clock1 The current clock vector
39 * @param tid1 The current thread; paired with clock1
40 * @param clock2 The clock value for the potentially-racing action
41 * @param tid2 The thread ID for the potentially-racing action
42 * @return true if the current clock allows a race with the event at clock2/tid2
44 static bool clock_may_race(ClockVector *clock1, thread_id_t tid1,
45 modelclock_t clock2, thread_id_t tid2)
47 return tid1 != tid2 && clock2 != 0 && clock1->getClock(tid2) <= clock2;
51 * Expands a record from the compact form to the full form. This is
52 * necessary for multiple readers or for very large thread ids or time
54 static void expandRecord(uint64_t * shadow) {
55 uint64_t shadowval=*shadow;
57 modelclock_t readClock = READVECTOR(shadowval);
58 thread_id_t readThread = int_to_id(RDTHREADID(shadowval));
59 modelclock_t writeClock = WRITEVECTOR(shadowval);
60 thread_id_t writeThread = int_to_id(WRTHREADID(shadowval));
62 struct RaceRecord *record = (struct RaceRecord *)snapshot_calloc(1, sizeof(struct RaceRecord));
63 record->writeThread=writeThread;
64 record->writeClock=writeClock;
67 record->capacity=INITCAPACITY;
68 record->thread = (thread_id_t *)snapshot_malloc(sizeof(thread_id_t)*record->capacity);
69 record->readClock = (modelclock_t *)snapshot_malloc(sizeof(modelclock_t)*record->capacity);
71 record->thread[0]=readThread;
72 record->readClock[0]=readClock;
74 *shadow=(uint64_t) record;
77 /** This function is called when we detect a data race.*/
78 static void reportDataRace(thread_id_t oldthread, modelclock_t oldclock, bool isoldwrite, ModelAction *newaction, bool isnewwrite, void *address) {
79 struct DataRace *race = (struct DataRace *)snapshot_malloc(sizeof(struct DataRace));
80 race->oldthread=oldthread;
81 race->oldclock=oldclock;
82 race->isoldwrite=isoldwrite;
83 race->newaction=newaction;
84 race->isnewwrite=isnewwrite;
85 race->address=address;
86 unrealizedraces.push_back(race);
88 /* If the race is realized, bail out now. */
89 if (checkDataRaces()) {
91 model->switch_to_master(NULL);
95 /** This function goes through the list of unrealized data races,
96 * removes the impossible ones, and print the realized ones. */
98 bool checkDataRaces() {
99 if (model->isfeasibleprefix()) {
100 /* Prune the non-racing unrealized dataraces */
101 unsigned int i,newloc=0;
102 for(i=0;i<unrealizedraces.size();i++) {
103 struct DataRace * race=unrealizedraces[i];
104 if (clock_may_race(race->newaction->get_cv(), race->newaction->get_tid(), race->oldclock, race->oldthread)) {
105 unrealizedraces[newloc++]=race;
109 unrealizedraces.resize(newloc);
111 if (unrealizedraces.size()!=0) {
112 /* We have an actual realized race. */
113 for(i=0;i<unrealizedraces.size();i++) {
114 struct DataRace * race=unrealizedraces[i];
123 void printRace(struct DataRace * race) {
124 printf("Datarace detected\n");
125 printf("Location %p\n", race->address);
126 printf("Initial access: thread %u clock %u, iswrite %u\n", id_to_int(race->oldthread), race->oldclock, race->isoldwrite);
127 printf("Second access: thread %u clock %u, iswrite %u\n", id_to_int(race->newaction->get_tid()), race->newaction->get_seq_number(), race->isnewwrite);
130 /** This function does race detection for a write on an expanded record. */
131 void fullRaceCheckWrite(thread_id_t thread, void *location, uint64_t * shadow, ClockVector *currClock) {
132 struct RaceRecord * record=(struct RaceRecord *) (*shadow);
134 /* Check for datarace against last read. */
136 for(int i=0;i<record->numReads;i++) {
137 modelclock_t readClock = record->readClock[i];
138 thread_id_t readThread = record->thread[i];
140 /* Note that readClock can't actuall be zero here, so it could be
143 if (clock_may_race(currClock, thread, readClock, readThread)) {
144 /* We have a datarace */
145 reportDataRace(readThread, readClock, false, model->get_parent_action(thread), true, location);
149 /* Check for datarace against last write. */
151 modelclock_t writeClock = record->writeClock;
152 thread_id_t writeThread = record->writeThread;
154 if (clock_may_race(currClock, thread, writeClock, writeThread)) {
155 /* We have a datarace */
156 reportDataRace(writeThread, writeClock, true, model->get_parent_action(thread), true, location);
160 record->writeThread=thread;
161 modelclock_t ourClock = currClock->getClock(thread);
162 record->writeClock=ourClock;
165 /** This function does race detection on a write. */
166 void raceCheckWrite(thread_id_t thread, void *location, ClockVector *currClock) {
167 uint64_t * shadow=lookupAddressEntry(location);
168 uint64_t shadowval=*shadow;
171 if (shadowval!=0&&!ISSHORTRECORD(shadowval)) {
172 fullRaceCheckWrite(thread, location, shadow, currClock);
176 int threadid = id_to_int(thread);
177 modelclock_t ourClock = currClock->getClock(thread);
179 /* Thread ID is too large or clock is too large. */
180 if (threadid > MAXTHREADID || ourClock > MAXWRITEVECTOR) {
181 expandRecord(shadow);
182 fullRaceCheckWrite(thread, location, shadow, currClock);
186 /* Check for datarace against last read. */
188 modelclock_t readClock = READVECTOR(shadowval);
189 thread_id_t readThread = int_to_id(RDTHREADID(shadowval));
191 if (clock_may_race(currClock, thread, readClock, readThread)) {
192 /* We have a datarace */
193 reportDataRace(readThread, readClock, false, model->get_parent_action(thread), true, location);
196 /* Check for datarace against last write. */
198 modelclock_t writeClock = WRITEVECTOR(shadowval);
199 thread_id_t writeThread = int_to_id(WRTHREADID(shadowval));
201 if (clock_may_race(currClock, thread, writeClock, writeThread)) {
202 /* We have a datarace */
203 reportDataRace(writeThread, writeClock, true, model->get_parent_action(thread), true, location);
205 *shadow = ENCODEOP(0, 0, threadid, ourClock);
208 /** This function does race detection on a read for an expanded record. */
209 void fullRaceCheckRead(thread_id_t thread, void *location, uint64_t * shadow, ClockVector *currClock) {
210 struct RaceRecord * record=(struct RaceRecord *) (*shadow);
212 /* Check for datarace against last write. */
214 modelclock_t writeClock = record->writeClock;
215 thread_id_t writeThread = record->writeThread;
217 if (clock_may_race(currClock, thread, writeClock, writeThread)) {
218 /* We have a datarace */
219 reportDataRace(writeThread, writeClock, true, model->get_parent_action(thread), false, location);
222 /* Shorten vector when possible */
226 for(int i=0;i<record->numReads;i++) {
227 modelclock_t readClock = record->readClock[i];
228 thread_id_t readThread = record->thread[i];
230 /* Note that is not really a datarace check as reads cannott
231 actually race. It is just determining that this read subsumes
232 another in the sense that either this read races or neither
233 read races. Note that readClock can't actually be zero, so it
234 could be optimized. */
236 if (clock_may_race(currClock, thread, readClock, readThread)) {
237 /* Still need this read in vector */
238 if (copytoindex!=i) {
239 record->readClock[copytoindex]=record->readClock[i];
240 record->thread[copytoindex]=record->thread[i];
246 if (copytoindex>=record->capacity) {
247 int newCapacity=record->capacity*2;
248 thread_id_t *newthread = (thread_id_t *)snapshot_malloc(sizeof(thread_id_t)*newCapacity);
249 modelclock_t *newreadClock =( modelclock_t *)snapshot_malloc(sizeof(modelclock_t)*newCapacity);
250 std::memcpy(newthread, record->thread, record->capacity*sizeof(thread_id_t));
251 std::memcpy(newreadClock, record->readClock, record->capacity*sizeof(modelclock_t));
252 snapshot_free(record->readClock);
253 snapshot_free(record->thread);
254 record->readClock=newreadClock;
255 record->thread=newthread;
256 record->capacity=newCapacity;
259 modelclock_t ourClock = currClock->getClock(thread);
261 record->thread[copytoindex]=thread;
262 record->readClock[copytoindex]=ourClock;
263 record->numReads=copytoindex+1;
266 /** This function does race detection on a read. */
267 void raceCheckRead(thread_id_t thread, void *location, ClockVector *currClock) {
268 uint64_t * shadow=lookupAddressEntry(location);
269 uint64_t shadowval=*shadow;
272 if (shadowval!=0&&!ISSHORTRECORD(shadowval)) {
273 fullRaceCheckRead(thread, location, shadow, currClock);
277 int threadid = id_to_int(thread);
278 modelclock_t ourClock = currClock->getClock(thread);
280 /* Thread ID is too large or clock is too large. */
281 if (threadid > MAXTHREADID || ourClock > MAXWRITEVECTOR) {
282 expandRecord(shadow);
283 fullRaceCheckRead(thread, location, shadow, currClock);
287 /* Check for datarace against last write. */
289 modelclock_t writeClock = WRITEVECTOR(shadowval);
290 thread_id_t writeThread = int_to_id(WRTHREADID(shadowval));
292 if (clock_may_race(currClock, thread, writeClock, writeThread)) {
293 /* We have a datarace */
294 reportDataRace(writeThread, writeClock, true, model->get_parent_action(thread), false, location);
297 modelclock_t readClock = READVECTOR(shadowval);
298 thread_id_t readThread = int_to_id(RDTHREADID(shadowval));
300 if (clock_may_race(currClock, thread, readClock, readThread)) {
301 /* We don't subsume this read... Have to expand record. */
302 expandRecord(shadow);
303 fullRaceCheckRead(thread, location, shadow, currClock);
307 *shadow = ENCODEOP(threadid, ourClock, id_to_int(writeThread), writeClock);