runtime support for read only TRANSREADS
[IRC.git] / Robust / src / Runtime / STM / stm.c
1 /* ============================================================
2  * singleTMCommit.c
3  * - single thread commit on local machine
4  * =============================================================
5  * Copyright (c) 2009, University of California, Irvine, USA.
6  * All rights reserved.
7  * Author: Alokika Dash
8  *         adash@uci.edu
9  * =============================================================
10  *
11  */
12
13 #include "tm.h"
14 #include "garbage.h"
15 #define likely(x) x
16 /* Per thread transaction variables */
17 __thread objstr_t *t_cache;
18 __thread objstr_t *t_reserve;
19 __thread struct objlist * newobjs;
20
21 #ifdef DELAYCOMP
22 #include "delaycomp.h"
23 __thread struct pointerlist ptrstack;
24 __thread struct primitivelist primstack;
25 __thread struct branchlist branchstack;
26 struct pointerlist *c_ptrstack;
27 struct primitivelist *c_primstack;
28 struct branchlist *c_branchstack;
29 #endif
30
31 #ifdef TRANSSTATS
32 int numTransCommit = 0;
33 int numTransAbort = 0;
34 int nSoftAbort = 0;
35 int nSoftAbortCommit = 0;
36 int nSoftAbortAbort = 0;
37 #endif
38
39 #ifdef STMSTATS
40 /* Thread variable for locking/unlocking */
41 __thread threadrec_t *trec;
42 __thread struct objlist * lockedobjs;
43 /** Global lock **/
44 int typesCausingAbort[TOTALNUMCLASSANDARRAY];
45 /******Keep track of objects and types causing aborts******/
46 /* TODO uncomment for later use
47 #define DEBUGSTMSTAT(args...) { \
48   printf(args); \
49   fflush(stdout); \
50 }
51 */
52 #define DEBUGSTMSTAT(args...)
53 #else
54 #define DEBUGSTMSTAT(args...)
55 #endif
56
57 #ifdef STMDEBUG
58 #define DEBUGSTM(x...) printf(x);
59 #else
60 #define DEBUGSTM(x...)
61 #endif
62
63 #ifdef FASTMEMCPY
64 void * A_memcpy (void * dest, const void * src, size_t count);
65 #else
66 #define A_memcpy memcpy
67 #endif
68
69 extern void * curr_heapbase;
70 extern void * curr_heapptr;
71 extern void * curr_heaptop;
72
73 #ifdef STMSTATS
74 /*** Global variables *****/
75 objlockstate_t *objlockscope;
76 /**
77  * ABORTCOUNT
78  * params: object header
79  * Increments the abort count for each object
80  **/
81 void ABORTCOUNT(objheader_t * x) {
82   x->abortCount++;  
83   if (x->abortCount > MAXABORTS && (x->riskyflag != 1)) {        
84     //makes riskflag sticky
85     pthread_mutex_lock(&lockedobjstore); 
86     if (objlockscope->offset<MAXOBJLIST) { 
87       x->objlock=&(objlockscope->lock[objlockscope->offset++]);
88     } else { 
89       objlockstate_t *tmp=malloc(sizeof(objlockstate_t)); 
90       tmp->next=objlockscope; 
91       tmp->offset=1; 
92       x->objlock=&(tmp->lock[0]); 
93       objlockscope=tmp;
94     } 
95     pthread_mutex_unlock(&lockedobjstore); 
96     pthread_mutex_init(x->objlock, NULL);
97     //should put a memory barrier here
98     x->riskyflag = 1;                    
99   }
100 }
101 #endif
102
103 /* ==================================================
104  * stmStartup
105  * This function starts up the transaction runtime.
106  * ==================================================
107  */
108 int stmStartup() {
109   return 0;
110 }
111
112 /* ======================================
113  * objstrCreate
114  * - create an object store of given size
115  * ======================================
116  */
117 objstr_t *objstrCreate(unsigned int size) {
118   objstr_t *tmp;
119   if((tmp = calloc(1, (sizeof(objstr_t) + size))) == NULL) {
120     printf("%s() Calloc error at line %d, %s\n", __func__, __LINE__, __FILE__);
121     return NULL;
122   }
123   tmp->size = size;
124   tmp->next = NULL;
125   tmp->top = tmp + 1; //points to end of objstr_t structure!
126   return tmp;
127 }
128
129 void objstrReset() {
130   while(t_cache->next!=NULL) {
131     objstr_t *next=t_cache->next;
132     t_cache->next=t_reserve;
133     t_reserve=t_cache;
134     t_cache=next;
135   }
136   t_cache->top=t_cache+1;
137 }
138
139 //free entire list, starting at store
140 void objstrDelete(objstr_t *store) {
141   objstr_t *tmp;
142   while (store != NULL) {
143     tmp = store->next;
144     free(store);
145     store = tmp;
146   }
147   return;
148 }
149
150 /* =================================================
151  * transStart
152  * This function initializes things required in the
153  * transaction start
154  * =================================================
155  */
156 void transStart() {
157   //Transaction start is currently free...commit and aborting is not
158 #ifdef DELAYCOMP
159   c_ptrstack=&ptrstack;
160   c_primstack=&primstack;
161   c_branchstack=&branchstack;
162 #endif
163 }
164
165 /* =======================================================
166  * transCreateObj
167  * This function creates objects in the transaction record
168  * =======================================================
169  */
170 objheader_t *transCreateObj(void * ptr, unsigned int size) {
171   objheader_t *tmp = mygcmalloc(ptr, (sizeof(objheader_t) + size));
172   objheader_t *retval=&tmp[1];
173   tmp->lock=RW_LOCK_BIAS;
174   tmp->version = 1;
175   //initialize obj lock to the header
176   STATUS(tmp)=NEW;
177   // don't insert into table
178   if (newobjs->offset<MAXOBJLIST) {
179     newobjs->objs[newobjs->offset++]=retval;
180   } else {
181     struct objlist *tmp=malloc(sizeof(struct objlist));
182     tmp->next=newobjs;
183     tmp->objs[0]=retval;
184     tmp->offset=1;
185     newobjs=tmp;
186   }
187   return retval; //want space after object header
188 }
189
190 /* This functions inserts randowm wait delays in the order of msec
191  * Mostly used when transaction commits retry*/
192 void randomdelay(int softaborted) {
193   struct timespec req;
194   struct timeval t;
195
196   gettimeofday(&t,NULL);
197
198   req.tv_sec = 0;
199   req.tv_nsec = (long)((t.tv_usec)%(1<<softaborted))<<1; //1-11 microsec
200   nanosleep(&req, NULL);
201   return;
202 }
203
204 /* ==============================================
205  * objstrAlloc
206  * - allocate space in an object store
207  * ==============================================
208  */
209 void *objstrAlloc(unsigned int size) {
210   void *tmp;
211   int i=0;
212   objstr_t *store=t_cache;
213   if ((size&7)!=0) {
214     size+=(8-(size&7));
215   }
216
217   for(; i<2; i++) {
218     if (OSFREE(store)>=size) {
219       tmp=store->top;
220       store->top +=size;
221       return tmp;
222     }
223     if ((store=store->next)==NULL)
224       break;
225   }
226
227   {
228     unsigned int newsize=size>DEFAULT_OBJ_STORE_SIZE ? size : DEFAULT_OBJ_STORE_SIZE;
229     objstr_t **otmp=&t_reserve;
230     objstr_t *ptr;
231     while((ptr=*otmp)!=NULL) {
232       if (ptr->size>=newsize) {
233         //remove from list
234         *otmp=ptr->next;
235         ptr->next=t_cache;
236         t_cache=ptr;
237         ptr->top=((char *)(&ptr[1]))+size;
238         return &ptr[1];
239       }
240     }
241
242     objstr_t *os=(objstr_t *)calloc(1,(sizeof(objstr_t) + newsize));
243     void *nptr=&os[1];
244     os->next=t_cache;
245     t_cache=os;
246     os->size=newsize;
247     os->top=((char *)nptr)+size;
248     return nptr;
249   }
250 }
251
252
253 /* =============================================================
254  * transRead
255  * -finds the objects either in main heap
256  * -copies the object into the transaction cache
257  * =============================================================
258  */
259 __attribute__ ((pure)) void *transRead(void * oid, void *gl) {
260   objheader_t *tmp, *objheader;
261   objheader_t *objcopy;
262   int size;
263
264   /* Read from the main heap */
265   //No lock for now
266   objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
267   GETSIZE(size, header);
268   size += sizeof(objheader_t);
269   objcopy = (objheader_t *) objstrAlloc(size);
270 #ifdef STMSTATS
271   header->accessCount++;
272   if(header->riskyflag) {
273     header=needLock(header,gl);
274   }
275 #endif
276   A_memcpy(objcopy, header, size);
277   /* Insert into cache's lookup table */
278   STATUS(objcopy)=0;
279   if (((unsigned INTPTR)oid)<((unsigned INTPTR ) curr_heapbase)|| ((unsigned INTPTR)oid) >((unsigned INTPTR) curr_heapptr))
280     printf("ERROR! Bad object address!\n");
281   t_chashInsert(oid, &objcopy[1]);
282   return &objcopy[1];
283 }
284
285 void freenewobjs() {
286   struct objlist *ptr=newobjs;
287   while(ptr->next!=NULL) {
288     struct objlist *tmp=ptr->next;
289     free(ptr);
290     ptr=tmp;
291   }
292   ptr->offset=0;
293   newobjs=ptr;
294 }
295
296 #ifdef STMSTATS
297 void freelockedobjs() {
298   struct objlist *ptr=lockedobjs;
299   while(ptr->next!=NULL) {
300     struct objlist *tmp=ptr->next;
301     free(ptr);
302     ptr=tmp;
303   }
304   ptr->offset=0;
305   lockedobjs=ptr;
306 }
307 #endif
308
309 /* ================================================================
310  * transCommit
311  * - This function initiates the transaction commit process
312  * - goes through the transaction cache and decides
313  * - a final response
314  * ================================================================
315  */
316 #ifdef DELAYCOMP
317 int transCommit(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
318 #else
319 int transCommit() {
320 #endif
321   int softaborted=0;
322   do {
323     /* Look through all the objects in the transaction hash table */
324     int finalResponse;
325 #ifdef DELAYCOMP
326     if (c_numelements<(c_size>>3))
327       finalResponse= alttraverseCache(commitmethod, primitives, locals, params);
328     else
329       finalResponse= traverseCache(commitmethod, primitives, locals, params);
330 #else
331     if (c_numelements<(c_size>>3))
332       finalResponse= alttraverseCache();
333     else
334       finalResponse= traverseCache();
335 #endif
336     if(finalResponse == TRANS_ABORT) {
337 #ifdef TRANSSTATS
338       numTransAbort++;
339       if (softaborted) {
340         nSoftAbortAbort++;
341       }
342 #endif
343       freenewobjs();
344 #ifdef STMSTATS
345       freelockedobjs();
346 #endif
347       objstrReset();
348       t_chashreset();
349 #ifdef READSET
350       rd_t_chashreset();
351 #endif
352 #ifdef DELAYCOMP
353       dc_t_chashreset();
354       ptrstack.count=0;
355       primstack.count=0;
356       branchstack.count=0;
357 #endif
358       return TRANS_ABORT;
359     }
360     if(finalResponse == TRANS_COMMIT) {
361 #ifdef TRANSSTATS
362       numTransCommit++;
363       if (softaborted) {
364         nSoftAbortCommit++;
365       }
366 #endif
367       freenewobjs();
368 #ifdef STMSTATS
369       freelockedobjs();
370 #endif
371       objstrReset();
372       t_chashreset();
373 #ifdef READSET
374       rd_t_chashreset();
375 #endif
376 #ifdef DELAYCOMP
377       dc_t_chashreset();
378       ptrstack.count=0;
379       primstack.count=0;
380       branchstack.count=0;
381 #endif
382       return 0;
383     }
384
385     /* wait a random amount of time before retrying to commit transaction*/
386     if(finalResponse == TRANS_SOFT_ABORT) {
387 #ifdef TRANSSTATS
388       nSoftAbort++;
389 #endif
390       softaborted++;
391 #ifdef SOFTABORT
392       if (softaborted>1) {
393 #else
394       if (1) {
395 #endif
396         //retry if too many soft aborts
397         freenewobjs();
398 #ifdef STMSTATS
399     freelockedobjs();
400 #endif
401         objstrReset();
402         t_chashreset();
403 #ifdef READSET
404         rd_t_chashreset();
405 #endif
406 #ifdef DELAYCOMP
407         dc_t_chashreset();
408         ptrstack.count=0;
409         primstack.count=0;
410         branchstack.count=0;
411 #endif
412         return TRANS_ABORT;
413       }
414       //randomdelay(softaborted);
415     } else {
416       printf("Error: in %s() Unknown outcome", __func__);
417       exit(-1);
418     }
419   } while (1);
420 }
421
422 #ifdef DELAYCOMP
423 #define freearrays   if (c_numelements>=200) { \
424     free(oidrdlocked); \
425     free(oidrdversion); \
426   } \
427   if (t_numelements>=200) { \
428     free(oidwrlocked); \
429   }
430 #else
431 #define freearrays   if (c_numelements>=200) { \
432     free(oidrdlocked); \
433     free(oidrdversion); \
434     free(oidwrlocked); \
435   }
436 #endif
437
438 #ifdef DELAYCOMP
439 #define allocarrays int t_numelements=c_numelements+dc_c_numelements; \
440   if (t_numelements<200) { \
441     oidwrlocked=wrlocked; \
442   } else { \
443     oidwrlocked=malloc(t_numelements*sizeof(void *)); \
444   } \
445   if (c_numelements<200) { \
446     oidrdlocked=rdlocked; \
447     oidrdversion=rdversion; \
448   } else { \
449     int size=c_numelements*sizeof(void*); \
450     oidrdlocked=malloc(size); \
451     oidrdversion=malloc(size); \
452   }
453 #else
454 #define allocarrays if (c_numelements<200) { \
455     oidrdlocked=rdlocked; \
456     oidrdversion=rdversion; \
457     oidwrlocked=wrlocked; \
458   } else { \
459     int size=c_numelements*sizeof(void*); \
460     oidrdlocked=malloc(size); \
461     oidrdversion=malloc(size); \
462     oidwrlocked=malloc(size); \
463   }
464 #endif
465
466
467
468
469 /* ==================================================
470  * traverseCache
471  * - goes through the transaction cache and
472  * - decides if a transaction should commit or abort
473  * ==================================================
474  */
475 #ifdef DELAYCOMP
476 int traverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
477 #else
478 int traverseCache() {
479 #endif
480   /* Create info to keep track of objects that can be locked */
481   int numoidrdlocked=0;
482   int numoidwrlocked=0;
483   void * rdlocked[200];
484   int rdversion[200];
485   void * wrlocked[200];
486   int softabort=0;
487   int i;
488   void ** oidrdlocked;
489   void ** oidwrlocked;
490   int * oidrdversion;
491   allocarrays;
492
493   chashlistnode_t *ptr = c_table;
494   /* Represents number of bins in the chash table */
495   unsigned int size = c_size;
496   for(i = 0; i<size; i++) {
497     chashlistnode_t *curr = &ptr[i];
498     /* Inner loop to traverse the linked list of the cache lookupTable */
499     while(curr != NULL) {
500       //if the first bin in hash table is empty
501       if(curr->key == NULL)
502         break;
503       objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
504       objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
505       unsigned int version = headeraddr->version;
506
507       if(STATUS(headeraddr) & DIRTY) {
508         /* Read from the main heap  and compare versions */
509         if(write_trylock(&header->lock)) { //can aquire write lock
510           if (version == header->version) { /* versions match */
511             /* Keep track of objects locked */
512             oidwrlocked[numoidwrlocked++] = header;
513           } else {
514             oidwrlocked[numoidwrlocked++] = header;
515             transAbortProcess(oidwrlocked, numoidwrlocked);
516 #ifdef STMSTATS
517             ABORTCOUNT(header);
518             (typesCausingAbort[TYPE(header)])++;
519         getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion);
520 #endif
521             DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
522             DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
523             freearrays;
524             if (softabort)
525             return TRANS_SOFT_ABORT;
526               else 
527             return TRANS_ABORT;
528           }
529         } else {
530           if(version == header->version) {
531             /* versions match */
532             softabort=1;
533           }
534           transAbortProcess(oidwrlocked, numoidwrlocked);
535 #ifdef STMSTATS
536           ABORTCOUNT(header);
537           (typesCausingAbort[TYPE(header)])++;
538 #endif
539 #if defined(STMSTATS)||defined(SOFTABORT)
540       if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion))
541             softabort=0;
542 #endif
543           DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
544           DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
545           freearrays;
546           if (softabort)
547             return TRANS_SOFT_ABORT;
548           else 
549             return TRANS_ABORT;
550       
551         }
552       } else {
553         oidrdversion[numoidrdlocked]=version;
554         oidrdlocked[numoidrdlocked++] = header;
555       }
556       curr = curr->next;
557     }
558   } //end of for
559
560 #ifdef DELAYCOMP
561   //acquire access set locks
562   unsigned int numoidwrtotal=numoidwrlocked;
563
564   chashlistnode_t *dc_curr = dc_c_list;
565   /* Inner loop to traverse the linked list of the cache lookupTable */
566   while(likely(dc_curr != NULL)) {
567     //if the first bin in hash table is empty
568     objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
569     objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
570     if(write_trylock(&header->lock)) { //can aquire write lock    
571       oidwrlocked[numoidwrtotal++] = header;
572     } else {
573       //maybe we already have lock
574       void * key=dc_curr->key;
575       chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
576       
577       do {
578         if(node->key == key) {
579           objheader_t * headeraddr=&((objheader_t *) node->val)[-1];      
580           if(STATUS(headeraddr) & DIRTY) {
581             goto nextloop;
582           } else
583             break;
584         }
585         node = node->next;
586       } while(node != NULL);
587
588       //have to abort to avoid deadlock
589       transAbortProcess(oidwrlocked, numoidwrtotal);
590 #ifdef STMSTATS
591       ABORTCOUNT(header);
592       (typesCausingAbort[TYPE(header)])++;
593 #endif
594 #if defined(STMSTATS)||defined(SOFTABORT)
595       if(getTotalAbortCount(i+1, size, (void *)(curr->next), numoidrdlocked, oidrdlocked, oidrdversion))
596         softabort=0;
597 #endif
598       DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
599       DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
600       freearrays;
601       if (softabort)
602         return TRANS_SOFT_ABORT;
603       else
604         return TRANS_ABORT;
605     }
606   nextloop:
607     dc_curr = dc_curr->lnext;
608   }
609 #endif
610
611   //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
612
613   for(i=0; i<numoidrdlocked; i++) {
614     /* Read from the main heap  and compare versions */
615     objheader_t *header=oidrdlocked[i];
616     unsigned int version=oidrdversion[i];
617     if(header->lock>0) { //not write locked
618       if(version != header->version) { /* versions do not match */
619 #ifdef DELAYCOMP
620         transAbortProcess(oidwrlocked, numoidwrtotal);
621 #else
622         transAbortProcess(oidwrlocked, numoidwrlocked);
623 #endif
624 #ifdef STMSTATS
625         ABORTCOUNT(header);
626         (typesCausingAbort[TYPE(header)])++;
627         getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
628 #endif
629         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
630         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
631         freearrays;
632         return TRANS_ABORT;
633       }
634 #if DELAYCOMP
635     } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
636       //couldn't get lock because we already have it
637       //check if it is the right version number
638       if (version!=header->version) {
639         transAbortProcess(oidwrlocked, numoidwrtotal);
640 #ifdef STMSTATS
641         ABORTCOUNT(header);
642         (typesCausingAbort[TYPE(header)])++;
643         getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
644 #endif
645         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
646         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
647         freearrays;
648         return TRANS_ABORT;
649       }
650 #endif
651     } else { /* cannot aquire lock */
652       //do increment as we didn't get lock
653       if(version == header->version) {
654         softabort=1;
655       }
656 #ifdef DELAYCOMP
657       transAbortProcess(oidwrlocked, numoidwrtotal);
658 #else
659       transAbortProcess(oidwrlocked, numoidwrlocked);
660 #endif
661 #ifdef STMSTATS
662       ABORTCOUNT(header);
663       (typesCausingAbort[TYPE(header)])++;
664 #endif
665 #if defined(STMSTATS)||defined(SOFTABORT)
666       if(getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion))
667         softabort=0;
668 #endif
669       DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
670       DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
671       freearrays;
672       if (softabort)
673         return TRANS_SOFT_ABORT;
674       else 
675         return TRANS_ABORT;
676     }
677   }
678
679 #ifdef READSET
680   //need to validate auxilary readset
681   rdchashlistnode_t *rd_curr = rd_c_list;
682   /* Inner loop to traverse the linked list of the cache lookupTable */
683   while(likely(rd_curr != NULL)) {
684     //if the first bin in hash table is empty
685     unsigned int version=rd_curr->version;
686     objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
687     if(header->lock>0) { //object is not locked
688       if (version!=header->version) {
689         //have to abort
690 #ifdef DELAYCOMP
691         transAbortProcess(oidwrlocked, numoidwrtotal);
692 #else
693         transAbortProcess(oidwrlocked, numoidwrlocked);
694 #endif
695 #ifdef STMSTATS
696         ABORTCOUNT(header);
697         (typesCausingAbort[TYPE(header)])++;
698 #endif
699 #if defined(STMSTATS)||defined(SOFTABORT)
700         if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
701           softabort=0;
702 #endif
703         DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
704         DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
705         freearrays;
706         if (softabort)
707           return TRANS_SOFT_ABORT;
708         else
709           return TRANS_ABORT;   
710       }
711     } else {
712       //maybe we already have lock
713       if (version==header->version) {
714         void * key=rd_curr->key;
715 #ifdef DELAYCOMP
716         //check to see if it is in the delaycomp table
717         {
718           chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
719           do {
720             if(node->key == key)
721               goto nextloopread;
722             node = node->next;
723           } while(node != NULL);
724         }
725 #endif
726         //check normal table
727         {
728           chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
729           do {
730             if(node->key == key) {
731               objheader_t * headeraddr=&((objheader_t *) node->val)[-1];          
732               if(STATUS(headeraddr) & DIRTY) {
733                 goto nextloopread;
734               }
735             }
736             node = node->next;
737           } while(node != NULL);
738         }
739       }
740 #ifdef DELAYCOMP
741       //have to abort to avoid deadlock
742       transAbortProcess(oidwrlocked, numoidwrtotal);
743 #else
744       transAbortProcess(oidwrlocked, numoidwrlocked);
745 #endif
746
747 #ifdef STMSTATS
748       ABORTCOUNT(header);
749       (typesCausingAbort[TYPE(header)])++;
750 #endif
751 #if defined(STMSTATS)||defined(SOFTABORT)
752       if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
753         softabort=0;
754 #endif
755       DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
756       DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
757       freearrays;
758       if (softabort)
759         return TRANS_SOFT_ABORT;
760       else
761         return TRANS_ABORT;
762     }
763   nextloopread:
764     rd_curr = rd_curr->lnext;
765   }
766 #endif
767   
768   /* Decide the final response */
769 #ifdef DELAYCOMP
770   transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
771 #else
772   transCommitProcess(oidwrlocked, numoidwrlocked);
773 #endif
774   DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
775   freearrays;
776   return TRANS_COMMIT;
777 }
778
779 /* ==================================================
780  * alttraverseCache
781  * - goes through the transaction cache and
782  * - decides if a transaction should commit or abort
783  * ==================================================
784  */
785
786 #ifdef DELAYCOMP
787 int alttraverseCache(void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
788 #else
789 int alttraverseCache() {
790 #endif
791   /* Create info to keep track of objects that can be locked */
792   int numoidrdlocked=0;
793   int numoidwrlocked=0;
794   void * rdlocked[200];
795   int rdversion[200];
796   void * wrlocked[200];
797   int softabort=0;
798   int i;
799   void ** oidrdlocked;
800   int * oidrdversion;
801   void ** oidwrlocked;
802   allocarrays;
803
804   chashlistnode_t *curr = c_list;
805   /* Inner loop to traverse the linked list of the cache lookupTable */
806   while(likely(curr != NULL)) {
807     //if the first bin in hash table is empty
808     objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
809     objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
810     unsigned int version = headeraddr->version;
811
812     if(STATUS(headeraddr) & DIRTY) {
813       /* Read from the main heap  and compare versions */
814       if(likely(write_trylock(&header->lock))) { //can aquire write lock
815         if (likely(version == header->version)) { /* versions match */
816           /* Keep track of objects locked */
817           oidwrlocked[numoidwrlocked++] = header;
818         } else {
819           oidwrlocked[numoidwrlocked++] = header;
820           transAbortProcess(oidwrlocked, numoidwrlocked);
821 #ifdef STMSTATS
822           ABORTCOUNT(header);
823           (typesCausingAbort[TYPE(header)])++;
824       getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion);
825 #endif
826           DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
827           DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
828           freearrays;
829           return TRANS_ABORT;
830         }
831       } else { /* cannot aquire lock */
832         if(version == header->version) {
833           /* versions match */
834           softabort=1;
835         }
836         transAbortProcess(oidwrlocked, numoidwrlocked);
837 #ifdef STMSTATS
838         ABORTCOUNT(header);
839         (typesCausingAbort[TYPE(header)])++;
840 #endif
841 #if defined(STMSTATS)||defined(SOFTABORT)
842     if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
843           softabort=0;
844 #endif
845         DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
846         DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
847         freearrays;
848         if (softabort)
849           return TRANS_SOFT_ABORT;
850         else 
851           return TRANS_ABORT;
852       }
853     } else {
854       /* Read from the main heap  and compare versions */
855       oidrdversion[numoidrdlocked]=version;
856       oidrdlocked[numoidrdlocked++] = header;
857     }
858     curr = curr->lnext;
859   }
860
861 #ifdef DELAYCOMP
862   //acquire other locks
863   unsigned int numoidwrtotal=numoidwrlocked;
864   chashlistnode_t *dc_curr = dc_c_list;
865   /* Inner loop to traverse the linked list of the cache lookupTable */
866   while(likely(dc_curr != NULL)) {
867     //if the first bin in hash table is empty
868     objheader_t * headeraddr=&((objheader_t *) dc_curr->val)[-1];
869     objheader_t *header=(objheader_t *)(((char *)dc_curr->key)-sizeof(objheader_t));
870     if(write_trylock(&header->lock)) { //can aquire write lock
871       oidwrlocked[numoidwrtotal++] = header;
872     } else {
873       //maybe we already have lock
874       void * key=dc_curr->key;
875       chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
876       
877       do {
878         if(node->key == key) {
879           objheader_t * headeraddr=&((objheader_t *) node->val)[-1];
880           if(STATUS(headeraddr) & DIRTY) {
881             goto nextloop;
882           }
883         }
884         node = node->next;
885       } while(node != NULL);
886
887       //have to abort to avoid deadlock
888       transAbortProcess(oidwrlocked, numoidwrtotal);
889 #ifdef STMSTATS
890       ABORTCOUNT(header);
891       (typesCausingAbort[TYPE(header)])++;
892 #endif
893 #if defined(STMSTATS)||defined(SOFTABORT)
894       if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
895         softabort=0;
896 #endif
897       DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
898       DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
899       freearrays;
900       if (softabort)
901         return TRANS_SOFT_ABORT;
902       else
903         return TRANS_ABORT;
904     }
905   nextloop:
906     dc_curr = dc_curr->lnext;
907   }
908 #endif
909
910   //THIS IS THE SERIALIZATION END POINT (START POINT IS END OF EXECUTION)*****
911
912   for(i=0; i<numoidrdlocked; i++) {
913     objheader_t * header=oidrdlocked[i];
914     unsigned int version=oidrdversion[i];
915     if(header->lock>=0) {
916       if(version != header->version) {
917 #ifdef DELAYCOMP
918         transAbortProcess(oidwrlocked, numoidwrtotal);
919 #else
920         transAbortProcess(oidwrlocked, numoidwrlocked);
921 #endif
922 #ifdef STMSTATS
923         ABORTCOUNT(header);
924         (typesCausingAbort[TYPE(header)])++;
925         getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
926 #endif
927         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
928         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
929         freearrays;
930         return TRANS_ABORT;
931       }
932 #ifdef DELAYCOMP
933     } else if (dc_t_chashSearch(((char *)header)+sizeof(objheader_t))!=NULL) {
934       //couldn't get lock because we already have it
935       //check if it is the right version number
936       if (version!=header->version) {
937         transAbortProcess(oidwrlocked, numoidwrtotal);
938 #ifdef STMSTATS
939         ABORTCOUNT(header);
940         (typesCausingAbort[TYPE(header)])++;
941         getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion);
942 #endif
943         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
944         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
945         freearrays;
946         return TRANS_ABORT;
947       }
948 #endif
949     } else { /* cannot aquire lock */
950       if(version == header->version) {
951         softabort=1;
952       }
953 #ifdef DELAYCOMP
954       transAbortProcess(oidwrlocked, numoidwrtotal);
955 #else
956       transAbortProcess(oidwrlocked, numoidwrlocked);
957 #endif
958 #ifdef STMSTATS
959       ABORTCOUNT(header);
960       (typesCausingAbort[TYPE(header)])++;
961 #endif
962 #if defined(STMSTATS)||defined(SOFTABORT)
963       if(getReadAbortCount(i+1, numoidrdlocked, oidrdlocked, oidrdversion))
964         softabort=0;
965 #endif
966       DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
967       DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
968       freearrays;
969       if (softabort)
970         return TRANS_SOFT_ABORT;
971       else 
972         return TRANS_ABORT;
973     }
974   }
975
976 #ifdef READSET
977   //need to validate auxilary readset
978   rdchashlistnode_t *rd_curr = rd_c_list;
979   /* Inner loop to traverse the linked list of the cache lookupTable */
980   while(likely(rd_curr != NULL)) {
981     //if the first bin in hash table is empty
982     int version=rd_curr->version;
983     objheader_t *header=(objheader_t *)(((char *)rd_curr->key)-sizeof(objheader_t));
984     if(header->lock>0) { //object is not locked
985       if (version!=header->version) {
986         //have to abort
987 #ifdef DELAYCOMP
988         transAbortProcess(oidwrlocked, numoidwrtotal);
989 #else
990         transAbortProcess(oidwrlocked, numoidwrlocked);
991 #endif
992 #ifdef STMSTATS
993         ABORTCOUNT(header);
994         (typesCausingAbort[TYPE(header)])++;
995 #endif
996 #if defined(STMSTATS)||defined(SOFTABORT)
997         if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
998           softabort=0;
999 #endif
1000         DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1001         DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1002         freearrays;
1003         if (softabort)
1004           return TRANS_SOFT_ABORT;
1005         else
1006           return TRANS_ABORT;   
1007       }
1008     } else {
1009       if (version==header->version) {
1010         void * key=rd_curr->key;
1011 #ifdef DELAYCOMP
1012         //check to see if it is in the delaycomp table
1013         {
1014           chashlistnode_t *node = &dc_c_table[(((unsigned INTPTR)key) & dc_c_mask)>>4];
1015           do {
1016             if(node->key == key)
1017               goto nextloopread;
1018             node = node->next;
1019           } while(node != NULL);
1020         }
1021 #endif
1022         //check normal table
1023         {
1024           chashlistnode_t *node = &c_table[(((unsigned INTPTR)key) & c_mask)>>4];
1025           do {
1026             if(node->key == key) {
1027               objheader_t * headeraddr=&((objheader_t *) node->val)[-1];          
1028               if(STATUS(headeraddr) & DIRTY) {
1029                 goto nextloopread;
1030               }
1031             }
1032             node = node->next;
1033           } while(node != NULL);
1034         }
1035       }
1036 #ifdef DELAYCOMP
1037         //have to abort to avoid deadlock
1038         transAbortProcess(oidwrlocked, numoidwrtotal);
1039 #else
1040         transAbortProcess(oidwrlocked, numoidwrlocked);
1041 #endif
1042 #ifdef STMSTATS
1043       ABORTCOUNT(header);
1044       (typesCausingAbort[TYPE(header)])++;
1045 #endif
1046 #if defined(STMSTATS)||defined(SOFTABORT)
1047       if(getTotalAbortCount2((void *) curr->next, numoidrdlocked, oidrdlocked, oidrdversion))
1048         softabort=0;
1049 #endif
1050       DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
1051       DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
1052       freearrays;
1053       if (softabort)
1054         return TRANS_SOFT_ABORT;
1055       else
1056         return TRANS_ABORT;
1057     }
1058   nextloopread:
1059     rd_curr = rd_curr->lnext;
1060   }
1061 #endif
1062
1063   /* Decide the final response */
1064 #ifdef DELAYCOMP
1065   transCommitProcess(oidwrlocked, numoidwrlocked, numoidwrtotal, commitmethod, primitives, locals, params);
1066 #else
1067   transCommitProcess(oidwrlocked, numoidwrlocked);
1068 #endif
1069   DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
1070   freearrays;
1071   return TRANS_COMMIT;
1072 }
1073
1074 /* ==================================
1075  * transAbortProcess
1076  *
1077  * =================================
1078  */
1079 void transAbortProcess(void **oidwrlocked, int numoidwrlocked) {
1080   int i;
1081   objheader_t *header;
1082   /* Release read locks */
1083
1084   /* Release write locks */
1085   for(i=numoidwrlocked-1; i>=0; i--) {
1086     /* Read from the main heap */
1087     header = (objheader_t *)oidwrlocked[i];
1088     write_unlock(&header->lock);
1089   }
1090
1091 #ifdef STMSTATS
1092   /* clear trec and then release objects locked */
1093   struct objlist *ptr=lockedobjs;
1094   while(ptr!=NULL) {
1095     int max=ptr->offset;
1096     for(i=max-1; i>=0; i--) {
1097       header = (objheader_t *)ptr->objs[i];
1098       header->trec = NULL;
1099       pthread_mutex_unlock(header->objlock);
1100     }
1101     ptr=ptr->next;
1102   }
1103 #endif
1104 }
1105
1106 /* ==================================
1107  * transCommitProcess
1108  *
1109  * =================================
1110  */
1111 #ifdef DELAYCOMP
1112  void transCommitProcess(void ** oidwrlocked, int numoidwrlocked, int numoidwrtotal, void (*commitmethod)(void *, void *, void *), void * primitives, void * locals, void * params) {
1113 #else
1114    void transCommitProcess(void ** oidwrlocked, int numoidwrlocked) {
1115 #endif
1116   objheader_t *header;
1117   void *ptrcreate;
1118   int i;
1119   struct objlist *ptr=newobjs;
1120   while(ptr!=NULL) {
1121     int max=ptr->offset;
1122     for(i=0; i<max; i++) {
1123       //clear the new flag
1124       ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
1125     }
1126     ptr=ptr->next;
1127   }
1128
1129   /* Copy from transaction cache -> main object store */
1130   for (i = numoidwrlocked-1; i >=0; i--) {
1131     /* Read from the main heap */
1132     header = (objheader_t *)oidwrlocked[i];
1133     int tmpsize;
1134     GETSIZE(tmpsize, header);
1135     struct ___Object___ *dst=(struct ___Object___*)(((char *)oidwrlocked[i])+sizeof(objheader_t));
1136     struct ___Object___ *src=t_chashSearch(dst);
1137     dst->___cachedCode___=src->___cachedCode___;
1138     dst->___cachedHash___=src->___cachedHash___;
1139     A_memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
1140     __asm__ __volatile__("": : :"memory");
1141 #ifndef DELAYCOMP
1142     header->version++;
1143 #endif
1144   }
1145   __asm__ __volatile__("": : :"memory");
1146
1147 #ifdef DELAYCOMP
1148   //  call commit method
1149   ptrstack.count=0;
1150   primstack.count=0;
1151   branchstack.count=0;
1152   commitmethod(params, locals, primitives);
1153 #endif
1154
1155   /* Release write locks */
1156 #ifdef DELAYCOMP
1157   for(i=numoidwrtotal-1; i>=0; i--) {
1158 #else
1159   for(i=numoidwrlocked-1; i>=0; i--) {
1160 #endif
1161     header = (objheader_t *)oidwrlocked[i];
1162 #ifdef DELAYCOMP
1163     header->version++;
1164 #endif
1165     write_unlock(&header->lock);
1166   }
1167
1168 #ifdef STMSTATS
1169   /* clear trec and then release objects locked */
1170   ptr=lockedobjs;
1171   while(ptr!=NULL) {
1172     int max=ptr->offset;
1173     for(i=max-1; i>=0; i--) {
1174       header = (objheader_t *)ptr->objs[i];
1175       header->trec = NULL;
1176       pthread_mutex_unlock(header->objlock);
1177     }
1178     ptr=ptr->next;
1179   }
1180 #endif
1181 }
1182
1183 #if defined(STMSTATS)||defined(SOFTABORT)
1184 /** ========================================================================================
1185  * getTotalAbortCount (for traverseCache only)
1186  * params : start: start index of the loop
1187  *        : stop: stop index of the loop
1188  *        : startptr: pointer that points to where to start looking in the cache hash table
1189  *        : numoidrdlocked : number of objects read that are locked
1190  *        : oidrdlocked : array of objects read and currently locked
1191  *        : oidrdversion : array of versions of object read
1192  * =========================================================================================
1193  **/
1194 int getTotalAbortCount(int start, int stop, void *startptr, int numoidrdlocked, void *oidrdlocked, int *oidrdversion) {
1195   int i;
1196   int hardabort=0;
1197   int isFirstTime=0;
1198   chashlistnode_t *curr = (chashlistnode_t *) startptr;
1199   chashlistnode_t *ptr = c_table;
1200   /* First go through all objects left in the cache that have not been covered yet */
1201   for(i = start; i < stop; i++) {
1202     if(!isFirstTime)
1203       curr = &ptr[i];
1204     /* Inner loop to traverse the linked list of the cache lookupTable */
1205     while(curr != NULL) {
1206       if(curr->key == NULL)
1207         break;
1208       objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
1209       objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
1210       unsigned int version = headeraddr->version;
1211       /* versions do not match */
1212       if(version != header->version) {
1213 #ifdef STMSTATS
1214         ABORTCOUNT(header);
1215         (typesCausingAbort[TYPE(header)])++;
1216 #endif
1217         hardabort=1;
1218       }
1219       curr = curr->next;
1220     }
1221     isFirstTime = 1;
1222   }
1223
1224   /* Then go through all objects that are read and are currently present in the readLockedArray */
1225   if(numoidrdlocked>0) {
1226     for(i=0; i<numoidrdlocked; i++) {
1227       objheader_t *header = ((void **)oidrdlocked)[i];
1228       unsigned int version = oidrdversion[i];
1229       if(version != header->version) { /* versions do not match */
1230 #ifdef STMSTATS
1231         ABORTCOUNT(header);
1232         (typesCausingAbort[TYPE(header)])++;
1233 #endif
1234         hardabort=1;
1235       }
1236     }
1237   }
1238
1239   return hardabort;
1240 }
1241
1242 /** ========================================================================================
1243  * getTotalAbortCount2 (for alttraverseCache only)
1244  * params : startptr: pointer that points to where to start looking in the cache hash table
1245  *        : numoidrdlocked : number of objects read that are locked
1246  *        : oidrdlocked : array of objects read and currently locked
1247  *        : oidrdversion : array of versions of object read
1248  * =========================================================================================
1249  **/
1250 int getTotalAbortCount2(void *startptr, int numoidrdlocked, void *oidrdlocked, int *oidrdversion) {
1251   int hardabort=0;
1252   chashlistnode_t *curr = (chashlistnode_t *) startptr;
1253   /* Inner loop to traverse the linked list of the cache lookupTable */
1254   while(curr != NULL) {
1255     objheader_t *headeraddr=&((objheader_t *) curr->val)[-1];
1256     objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
1257     unsigned int version = headeraddr->version;
1258     /* versions do not match */
1259     if(version != header->version) {
1260 #ifdef STMSTATS
1261       ABORTCOUNT(header);
1262       (typesCausingAbort[TYPE(header)])++;
1263 #endif
1264       hardabort=1;
1265     }
1266     curr = curr->next;
1267   }
1268
1269   /* Then go through all objects that are read and are currently present in the readLockedArray */
1270   if(numoidrdlocked>0) {
1271     int i;
1272     for(i=0; i<numoidrdlocked; i++) {
1273       objheader_t *header = ((void **)oidrdlocked)[i];
1274       unsigned int version = oidrdversion[i];
1275       if(version != header->version) { /* versions do not match */
1276 #ifdef STMSTATS
1277         ABORTCOUNT(header);
1278         (typesCausingAbort[TYPE(header)])++;
1279 #endif
1280         hardabort=1;
1281       }
1282     }
1283   }
1284
1285   return hardabort;
1286 }
1287
1288 /**
1289  * getReadAbortCount : Tells the number of aborts caused by objects that are read by
1290  *                    visiting the read array
1291  * params: int start, int stop are indexes to readLocked array
1292  *         void  *oidrdlocked = readLocked array
1293  *         int *oidrdversion = version array
1294  **/
1295 int getReadAbortCount(int start, int stop, void *oidrdlocked, int *oidrdversion) {
1296   int i;
1297   int hardabort=0;
1298   /* Go through oids read that are locked */
1299   for(i = start; i < stop; i++) {
1300     objheader_t *header = ((void **)oidrdlocked)[i];
1301     unsigned int version = oidrdversion[i];
1302     if(version != header->version) { /* versions do not match */
1303 #ifdef STMSTATS
1304       ABORTCOUNT(header);
1305       (typesCausingAbort[TYPE(header)])++;
1306 #endif
1307       hardabort=1;
1308     }
1309   }
1310   return hardabort;
1311 }
1312
1313 /**
1314  * needLock
1315  * params: Object header, ptr to garbage collector
1316  * Locks an object that causes aborts
1317  **/
1318 objheader_t * needLock(objheader_t *header, void *gl) {
1319   int lockstatus;
1320   threadrec_t *ptr;
1321   while((lockstatus = pthread_mutex_trylock(header->objlock)) 
1322       && ((ptr = header->trec) == NULL)) { //retry
1323     ;
1324   }
1325   if(lockstatus==0) { //acquired lock
1326     /* Set trec */
1327     header->trec = trec;
1328   } else { //failed to get lock
1329     trec->blocked=1;
1330     //memory barrier
1331     __asm__ __volatile__("":::"memory");
1332     //see if other thread is blocked
1333     if(ptr->blocked == 1) {
1334       //it might be block, so ignore lock and clear our blocked flag
1335       trec->blocked=0;
1336       return;
1337     } else { 
1338 #ifdef PRECISE_GC
1339       INTPTR ptrarray[]={1, (INTPTR)gl, (INTPTR) header};
1340       void *lockptr=header->objlock;
1341       stopforgc((struct garbagelist *)ptrarray);
1342       //grab lock and wait our turn
1343       pthread_mutex_lock(lockptr);
1344       restartaftergc();
1345       header=(objheader_t *) ptrarray[2];
1346 #else
1347       pthread_mutex_lock(header->objptr);
1348 #endif
1349       /* we have lock, so we are not blocked anymore */
1350       trec->blocked = 0;
1351       /* Set our trec */
1352       header->trec = trec;
1353     }
1354   }
1355   //trec->blocked is zero now
1356
1357   /* Save the locked object */
1358   if (lockedobjs->offset<MAXOBJLIST) {
1359     lockedobjs->objs[lockedobjs->offset++]=header;
1360   } else {
1361     struct objlist *tmp=malloc(sizeof(struct objlist));
1362     tmp->next=lockedobjs;
1363     tmp->objs[0]=header;
1364     tmp->offset=1;
1365     lockedobjs=tmp;
1366   }
1367   return header;
1368 }
1369
1370 #endif