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