changes to compile
[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
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 TRANSSTATS
22 int numTransCommit = 0;
23 int numTransAbort = 0;
24 int nSoftAbort = 0;
25 int nSoftAbortCommit = 0;
26 int nSoftAbortAbort = 0;
27 #endif
28
29 #ifdef STMSTATS
30 /* Thread variable for locking/unlocking */
31 __thread threadrec_t *trec;
32 __thread struct objlist * lockedobjs;
33 /** Global lock **/
34 int typesCausingAbort[TOTALNUMCLASSANDARRAY];
35 /******Keep track of objects and types causing aborts******/
36 /* TODO uncomment for later use
37 #define DEBUGSTMSTAT(args...) { \
38   printf(args); \
39   fflush(stdout); \
40 }
41 */
42 #define DEBUGSTMSTAT(args...)
43 #else
44 #define DEBUGSTMSTAT(args...)
45 #endif
46
47 #ifdef STMDEBUG
48 #define DEBUGSTM(x...) printf(x);
49 #else
50 #define DEBUGSTM(x...)
51 #endif
52
53 #ifdef FASTMEMCPY
54 void * A_memcpy (void * dest, const void * src, size_t count);
55 #else
56 #define A_memcpy memcpy
57 #endif
58
59 #ifdef STMSTATS
60 /*** Global variables *****/
61 objlockstate_t *objlockscope;
62 /**
63  * ABORTCOUNT
64  * params: object header
65  * Increments the abort count for each object
66  **/
67 void ABORTCOUNT(objheader_t * x) {
68   x->abortCount++;  
69   if (x->abortCount > MAXABORTS && (x->riskyflag != 1)) {        
70     //makes riskflag sticky
71     pthread_mutex_lock(&lockedobjstore); 
72     if (objlockscope->offset<MAXOBJLIST) { 
73       x->objlock=&(objlockscope->lock[objlockscope->offset++]);
74     } else { 
75       objlockstate_t *tmp=malloc(sizeof(objlockstate_t)); 
76       tmp->next=objlockscope; 
77       tmp->offset=1; 
78       x->objlock=&(tmp->lock[0]); 
79       objlockscope=tmp;
80     } 
81     pthread_mutex_unlock(&lockedobjstore); 
82     pthread_mutex_init(x->objlock, NULL);
83     //should put a memory barrier here
84     x->riskyflag = 1;                    
85   }
86 }
87 #endif
88
89 /* ==================================================
90  * stmStartup
91  * This function starts up the transaction runtime.
92  * ==================================================
93  */
94 int stmStartup() {
95   return 0;
96 }
97
98 /* ======================================
99  * objstrCreate
100  * - create an object store of given size
101  * ======================================
102  */
103 objstr_t *objstrCreate(unsigned int size) {
104   objstr_t *tmp;
105   if((tmp = calloc(1, (sizeof(objstr_t) + size))) == NULL) {
106     printf("%s() Calloc error at line %d, %s\n", __func__, __LINE__, __FILE__);
107     return NULL;
108   }
109   tmp->size = size;
110   tmp->next = NULL;
111   tmp->top = tmp + 1; //points to end of objstr_t structure!
112   return tmp;
113 }
114
115 void objstrReset() {
116   while(t_cache->next!=NULL) {
117     objstr_t *next=t_cache->next;
118     t_cache->next=t_reserve;
119     t_reserve=t_cache;
120     t_cache=next;
121   }
122   t_cache->top=t_cache+1;
123 }
124
125 //free entire list, starting at store
126 void objstrDelete(objstr_t *store) {
127   objstr_t *tmp;
128   while (store != NULL) {
129     tmp = store->next;
130     free(store);
131     store = tmp;
132   }
133   return;
134 }
135
136 /* =================================================
137  * transStart
138  * This function initializes things required in the
139  * transaction start
140  * =================================================
141  */
142 void transStart() {
143   //Transaction start is currently free...commit and aborting is not
144 }
145
146 /* =======================================================
147  * transCreateObj
148  * This function creates objects in the transaction record
149  * =======================================================
150  */
151 objheader_t *transCreateObj(void * ptr, unsigned int size) {
152   objheader_t *tmp = mygcmalloc(ptr, (sizeof(objheader_t) + size));
153   objheader_t *retval=&tmp[1];
154   tmp->lock=RW_LOCK_BIAS;
155   tmp->version = 1;
156   //initialize obj lock to the header
157   STATUS(tmp)=NEW;
158   // don't insert into table
159   if (newobjs->offset<MAXOBJLIST) {
160     newobjs->objs[newobjs->offset++]=retval;
161   } else {
162     struct objlist *tmp=malloc(sizeof(struct objlist));
163     tmp->next=newobjs;
164     tmp->objs[0]=retval;
165     tmp->offset=1;
166     newobjs=tmp;
167   }
168   return retval; //want space after object header
169 }
170
171 /* This functions inserts randowm wait delays in the order of msec
172  * Mostly used when transaction commits retry*/
173 void randomdelay(int softaborted) {
174   struct timespec req;
175   struct timeval t;
176
177   gettimeofday(&t,NULL);
178
179   req.tv_sec = 0;
180   req.tv_nsec = (long)((t.tv_usec)%(1<<softaborted))<<1; //1-11 microsec
181   nanosleep(&req, NULL);
182   return;
183 }
184
185 /* ==============================================
186  * objstrAlloc
187  * - allocate space in an object store
188  * ==============================================
189  */
190 void *objstrAlloc(unsigned int size) {
191   void *tmp;
192   int i=0;
193   objstr_t *store=t_cache;
194   if ((size&7)!=0) {
195     size+=(8-(size&7));
196   }
197
198   for(; i<2; i++) {
199     if (OSFREE(store)>=size) {
200       tmp=store->top;
201       store->top +=size;
202       return tmp;
203     }
204     if ((store=store->next)==NULL)
205       break;
206   }
207
208   {
209     unsigned int newsize=size>DEFAULT_OBJ_STORE_SIZE ? size : DEFAULT_OBJ_STORE_SIZE;
210     objstr_t **otmp=&t_reserve;
211     objstr_t *ptr;
212     while((ptr=*otmp)!=NULL) {
213       if (ptr->size>=newsize) {
214         //remove from list
215         *otmp=ptr->next;
216         ptr->next=t_cache;
217         t_cache=ptr;
218         ptr->top=((char *)(&ptr[1]))+size;
219         return &ptr[1];
220       }
221     }
222
223     objstr_t *os=(objstr_t *)calloc(1,(sizeof(objstr_t) + newsize));
224     void *nptr=&os[1];
225     os->next=t_cache;
226     t_cache=os;
227     os->size=newsize;
228     os->top=((char *)nptr)+size;
229     return nptr;
230   }
231 }
232
233 /* =============================================================
234  * transRead
235  * -finds the objects either in main heap
236  * -copies the object into the transaction cache
237  * =============================================================
238  */
239 __attribute__((pure)) void *transRead(void * oid, void *gl) {
240   objheader_t *tmp, *objheader;
241   objheader_t *objcopy;
242   int size;
243
244   /* Read from the main heap */
245   //No lock for now
246   objheader_t *header = (objheader_t *)(((char *)oid) - sizeof(objheader_t));
247   GETSIZE(size, header);
248   size += sizeof(objheader_t);
249   objcopy = (objheader_t *) objstrAlloc(size);
250 #ifdef STMSTATS
251   header->accessCount++;
252   //FIXME riskratio fix
253   //float riskratio = ((header->abortCount)/(header->accessCount));
254   //DEBUGSTMSTAT("type: %d, header->abortCount: %d, header->accessCount: %d, riskratio: %f\n", TYPE(header), header->abortCount, header->accessCount, riskratio);
255   //DEBUGSTMSTAT("type: %d, header->abortCount: %d, header->accessCount: %d\n", TYPE(header), header->abortCount, header->accessCount);
256   //if(header->abortCount > MAXABORTS &&  riskratio > NEED_LOCK_THRESHOLD) {
257   if(header->riskyflag) {
258     needLock(header,gl);
259   }
260 #endif
261   A_memcpy(objcopy, header, size);
262   /* Insert into cache's lookup table */
263   STATUS(objcopy)=0;
264   t_chashInsert(oid, &objcopy[1]);
265   return &objcopy[1];
266 }
267
268 void freenewobjs() {
269   struct objlist *ptr=newobjs;
270   while(ptr->next!=NULL) {
271     struct objlist *tmp=ptr->next;
272     free(ptr);
273     ptr=tmp;
274   }
275   ptr->offset=0;
276   newobjs=ptr;
277 }
278
279 #ifdef STMSTATS
280 void freelockedobjs() {
281   struct objlist *ptr=lockedobjs;
282   while(ptr->next!=NULL) {
283     struct objlist *tmp=ptr->next;
284     free(ptr);
285     ptr=tmp;
286   }
287   ptr->offset=0;
288   lockedobjs=ptr;
289 }
290 #endif
291
292 /* ================================================================
293  * transCommit
294  * - This function initiates the transaction commit process
295  * - goes through the transaction cache and decides
296  * - a final response
297  * ================================================================
298  */
299 int transCommit() {
300   int softaborted=0;
301   do {
302     /* Look through all the objects in the transaction hash table */
303     int finalResponse;
304     if (c_numelements<(c_size>>3))
305       finalResponse= alttraverseCache();
306     else
307       finalResponse= traverseCache();
308     if(finalResponse == TRANS_ABORT) {
309 #ifdef TRANSSTATS
310       numTransAbort++;
311       if (softaborted) {
312         nSoftAbortAbort++;
313       }
314 #endif
315       freenewobjs();
316 #ifdef STMSTATS
317       freelockedobjs();
318 #endif
319       objstrReset();
320       t_chashreset();
321       return TRANS_ABORT;
322     }
323     if(finalResponse == TRANS_COMMIT) {
324 #ifdef TRANSSTATS
325       numTransCommit++;
326       if (softaborted) {
327         nSoftAbortCommit++;
328       }
329 #endif
330       freenewobjs();
331 #ifdef STMSTATS
332       freelockedobjs();
333 #endif
334       objstrReset();
335       t_chashreset();
336       return 0;
337     }
338     /* wait a random amount of time before retrying to commit transaction*/
339     if(finalResponse == TRANS_SOFT_ABORT) {
340 #ifdef TRANSSTATS
341       nSoftAbort++;
342 #endif
343       softaborted++;
344       if (softaborted>4) {
345         //retry if too many soft aborts
346         freenewobjs();
347 #ifdef STMSTATS
348     freelockedobjs();
349 #endif
350         objstrReset();
351         t_chashreset();
352         return TRANS_ABORT;
353       }
354       randomdelay(softaborted);
355     } else {
356       printf("Error: in %s() Unknown outcome", __func__);
357       exit(-1);
358     }
359   } while (1);
360 }
361
362 /* ==================================================
363  * traverseCache
364  * - goes through the transaction cache and
365  * - decides if a transaction should commit or abort
366  * ==================================================
367  */
368 int traverseCache() {
369   /* Create info to keep track of objects that can be locked */
370   int numoidrdlocked=0;
371   int numoidwrlocked=0;
372   void * rdlocked[200];
373   int rdversion[200];
374   void * wrlocked[200];
375   int softabort=0;
376   int i;
377   void ** oidrdlocked;
378   void ** oidwrlocked;
379   int * oidrdversion;
380   if (c_numelements<200) {
381     oidrdlocked=rdlocked;
382     oidrdversion=rdversion;
383     oidwrlocked=wrlocked;
384   } else {
385     int size=c_numelements*sizeof(void*);
386     oidrdlocked=malloc(size);
387     oidrdversion=malloc(size);
388     oidwrlocked=malloc(size);
389   }
390   chashlistnode_t *ptr = c_table;
391   /* Represents number of bins in the chash table */
392   unsigned int size = c_size;
393   for(i = 0; i<size; i++) {
394     chashlistnode_t *curr = &ptr[i];
395     /* Inner loop to traverse the linked list of the cache lookupTable */
396     while(curr != NULL) {
397       //if the first bin in hash table is empty
398       if(curr->key == NULL)
399         break;
400       objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
401       objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
402       unsigned int version = headeraddr->version;
403
404       if(STATUS(headeraddr) & DIRTY) {
405         /* Read from the main heap  and compare versions */
406         if(write_trylock(&header->lock)) { //can aquire write lock
407           if (version == header->version) { /* versions match */
408             /* Keep track of objects locked */
409             oidwrlocked[numoidwrlocked++] = OID(header);
410           } else {
411             oidwrlocked[numoidwrlocked++] = OID(header);
412             transAbortProcess(oidwrlocked, numoidwrlocked);
413 #ifdef STMSTATS
414             ABORTCOUNT(header);
415             (typesCausingAbort[TYPE(header)])++;
416             getTotalAbortCount(i+1, size, (void *)(curr->next), NULL, 1);
417 #endif
418             DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
419             DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
420             if (c_numelements>=200) {
421               free(oidrdlocked);
422               free(oidrdversion);
423               free(oidwrlocked);
424             }
425             return TRANS_ABORT;
426           }
427         } else { /* cannot aquire lock */
428           if(version == header->version) {
429             /* versions match */
430             softabort=1;
431           } else {
432             transAbortProcess(oidwrlocked, numoidwrlocked);
433 #ifdef STMSTATS
434             ABORTCOUNT(header);
435             (typesCausingAbort[TYPE(header)])++;
436             getTotalAbortCount(i+1, size, (void *)(curr->next), NULL, 1);
437 #endif
438             DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
439             DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
440             if (c_numelements>=200) {
441               free(oidrdlocked);
442               free(oidrdversion);
443               free(oidwrlocked);
444             }
445             return TRANS_ABORT;
446           }
447         }
448       } else {
449         oidrdversion[numoidrdlocked]=version;
450         oidrdlocked[numoidrdlocked++] = header;
451       }
452       curr = curr->next;
453     }
454   } //end of for
455
456   //THIS IS THE SERIALIZATION POINT *****
457
458   for(i=0; i<numoidrdlocked; i++) {
459     /* Read from the main heap  and compare versions */
460     objheader_t *header=oidrdlocked[i];
461     unsigned int version=oidrdversion[i];
462     if(header->lock>0) { //not write locked
463       if(version != header->version) { /* versions do not match */
464         oidrdlocked[numoidrdlocked++] = OID(header);
465         transAbortProcess(oidwrlocked, numoidwrlocked);
466 #ifdef STMSTATS
467         ABORTCOUNT(header);
468         (typesCausingAbort[TYPE(header)])++;
469         getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *) oidrdversion, 0);
470 #endif
471         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
472         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
473         if (c_numelements>=200) {
474           free(oidrdlocked);
475           free(oidrdversion);
476           free(oidwrlocked);
477         }
478         return TRANS_ABORT;
479       }
480     } else { /* cannot aquire lock */
481       //do increment as we didn't get lock
482       if(version == header->version) {
483         softabort=1;
484       } else {
485         transAbortProcess(oidwrlocked, numoidwrlocked);
486 #ifdef STMSTATS
487         ABORTCOUNT(header);
488         (typesCausingAbort[TYPE(header)])++;
489         getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *) oidrdversion, 0);
490 #endif
491         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
492         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
493         if (c_numelements>=200) {
494           free(oidrdlocked);
495           free(oidrdversion);
496           free(oidwrlocked);
497         }
498         return TRANS_ABORT;
499       }
500     }
501   }
502
503   /* Decide the final response */
504   if (softabort) {
505     transAbortProcess(oidwrlocked, numoidwrlocked);
506     DEBUGSTM("Soft Abort: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
507     if (c_numelements>=200) {
508       free(oidrdlocked);
509       free(oidrdversion);
510       free(oidwrlocked);
511     }
512     return TRANS_SOFT_ABORT;
513   } else {
514     transCommitProcess(oidwrlocked, numoidwrlocked);
515     DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
516     if (c_numelements>=200) {
517       free(oidrdlocked);
518       free(oidrdversion);
519       free(oidwrlocked);
520     }
521     return TRANS_COMMIT;
522   }
523 }
524
525 /* ==================================================
526  * alttraverseCache
527  * - goes through the transaction cache and
528  * - decides if a transaction should commit or abort
529  * ==================================================
530  */
531 int alttraverseCache() {
532   /* Create info to keep track of objects that can be locked */
533   int numoidrdlocked=0;
534   int numoidwrlocked=0;
535   void * rdlocked[200];
536   int rdversion[200];
537   void * wrlocked[200];
538   int softabort=0;
539   int i;
540   void ** oidrdlocked;
541   int * oidrdversion;
542   void ** oidwrlocked;
543   if (c_numelements<200) {
544     oidrdlocked=rdlocked;
545     oidrdversion=rdversion;
546     oidwrlocked=wrlocked;
547   } else {
548     int size=c_numelements*sizeof(void*);
549     oidrdlocked=malloc(size);
550     oidrdversion=malloc(size);
551     oidwrlocked=malloc(size);
552   }
553   chashlistnode_t *curr = c_list;
554   /* Inner loop to traverse the linked list of the cache lookupTable */
555   while(curr != NULL) {
556     //if the first bin in hash table is empty
557     objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
558     objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
559     unsigned int version = headeraddr->version;
560
561     if(STATUS(headeraddr) & DIRTY) {
562       /* Read from the main heap  and compare versions */
563       if(write_trylock(&header->lock)) { //can aquire write lock
564         if (version == header->version) { /* versions match */
565           /* Keep track of objects locked */
566           oidwrlocked[numoidwrlocked++] = OID(header);
567         } else {
568           oidwrlocked[numoidwrlocked++] = OID(header);
569           transAbortProcess(oidwrlocked, numoidwrlocked);
570 #ifdef STMSTATS
571           ABORTCOUNT(header);
572           (typesCausingAbort[TYPE(header)])++;
573           getTotalAbortCount(0, 1, (void *) curr->next, NULL, 1);
574 #endif
575           DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
576           DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
577           if (c_numelements>=200) {
578             free(oidrdlocked);
579             free(oidrdversion);
580             free(oidwrlocked);
581           }
582           return TRANS_ABORT;
583         }
584       } else { /* cannot aquire lock */
585         if(version == header->version) {
586           /* versions match */
587           softabort=1;
588         } else {
589           transAbortProcess(oidwrlocked, numoidwrlocked);
590 #ifdef STMSTATS
591           ABORTCOUNT(header);
592           (typesCausingAbort[TYPE(header)])++;
593           getTotalAbortCount(0, 1, (void *) curr->next, NULL, 1);
594 #endif
595           DEBUGSTM("WR Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
596           DEBUGSTMSTAT("WR Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
597           if (c_numelements>=200) {
598             free(oidrdlocked);
599             free(oidrdversion);
600             free(oidwrlocked);
601           }
602           return TRANS_ABORT;
603         }
604       }
605     } else {
606       /* Read from the main heap  and compare versions */
607       oidrdversion[numoidrdlocked]=version;
608       oidrdlocked[numoidrdlocked++] = header;
609     }
610     curr = curr->lnext;
611   }
612   //THIS IS THE SERIALIZATION POINT *****
613   for(i=0; i<numoidrdlocked; i++) {
614     objheader_t * header = oidrdlocked[i];
615     unsigned int version=oidrdversion[i];
616     if(header->lock>=0) {
617       if(version != header->version) {
618         transAbortProcess(oidwrlocked, numoidwrlocked);
619 #ifdef STMSTATS
620         ABORTCOUNT(header);
621         (typesCausingAbort[TYPE(header)])++;
622         getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *)oidrdversion, 0);
623 #endif
624         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
625         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
626         if (c_numelements>=200) {
627           free(oidrdlocked);
628           free(oidrdversion);
629           free(oidwrlocked);
630         }
631         return TRANS_ABORT;
632       }
633     } else { /* cannot aquire lock */
634       if(version == header->version) {
635         softabort=1;
636       } else {
637         transAbortProcess(oidwrlocked, numoidwrlocked);
638 #ifdef STMSTATS
639         ABORTCOUNT(header);
640         (typesCausingAbort[TYPE(header)])++;
641         getTotalAbortCount(i+1, numoidrdlocked, oidrdlocked, (void *)oidrdversion, 0);
642 #endif
643         DEBUGSTM("RD Abort: rd: %u wr: %u tot: %u type: %u ver: %u\n", numoidrdlocked, numoidwrlocked, c_numelements, TYPE(header), header->version);
644         DEBUGSTMSTAT("RD Abort: Access Count: %u AbortCount: %u type: %u ver: %u \n", header->accessCount, header->abortCount, TYPE(header), header->version);
645         if (c_numelements>=200) {
646           free(oidrdlocked);
647           free(oidrdversion);
648           free(oidwrlocked);
649         }
650         return TRANS_ABORT;
651       }
652     }
653   }
654
655   /* Decide the final response */
656   if (softabort) {
657     transAbortProcess(oidwrlocked, numoidwrlocked);
658     DEBUGSTM("Soft Abort: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
659     if (c_numelements>=200) {
660       free(oidrdlocked);
661       free(oidrdversion);
662       free(oidwrlocked);
663     }
664     return TRANS_SOFT_ABORT;
665   } else {
666     transCommitProcess(oidwrlocked, numoidwrlocked);
667     DEBUGSTM("Commit: rd: %u wr: %u tot: %u\n", numoidrdlocked, numoidwrlocked, c_numelements);
668     if (c_numelements>=200) {
669       free(oidrdlocked);
670       free(oidrdversion);
671       free(oidwrlocked);
672     }
673     return TRANS_COMMIT;
674   }
675 }
676
677
678 /* ==================================
679  * transAbortProcess
680  *
681  * =================================
682  */
683 int transAbortProcess(void **oidwrlocked, int numoidwrlocked) {
684   int i;
685   objheader_t *header;
686   /* Release read locks */
687
688   /* Release write locks */
689   for(i=0; i< numoidwrlocked; i++) {
690     /* Read from the main heap */
691     header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
692     write_unlock(&header->lock);
693   }
694
695 #ifdef STMSTATS
696   /* clear trec and then release objects locked */
697   struct objlist *ptr=lockedobjs;
698   while(ptr!=NULL) {
699     int max=ptr->offset;
700     for(i=0; i<max; i++) {
701       header = (objheader_t *)((char *)(ptr->objs[i]) - sizeof(objheader_t));
702       header->trec = NULL;
703       pthread_mutex_unlock(header->objlock);
704     }
705     ptr=ptr->next;
706   }
707 #endif
708 }
709
710 /* ==================================
711  * transCommitProcess
712  *
713  * =================================
714  */
715 int transCommitProcess(void ** oidwrlocked, int numoidwrlocked) {
716   objheader_t *header;
717   void *ptrcreate;
718   int i;
719   struct objlist *ptr=newobjs;
720   while(ptr!=NULL) {
721     int max=ptr->offset;
722     for(i=0; i<max; i++) {
723       //clear the new flag
724       ((struct ___Object___ *)ptr->objs[i])->___objstatus___=0;
725     }
726     ptr=ptr->next;
727   }
728
729   /* Copy from transaction cache -> main object store */
730   for (i = 0; i < numoidwrlocked; i++) {
731     /* Read from the main heap */
732     header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
733     int tmpsize;
734     GETSIZE(tmpsize, header);
735     struct ___Object___ *dst=(struct ___Object___*)oidwrlocked[i];
736     struct ___Object___ *src=t_chashSearch(oidwrlocked[i]);
737     dst->___cachedCode___=src->___cachedCode___;
738     dst->___cachedHash___=src->___cachedHash___;
739     A_memcpy(&dst[1], &src[1], tmpsize-sizeof(struct ___Object___));
740     __asm__ __volatile__("": : :"memory");
741     header->version++;
742   }
743   __asm__ __volatile__("": : :"memory");
744
745   /* Release write locks */
746   for(i=0; i< numoidwrlocked; i++) {
747     header = (objheader_t *)(((char *)(oidwrlocked[i])) - sizeof(objheader_t));
748     write_unlock(&header->lock);
749   }
750
751 #ifdef STMSTATS
752   /* clear trec and then release objects locked */
753   ptr=lockedobjs;
754   while(ptr!=NULL) {
755     int max=ptr->offset;
756     for(i=0; i<max; i++) {
757       header = (objheader_t *)(((char *)(ptr->objs[i])) - sizeof(objheader_t));
758       header->trec = NULL;
759       pthread_mutex_unlock(header->objlock);
760     }
761     ptr=ptr->next;
762   }
763 #endif
764
765   return 0;
766 }
767
768 /** ========================================================================================
769  * getTotalAbortCount
770  * params : start: start index of the loop
771  *        : stop: stop index of the loop
772  *        : startptr: pointer that points to where to start looking in the array/ linked list
773  *          0='r'/1='w' if found when visiting objects read/ objects modified
774  * =========================================================================================
775  **/
776 #ifdef STMSTATS
777 void getTotalAbortCount(int start, int stop, void *startptr, void *checkptr, int type) {
778   int i;
779   if(type) {
780     int isFirstTime = 0;
781     chashlistnode_t *curr = (chashlistnode_t *) startptr;
782     chashlistnode_t *ptr = c_table;
783     for(i = start; i < stop; i++) {
784       if(!isFirstTime)
785         curr = &ptr[i];
786       /* Inner loop to traverse the linked list of the cache lookupTable */
787       while(curr != NULL) {
788         if(curr->key == NULL)
789           break;
790         objheader_t * headeraddr=&((objheader_t *) curr->val)[-1];
791         objheader_t *header=(objheader_t *)(((char *)curr->key)-sizeof(objheader_t));
792         unsigned int version = headeraddr->version;
793         /* versions do not match */
794         if(version != header->version) {
795           ABORTCOUNT(header);
796           (typesCausingAbort[TYPE(header)])++;
797         }
798         curr = curr->next;
799       }
800       isFirstTime = 1;
801     }
802   } else {
803     /* Go through oids read that are locked */
804     for(i = start; i < stop; i++) {
805       objheader_t *header = ((void **)startptr)[i];
806       unsigned int version = ((int *)checkptr)[i];
807       if(version != header->version) { /* versions do not match */
808         ABORTCOUNT(header);
809         (typesCausingAbort[TYPE(header)])++;
810       }
811     }
812   }
813 }
814
815 /**
816  * needLock
817  * params: Object header
818  * Locks an object that causes aborts
819  **/
820 void needLock(objheader_t *header, void *gl) {
821   int lockstatus;
822   threadrec_t *ptr;
823   while((lockstatus = pthread_mutex_trylock(header->objlock)) 
824       && ((ptr = header->trec) == NULL)) { //retry
825     ;
826   }
827   if(lockstatus==0) { //acquired lock
828     /* Set trec */
829     header->trec = trec;
830   } else { //failed to get lock
831     trec->blocked=1;
832     //memory barrier
833     __asm__ __volatile__("":::"memory");
834     //see if other thread is blocked
835     if(ptr->blocked == 1) {
836       //it might be block, so ignore lock and clear our blocked flag
837       trec->blocked=0;
838       return;
839     } else { 
840 #ifdef PRECISE_GC
841       stopforgc((struct garbagelist *)gl);
842 #endif
843       //grab lock and wait our turn
844       pthread_mutex_lock(header->objlock);
845 #ifdef PRECISE_GC
846       restartaftergc();
847 #endif
848       /* we have lock, so we are not blocked anymore */
849       trec->blocked = 0;
850       /* Set our trec */
851       header->trec = trec;
852     }
853   }
854   //trec->blocked is zero now
855
856   /* Save the locked object */
857   if (lockedobjs->offset<MAXOBJLIST) {
858     lockedobjs->objs[lockedobjs->offset++]=OID(header);
859   } else {
860     struct objlist *tmp=malloc(sizeof(struct objlist));
861     tmp->next=lockedobjs;
862     tmp->objs[0]=OID(header);
863     tmp->offset=1;
864     lockedobjs=tmp;
865   }
866 }
867 #endif