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