changes
[IRC.git] / Robust / src / Runtime / thread.c
1 #include "runtime.h"
2 #include <sys/types.h>
3 #include <sys/mman.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <stdlib.h>
7 #include "thread.h"
8 #include "option.h"
9 #include <signal.h>
10 #include "methodheaders.h"
11 #ifndef MULTICORE
12 #include "mlp_lock.h"
13 #endif
14
15 #ifdef DSTM
16 #ifdef RECOVERY
17 #include <DSTM/interface_recovery/dstm.h>
18 #include <DSTM/interface_recovery/llookup.h>
19 #else
20 #include <DSTM/interface/dstm.h>
21 #include <DSTM/interface/llookup.h>
22 #endif
23 #endif
24
25 #ifndef RAW
26 #include <stdio.h>
27 #endif
28 #ifdef STM
29 #include "tm.h"
30 #endif
31 #include <execinfo.h>
32 #ifdef EVENTMONITOR
33 #include "monitor.h"
34 #endif
35
36
37 int threadcount;
38 pthread_mutex_t gclock;
39 pthread_mutex_t gclistlock;
40 pthread_cond_t gccond;
41 pthread_mutex_t objlock;
42 pthread_cond_t objcond;
43
44 pthread_mutex_t atomiclock;
45
46 pthread_mutex_t joinlock;
47 pthread_cond_t joincond;
48 pthread_key_t threadlocks;
49 pthread_key_t macthreadid;
50 pthread_mutex_t threadnotifylock;
51 pthread_cond_t threadnotifycond;
52 pthread_key_t oidval;
53
54 #if defined(THREADS) || defined(DSTM) || defined(STM)||defined(MLP)
55 #ifndef MAC
56 extern __thread struct listitem litem;
57 #else
58 pthread_key_t litemkey;
59 #endif
60 extern struct listitem * list;
61 #endif
62
63 void threadexit() {
64 #ifdef DSTM
65   objheader_t* ptr;
66   unsigned int oidvalue;
67 #endif
68   void *value;
69
70 #ifdef THREADS
71 #ifdef MAC
72   struct lockvector *lptr=(struct lockvector *) pthread_getspecific(threadlocks);
73 #else
74   struct lockvector *lptr=&lvector;
75 #endif
76   for(lptr->index--;lptr->index>=0;lptr->index--) {
77     if (lptr->locks[lptr->index].islastlock) {
78       struct ___Object___ *ll=lptr->locks[lptr->index].object;
79       ll->tid=0;
80     }
81   }
82
83   pthread_mutex_lock(&objlock); //wake everyone up
84   pthread_cond_broadcast(&objcond);
85   pthread_mutex_unlock(&objlock);
86 #endif
87   pthread_mutex_lock(&gclistlock);
88
89 #ifndef MAC
90   if (litem.prev==NULL) {
91     list=litem.next;
92   } else {
93     litem.prev->next=litem.next;
94   }
95   if (litem.next!=NULL) {
96     litem.next->prev=litem.prev;
97   }
98 #else
99   {
100     struct listitem *litem=pthread_getspecific(litemkey);
101     if (litem->prev==NULL) {
102       list=litem->next;
103     } else {
104       litem->prev->next=litem->next;
105     }
106     if (litem->next!=NULL) {
107       litem->next->prev=litem->prev;
108     }
109   }
110 #endif
111   threadcount--;
112   pthread_cond_signal(&gccond);
113   pthread_mutex_unlock(&gclistlock);
114 #ifdef DSTM
115   /* Add transaction to check if thread finished for join operation */
116   value = pthread_getspecific(oidval);
117   oidvalue = *((unsigned int *)value);
118   goto transstart;
119 transstart:
120   {
121     transStart();
122     ptr = transRead(oidvalue);
123     struct ___Thread___ *p = (struct ___Thread___ *) ptr;
124     p->___threadDone___ = 1;
125     *((unsigned int *)&((struct ___Object___ *) p)->___localcopy___) |=DIRTY;
126     if(transCommit() != 0) {
127       goto transstart;
128     }
129   }
130 #endif
131   pthread_exit(NULL);
132 }
133
134 void threadhandler(int sig, struct sigcontext ctx) {
135   void *buffer[100];
136   char **strings;
137   int nptrs,j;
138
139   printf("We just took sig=%d\n",sig);
140   printf("signal\n");
141   printf("To get stack trace, set breakpoint in threadhandler in gdb\n");
142   nptrs = backtrace(buffer, 100);
143 #ifdef BIT64
144   buffer[1]=(void *)ctx.rip;
145 #else
146   buffer[1]=(void *)ctx.eip;
147 #endif
148
149   strings = backtrace_symbols(buffer, nptrs);
150   if (strings == NULL) {
151     perror("backtrace_symbols");
152     exit(EXIT_FAILURE);
153   }
154   
155   for (j = 0; j < nptrs; j++)
156     printf("%s\n", strings[j]);
157   
158   threadexit();
159 }
160
161 #define downpage(x) ((void *)(((INTPTR)x)&~((INTPTR)4095)))
162
163 void initializethreads() {
164   struct sigaction sig;
165   threadcount=1;
166 #ifdef THREADS
167   pthread_mutex_init(&atomiclock, NULL);
168 #endif
169   pthread_mutex_init(&gclock, NULL);
170   pthread_mutex_init(&gclistlock, NULL);
171   pthread_cond_init(&gccond, NULL);
172   pthread_mutex_init(&objlock,NULL);
173   pthread_cond_init(&objcond,NULL);
174   pthread_mutex_init(&joinlock,NULL);
175   pthread_cond_init(&joincond,NULL);
176 #ifdef MAC
177   pthread_key_create(&macthreadid, NULL);
178   pthread_key_create(&threadlocks, NULL);
179   pthread_key_create(&litem, NULL);
180 #endif
181   processOptions();
182   initializeexithandler();
183 #ifdef AFFINITY
184   set_affinity();
185 #endif
186
187   //deprecated use of sighandler, but apparently still works
188 #ifdef SANDBOX
189   sig.sa_handler=(void *)errorhandler;
190   abortenabled=0;
191 #else
192   sig.sa_handler=(void *)threadhandler;
193 #endif
194   sig.sa_flags=SA_RESTART;
195   sigemptyset(&sig.sa_mask);
196
197   /* Catch bus errors, segmentation faults, and floating point exceptions*/
198   sigaction(SIGBUS,&sig,0);
199   sigaction(SIGSEGV,&sig,0);
200   sigaction(SIGFPE,&sig,0);
201   signal(SIGPIPE, SIG_IGN);
202 #ifdef STM
203   newobjs=calloc(1, sizeof(struct objlist));
204   t_cache = objstrCreate(1048576);
205   t_reserve=NULL;
206   t_chashCreate(CHASH_SIZE, CLOADFACTOR);
207 #ifdef READSET
208   rd_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
209 #endif
210 #ifdef DELAYCOMP
211   dc_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
212   ptrstack.count=0;
213   primstack.count=0;
214   branchstack.count=0;
215 #if defined(STMARRAY)&&!defined(DUALVIEW)
216   arraystack.count=0;
217 #endif
218   int a=mprotect((downpage(&ptrstack.buffer[1024])), 4096, PROT_NONE);
219   if (a==-1)
220     perror("ptrstack");
221   a=mprotect(downpage(&primstack.array[MAXVALUES]), 4096, PROT_NONE);
222   if (a==-1)
223     perror("primstack");
224   a=mprotect(downpage(&branchstack.array[MAXBRANCHES]), 4096, PROT_NONE);
225   if (a==-1)
226     perror("branchstack");
227 #if defined(STMARRAY)&&!defined(DUALVIEW)
228   a=mprotect(downpage(&arraystack.index[MAXARRAY]), 4096, PROT_NONE);
229   if (a==-1)
230     perror("arraystack");
231 #endif
232 #endif
233 #ifdef STMSTATS
234   trec=calloc(1, sizeof(threadrec_t));
235   trec->blocked = 0;
236   lockedobjs=calloc(1, sizeof(struct objlist));
237   objlockscope = calloc(1, sizeof(objlockstate_t));
238   pthread_mutex_init(&lockedobjstore, NULL);
239   { 
240     int i;
241     for(i=0; i<TOTALNUMCLASSANDARRAY; i++) {
242       typesCausingAbort[i].numaccess = 0;
243       typesCausingAbort[i].numabort = 0;
244       typesCausingAbort[i].numtrans = 0;
245     }
246   }
247 #endif
248 #endif
249 #ifdef MAC
250   struct listitem *litem=malloc(sizeof(struct listitem));
251   struct lockvector *lvector=malloc(sizeof(struct lockvector));
252   litem->lockvector=lvector;
253   lvector->index=0;
254   pthread_setspecific(threadlocks, lvector);
255   pthread_setspecific(macthreadid, 0);
256   pthread_setspecific(litemkey, litem);
257   litem->prev=NULL;
258   litem->next=list;
259   if(list!=NULL)
260     list->prev=litem;
261   list=litem;
262 #else
263   //Add our litem to list of threads
264   mythreadid=0;
265   litem.prev=NULL;
266   litem.next=list;
267   litem.lvector=&lvector;
268   lvector.index=0;
269   if(list!=NULL)
270     list->prev=&litem;
271   list=&litem;
272 #endif
273 #ifdef EVENTMONITOR
274   createmonitor();
275 #endif
276 }
277
278 #if defined(THREADS)||defined(STM)
279 int threadcounter=0;
280
281 void initthread(struct ___Thread___ * ___this___) {
282 #ifdef AFFINITY
283   set_affinity();
284 #endif
285 #ifdef EVENTMONITOR
286   createmonitor();
287 #endif
288 #ifdef SANDBOX
289   struct sigaction sig;
290   abortenabled=0;
291   sig.sa_handler=(void *)errorhandler;
292   sig.sa_flags=SA_RESTART;
293   sigemptyset(&sig.sa_mask);
294
295   /* Catch bus errors, segmentation faults, and floating point exceptions*/
296   sigaction(SIGBUS,&sig,0);
297   sigaction(SIGSEGV,&sig,0);
298   sigaction(SIGFPE,&sig,0);
299 #endif
300 #ifdef PRECISE_GC
301   INTPTR p[]={1, (INTPTR) NULL, (INTPTR) ___this___};
302   //Add our litem to list of threads
303 #ifdef MAC
304   struct listitem litem;
305   pthread_setspecific(litemkey, &litem);
306   struct lockvector lvector;
307   pthread_setspecific(threadlocks, &lvector);
308 #endif
309   litem.lvector=&lvector;
310   lvector.index=0;
311   litem.prev=NULL;
312   pthread_mutex_lock(&gclistlock);
313 #ifdef MAC
314   pthread_setspecific(macthreadid, ++threadcounter);
315 #else
316   mythreadid=++threadcounter;
317 #endif
318   litem.next=list;
319   if(list!=NULL)
320     list->prev=&litem;
321   list=&litem;
322   pthread_mutex_unlock(&gclistlock);
323 #ifdef THREADS
324   ___Thread______staticStart____L___Thread___((struct ___Thread______staticStart____L___Thread____params *)p);
325 #else
326   newobjs=calloc(1, sizeof(struct objlist));
327 #ifdef STMSTATS
328   trec=calloc(1, sizeof(threadrec_t));
329   trec->blocked = 0;
330   lockedobjs=calloc(1, sizeof(struct objlist));
331 #endif
332   t_cache = objstrCreate(1048576);
333   t_reserve=NULL;
334   t_chashCreate(CHASH_SIZE, CLOADFACTOR);
335 #ifdef READSET
336   rd_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
337 #endif
338 #ifdef DELAYCOMP
339   dc_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
340   ptrstack.count=0;
341   primstack.count=0;
342   branchstack.count=0;
343 #if defined(STMARRAY)&&!defined(DUALVIEW)
344   arraystack.count=0;
345 #endif
346   int a=mprotect(downpage(&ptrstack.buffer[1024]), 4096, PROT_NONE);
347   if (a==-1)
348     perror("ptrstack");
349   a=mprotect(downpage(&primstack.array[MAXVALUES]), 4096, PROT_NONE);
350   if (a==-1)
351     perror("primstack");
352   a=mprotect(downpage(&branchstack.array[MAXBRANCHES]), 4096, PROT_NONE);
353   if (a==-1)
354     perror("branchstack");
355 #if defined(STMARRAY)&!defined(DUALVIEW)
356   a=mprotect(downpage(&arraystack.index[MAXARRAY]), 4096, PROT_NONE);
357   if (a==-1)
358     perror("arraystack");
359 #endif
360 #endif
361  ___Thread____NNR____staticStart____L___Thread___((struct ___Thread____NNR____staticStart____L___Thread____params *)p);
362  objstrDelete(t_cache);
363  objstrDelete(t_reserve);
364  t_chashDelete();
365  free(newobjs);
366 #ifdef STMSTATS
367  free(lockedobjs);
368 #endif
369 #endif
370   ___this___=(struct ___Thread___ *) p[2];
371 #else
372   ___Thread______staticStart____L___Thread___(___this___);
373 #endif
374   ___this___->___finished___=1;
375   pthread_mutex_lock(&joinlock);
376   pthread_cond_signal(&joincond);
377   pthread_mutex_unlock(&joinlock);
378
379   pthread_mutex_lock(&gclistlock);
380   if (litem.prev==NULL) {
381     list=litem.next;
382   } else {
383     litem.prev->next=litem.next;
384   }
385   if (litem.next!=NULL) {
386     litem.next->prev=litem.prev;
387   }
388   threadcount--;
389   pthread_cond_signal(&gccond);
390   pthread_mutex_unlock(&gclistlock);
391 }
392 #endif
393
394 #ifdef D___Thread______sleep____J
395 void CALL11(___Thread______sleep____J, long long ___millis___, long long ___millis___) {
396 #if defined(THREADS)||defined(STM)
397 #ifdef PRECISE_GC
398   stopforgc((struct garbagelist *)___params___);
399 #endif
400 #endif
401   usleep(___millis___*1000);
402 #if defined(THREADS)||defined(STM)
403 #ifdef PRECISE_GC
404   restartaftergc();
405 #endif
406 #endif
407 }
408 #endif
409
410 #ifdef D___Thread______yield____
411 void CALL00(___Thread______yield____) {
412   pthread_yield();
413 }
414 #endif
415
416 #ifdef D___Thread______abort____
417 void CALL00(___Thread______abort____) {
418 #ifdef SANDBOX
419   _longjmp(aborttrans,1);
420 #endif
421 }
422 #endif
423
424 #ifdef DSTM
425 #ifdef RECOVERY
426 // return if the machine is dead
427 #ifdef D___Thread______nativeGetStatus____I
428 int CALL12(___Thread______nativeGetStatus____I, int ___mid___, struct ___Thread___ * ___this___, int ___mid___) {
429   return getStatus(___mid___);
430 }
431 #endif
432 #else 
433 #ifdef D___Thread______nativeGetStatus____I
434 int CALL12(___Thread______nativeGetStatus____I, int ___mid___, struct ___Thread___ * ___this___, int ___mid___) {
435   return 0;
436 }
437 #endif
438 #endif
439 #endif
440 #ifdef DSTM
441 /* Add thread join capability */
442 #ifdef D___Thread______join____
443 void CALL01(___Thread______join____, struct ___Thread___ * ___this___) {
444   unsigned int *oidarray;
445   unsigned short *versionarray, version;
446   objheader_t *ptr;
447   /* Add transaction to check if thread finished for join operation */
448 transstart:
449   transStart();
450   ptr = transRead((unsigned int) VAR(___this___));
451   struct ___Thread___ *p = (struct ___Thread___ *) ptr;
452 #ifdef THREADJOINDEBUG
453   printf("Start join process for Oid = %x\n", (unsigned int) VAR(___this___));
454 #endif
455   if(p->___threadDone___ == 1) {
456 #ifdef THREADJOINDEBUG
457     printf("Thread oid = %x is done\n", (unsigned int) VAR(___this___));
458 #endif
459     transAbort();
460     return;
461   }
462 #ifdef RECOVERY
463   else if( checkiftheMachineDead(p->___mid___) == 0) {
464     printf("Thread oid = %x is dead\n", (unsigned int) VAR(___this___));
465     transAbort();
466     return;
467   }
468 #endif
469   else {
470     version = (ptr-1)->version;
471     if((oidarray = calloc(1, sizeof(unsigned int))) == NULL) {
472       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
473       return;
474     }
475
476     oidarray[0] = (unsigned int) VAR(___this___);
477
478     if((versionarray = calloc(1, sizeof(unsigned short))) == NULL) {
479       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
480       free(oidarray);
481       return;
482     }
483     versionarray[0] = version;
484     /* Request Notification */
485 #ifdef PRECISE_GC
486     stopforgc((struct garbagelist *)___params___);
487 #endif
488
489 #ifdef RECOVERY
490     reqNotify(oidarray, versionarray, 1,p->___mid___);
491 #else
492     reqNotify(oidarray, versionarray, 1);
493 #endif
494 #ifdef PRECISE_GC
495     restartaftergc();
496 #endif
497     free(oidarray);
498     free(versionarray);
499     transAbort();
500     goto transstart;
501   }
502   return;
503 }
504 #endif
505 #endif
506
507 #if defined(THREADS)||defined(STM)
508 #ifdef D___Thread______nativeJoin____
509 void CALL01(___Thread______nativeJoin____, struct ___Thread___ * ___this___) {
510   pthread_mutex_lock(&joinlock);
511   while(!VAR(___this___)->___finished___) {
512 #ifdef PRECISE_GC
513   stopforgc((struct garbagelist *)___params___);
514 #endif
515     pthread_cond_wait(&joincond, &joinlock);
516 #ifdef PRECISE_GC
517     restartaftergc();
518 #endif
519   }
520   pthread_mutex_unlock(&joinlock);
521 }
522 #endif
523
524 #ifdef D___Thread______nativeCreate____
525 void CALL01(___Thread______nativeCreate____, struct ___Thread___ * ___this___) {
526   pthread_t thread;
527   int retval;
528   pthread_attr_t nattr;
529
530   pthread_mutex_lock(&gclistlock);
531   threadcount++;
532   pthread_mutex_unlock(&gclistlock);
533   pthread_attr_init(&nattr);
534   pthread_attr_setdetachstate(&nattr, PTHREAD_CREATE_DETACHED);
535   INTPTR stacksize;
536   pthread_attr_getstacksize(&nattr, &stacksize);
537   do {
538     retval=pthread_create(&thread, &nattr, (void * (*)(void *)) &initthread, VAR(___this___));
539     if (retval!=0)
540       usleep(1);
541   } while(retval!=0);
542   /* This next statement will likely not work on many machines */
543
544   pthread_attr_destroy(&nattr);
545 }
546 #endif
547 #endif
548
549 #ifdef DSTM
550 #ifdef D___Thread______start____I
551 void CALL12(___Thread______start____I, int ___mid___, struct ___Thread___ * ___this___, int ___mid___) {
552   startRemoteThread((unsigned int)VAR(___this___), ___mid___);
553 }
554 #endif
555 #endif
556
557 #ifdef DSTM
558 void globalDestructor(void *value) {
559   free(value);
560   pthread_setspecific(oidval, NULL);
561 }
562
563 void initDSMthread(int *ptr) {
564   objheader_t *tmp;
565   void *threadData;
566   int oid=ptr[0];
567   int type=ptr[1];
568   free(ptr);
569 #ifdef PRECISE_GC
570   int p[]={1, 0 /* NULL */, oid};
571 #ifdef MAC
572   struct listitem litem;
573   pthread_setspecific(litemkey, &litem);
574 #endif
575
576   //Add our litem to list of threads
577   litem.prev=NULL;
578   pthread_mutex_lock(&gclistlock);
579   litem.next=list;
580   if(list!=NULL)
581     list->prev=&litem;
582   list=&litem;
583   pthread_mutex_unlock(&gclistlock);
584
585   ((void(*) (void *))virtualtable[type*MAXCOUNT+RUNMETHOD])(p);
586 #else
587   ((void(*) (void *))virtualtable[type*MAXCOUNT+RUNMETHOD])(oid);
588 #endif
589   threadData = calloc(1, sizeof(unsigned int));
590   *((unsigned int *) threadData) = oid;
591   pthread_setspecific(oidval, threadData);
592   pthread_mutex_lock(&gclistlock);
593
594 #ifdef THREADS
595   pthread_setspecific(threadlocks, litem.locklist);
596 #endif
597   if (litem.prev==NULL) {
598     list=litem.next;
599   } else {
600     litem.prev->next=litem.next;
601   }
602   if (litem.next!=NULL) {
603     litem.next->prev=litem.prev;
604   }
605   threadcount--;
606   pthread_cond_signal(&gccond);
607   pthread_mutex_unlock(&gclistlock);
608   /* Add transaction to check if thread finished for join operation */
609   goto transstart;
610 transstart:
611   {
612     transStart();
613     tmp  = transRead((unsigned int) oid);
614     ((struct ___Thread___ *)tmp)->___threadDone___ = 1;
615     *((unsigned int *)&((struct ___Object___ *) tmp)->___localcopy___) |=DIRTY;
616     if(transCommit()!= 0) {
617       goto transstart;
618     }
619   }
620   pthread_exit(NULL);
621 }
622
623 void startDSMthread(int oid, int objType) {
624   pthread_t thread;
625   int retval;
626   pthread_attr_t nattr;
627
628 //  printf("%s -> oid : %u\n",__func__,oid);
629
630   pthread_mutex_lock(&gclistlock);
631   threadcount++;
632   pthread_mutex_unlock(&gclistlock);
633   pthread_attr_init(&nattr);
634   pthread_attr_setdetachstate(&nattr, PTHREAD_CREATE_DETACHED);
635   int * ptr=malloc(sizeof(int)*2);
636   ptr[0]=oid;
637   ptr[1]=objType;
638   pthread_key_create(&oidval, globalDestructor);
639   
640   do {
641     retval=pthread_create(&thread, &nattr, (void * (*)(void *)) &initDSMthread,  ptr);
642     if (retval!=0)
643       usleep(1);
644   } while(retval!=0);
645
646   pthread_attr_destroy(&nattr);
647 }
648
649 #endif