small changes and bug fix for getting stats
[IRC.git] / Robust / src / Runtime / thread.c
1 #include "runtime.h"
2 #include <sys/types.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include "thread.h"
7 #include "option.h"
8 #include <signal.h>
9
10 #ifdef DSTM
11 #include <DSTM/interface/dstm.h>
12 #include <DSTM/interface/llookup.h>
13 #endif
14
15 #ifndef RAW
16 #include <stdio.h>
17 #endif
18 #ifdef STM
19 #include "tm.h"
20 #endif
21 #include <execinfo.h>
22
23
24 int threadcount;
25 pthread_mutex_t gclock;
26 pthread_mutex_t gclistlock;
27 pthread_cond_t gccond;
28 pthread_mutex_t objlock;
29 pthread_cond_t objcond;
30
31 pthread_mutex_t atomiclock;
32
33 pthread_mutex_t joinlock;
34 pthread_cond_t joincond;
35 pthread_key_t threadlocks;
36 pthread_mutex_t threadnotifylock;
37 pthread_cond_t threadnotifycond;
38 pthread_key_t oidval;
39
40 #if defined(THREADS) || defined(DSTM) || defined(STM)
41 #ifndef MAC
42 extern __thread struct listitem litem;
43 #else
44 pthread_key_t litemkey;
45 #endif
46 extern struct listitem * list;
47 #endif
48
49 void threadexit() {
50 #ifdef DSTM
51   objheader_t* ptr;
52   unsigned int oidvalue;
53 #endif
54   void *value;
55
56 #ifdef THREADS
57   struct ___Object___ *ll=pthread_getspecific(threadlocks);
58   while(ll!=NULL) {
59     struct ___Object___ *llnext=ll->___nextlockobject___;
60     ll->___nextlockobject___=NULL;
61     ll->___prevlockobject___=NULL;
62     ll->lockcount=0;
63     ll->tid=0; //unlock it
64     ll=llnext;
65   }
66   pthread_mutex_lock(&objlock); //wake everyone up
67   pthread_cond_broadcast(&objcond);
68   pthread_mutex_unlock(&objlock);
69 #endif
70   pthread_mutex_lock(&gclistlock);
71 #ifdef THREADS
72   pthread_setspecific(threadlocks, litem.locklist);
73 #endif
74 #ifndef MAC
75   if (litem.prev==NULL) {
76     list=litem.next;
77   } else {
78     litem.prev->next=litem.next;
79   }
80   if (litem.next!=NULL) {
81     litem.next->prev=litem.prev;
82   }
83 #else
84   {
85     struct listitem *litem=pthread_getspecific(litemkey);
86     if (litem->prev==NULL) {
87       list=litem->next;
88     } else {
89       litem->prev->next=litem->next;
90     }
91     if (litem->next!=NULL) {
92       litem->next->prev=litem->prev;
93     }
94   }
95 #endif
96   threadcount--;
97   pthread_cond_signal(&gccond);
98   pthread_mutex_unlock(&gclistlock);
99 #ifdef DSTM
100   /* Add transaction to check if thread finished for join operation */
101   value = pthread_getspecific(oidval);
102   oidvalue = *((unsigned int *)value);
103   goto transstart;
104 transstart:
105   {
106     transStart();
107     ptr = transRead(oidvalue);
108     struct ___Thread___ *p = (struct ___Thread___ *) ptr;
109     p->___threadDone___ = 1;
110     *((unsigned int *)&((struct ___Object___ *) p)->___localcopy___) |=DIRTY;
111     if(transCommit() != 0) {
112       goto transstart;
113     }
114   }
115 #endif
116   pthread_exit(NULL);
117 }
118
119 void threadhandler(int sig, struct sigcontext ctx) {
120   void *buffer[100];
121   char **strings;
122   int nptrs,j;
123
124   printf("We just took sig=%d\n",sig);
125   printf("signal\n");
126   printf("To get stack trace, set breakpoint in threadhandler in gdb\n");
127   nptrs = backtrace(buffer, 100);
128 #ifdef BIT64
129   buffer[1]=(void *)ctx.rip;
130 #else
131   buffer[1]=(void *)ctx.eip;
132 #endif
133
134   strings = backtrace_symbols(buffer, nptrs);
135   if (strings == NULL) {
136     perror("backtrace_symbols");
137     exit(EXIT_FAILURE);
138   }
139   
140   for (j = 0; j < nptrs; j++)
141     printf("%s\n", strings[j]);
142   
143   threadexit();
144 }
145
146 struct primitivelist *pl;
147
148 void initializethreads() {
149   struct sigaction sig;
150   threadcount=1;
151 #ifdef THREADS
152   pthread_mutex_init(&atomiclock, NULL);
153 #endif
154   pthread_mutex_init(&gclock, NULL);
155   pthread_mutex_init(&gclistlock, NULL);
156   pthread_cond_init(&gccond, NULL);
157   pthread_mutex_init(&objlock,NULL);
158   pthread_cond_init(&objcond,NULL);
159   pthread_mutex_init(&joinlock,NULL);
160   pthread_cond_init(&joincond,NULL);
161   pthread_key_create(&threadlocks, NULL);
162 #ifdef MAC
163   pthread_key_create(&litem, NULL);
164 #endif
165   processOptions();
166   initializeexithandler();
167
168   //deprecated use of sighandler, but apparently still works
169   sig.sa_handler=(void *)threadhandler;
170   sig.sa_flags=SA_RESTART;
171   sigemptyset(&sig.sa_mask);
172
173   /* Catch bus errors, segmentation faults, and floating point exceptions*/
174   sigaction(SIGBUS,&sig,0);
175   sigaction(SIGSEGV,&sig,0);
176   sigaction(SIGFPE,&sig,0);
177   signal(SIGPIPE, SIG_IGN);
178 #ifdef STM
179   newobjs=calloc(1, sizeof(struct objlist));
180   t_cache = objstrCreate(1048576);
181   t_reserve=NULL;
182   t_chashCreate(CHASH_SIZE, CLOADFACTOR);
183 #ifdef READSET
184   rd_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
185 #endif
186 #ifdef DELAYCOMP
187   dc_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
188   ptrstack.count=0;
189   primstack.count=0;
190   pl=&primstack;
191 #endif
192 #ifdef STMSTATS
193   trec=calloc(1, sizeof(threadrec_t));
194   trec->blocked = 0;
195   lockedobjs=calloc(1, sizeof(struct objlist));
196   objlockscope = calloc(1, sizeof(objlockstate_t));
197   pthread_mutex_init(&lockedobjstore, NULL);
198   { 
199     int i;
200     for(i=0; i<TOTALNUMCLASSANDARRAY; i++) {
201       typesCausingAbort[i].numabort = 0;
202       typesCausingAbort[i].numaccess = 0;
203       typesCausingAbort[i].numtrans = 0;
204     }
205   }
206 #endif
207 #endif
208 #ifdef MAC
209   struct listitem *litem=malloc(sizeof(struct listitem));
210   pthread_setspecific(litemkey, litem);
211   litem->prev=NULL;
212   litem->next=list;
213   if(list!=NULL)
214     list->prev=litem;
215   list=litem;
216 #else
217   //Add our litem to list of threads
218   litem.prev=NULL;
219   litem.next=list;
220   if(list!=NULL)
221     list->prev=&litem;
222   list=&litem;
223 #endif
224 }
225
226 #if defined(THREADS)||defined(STM)
227 void initthread(struct ___Thread___ * ___this___) {
228 #ifdef PRECISE_GC
229   INTPTR p[]={1, (INTPTR) NULL, (INTPTR) ___this___};
230   //Add our litem to list of threads
231 #ifdef MAC
232   struct listitem litem;
233   pthread_setspecific(litemkey, &litem);
234 #endif
235   litem.prev=NULL;
236   pthread_mutex_lock(&gclistlock);
237   litem.next=list;
238   if(list!=NULL)
239     list->prev=&litem;
240   list=&litem;
241   pthread_mutex_unlock(&gclistlock);
242   
243 #ifdef THREADS
244   ___Thread______staticStart____L___Thread___((struct ___Thread______staticStart____L___Thread____params *)p);
245 #else
246   newobjs=calloc(1, sizeof(struct objlist));
247 #ifdef STMSTATS
248   trec=calloc(1, sizeof(threadrec_t));
249   trec->blocked = 0;
250   lockedobjs=calloc(1, sizeof(struct objlist));
251 #endif
252   t_cache = objstrCreate(1048576);
253   t_reserve=NULL;
254   t_chashCreate(CHASH_SIZE, CLOADFACTOR);
255 #ifdef READSET
256   rd_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
257 #endif
258 #ifdef DELAYCOMP
259   dc_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
260   ptrstack.count=0;
261   primstack.count=0;
262 #endif
263  ___Thread____NNR____staticStart____L___Thread___((struct ___Thread____NNR____staticStart____L___Thread____params *)p);
264  objstrDelete(t_cache);
265  objstrDelete(t_reserve);
266  t_chashDelete();
267  free(newobjs);
268 #ifdef STMSTATS
269  free(lockedobjs);
270 #endif
271 #endif
272   ___this___=(struct ___Thread___ *) p[2];
273 #else
274   ___Thread______staticStart____L___Thread___(___this___);
275 #endif
276   ___this___->___finished___=1;
277   pthread_mutex_lock(&joinlock);
278   pthread_cond_signal(&joincond);
279   pthread_mutex_unlock(&joinlock);
280
281   pthread_mutex_lock(&gclistlock);
282 #ifdef THREADS
283   pthread_setspecific(threadlocks, litem.locklist);
284 #endif
285   if (litem.prev==NULL) {
286     list=litem.next;
287   } else {
288     litem.prev->next=litem.next;
289   }
290   if (litem.next!=NULL) {
291     litem.next->prev=litem.prev;
292   }
293   threadcount--;
294   pthread_cond_signal(&gccond);
295   pthread_mutex_unlock(&gclistlock);
296 }
297 #endif
298
299 void CALL11(___Thread______sleep____J, long long ___millis___, long long ___millis___) {
300 #if defined(THREADS)||defined(STM)
301 #ifdef PRECISE_GC
302   stopforgc((struct garbagelist *)___params___);
303 #endif
304 #endif
305   usleep(___millis___);
306 #if defined(THREADS)||defined(STM)
307 #ifdef PRECISE_GC
308   restartaftergc();
309 #endif
310 #endif
311 }
312
313 #if defined(DSTM)|| defined(THREADS)||defined(STM)
314 void CALL00(___Thread______yield____) {
315   pthread_yield();
316 }
317 #endif
318
319 #ifdef DSTM
320 /* Add thread join capability */
321 void CALL01(___Thread______join____, struct ___Thread___ * ___this___) {
322   unsigned int *oidarray;
323   unsigned short *versionarray, version;
324   objheader_t *ptr;
325   /* Add transaction to check if thread finished for join operation */
326 transstart:
327   transStart();
328   ptr = transRead((unsigned int) VAR(___this___));
329   struct ___Thread___ *p = (struct ___Thread___ *) ptr;
330 #ifdef THREADJOINDEBUG
331   printf("Start join process for Oid = %x\n", (unsigned int) VAR(___this___));
332 #endif
333   if(p->___threadDone___ == 1) {
334 #ifdef THREADJOINDEBUG
335     printf("Thread oid = %x is done\n", (unsigned int) VAR(___this___));
336 #endif
337     transAbort();
338     return;
339   } else {
340
341     version = (ptr-1)->version;
342     if((oidarray = calloc(1, sizeof(unsigned int))) == NULL) {
343       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
344       return;
345     }
346
347     oidarray[0] = (unsigned int) VAR(___this___);
348
349     if((versionarray = calloc(1, sizeof(unsigned short))) == NULL) {
350       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
351       free(oidarray);
352       return;
353     }
354     versionarray[0] = version;
355     /* Request Notification */
356 #ifdef PRECISE_GC
357     stopforgc((struct garbagelist *)___params___);
358 #endif
359     reqNotify(oidarray, versionarray, 1);
360 #ifdef PRECISE_GC
361     restartaftergc();
362 #endif
363     free(oidarray);
364     free(versionarray);
365     transAbort();
366     goto transstart;
367   }
368   return;
369 }
370 #endif
371
372 #if defined(THREADS)||defined(STM)
373 void CALL01(___Thread______nativeJoin____, struct ___Thread___ * ___this___) {
374   pthread_mutex_lock(&joinlock);
375   while(!VAR(___this___)->___finished___) {
376 #ifdef PRECISE_GC
377   stopforgc((struct garbagelist *)___params___);
378 #endif
379     pthread_cond_wait(&joincond, &joinlock);
380 #ifdef PRECISE_GC
381     restartaftergc();
382 #endif
383   }
384   pthread_mutex_unlock(&joinlock);
385 }
386
387 void CALL01(___Thread______nativeCreate____, struct ___Thread___ * ___this___) {
388   pthread_t thread;
389   int retval;
390   pthread_attr_t nattr;
391
392   pthread_mutex_lock(&gclistlock);
393   threadcount++;
394   pthread_mutex_unlock(&gclistlock);
395   pthread_attr_init(&nattr);
396   pthread_attr_setdetachstate(&nattr, PTHREAD_CREATE_DETACHED);
397   INTPTR stacksize;
398   pthread_attr_getstacksize(&nattr, &stacksize);
399   printf("STACKSIZE=%u\n",stacksize);
400   do {
401     retval=pthread_create(&thread, &nattr, (void * (*)(void *)) &initthread, VAR(___this___));
402     if (retval!=0)
403       usleep(1);
404   } while(retval!=0);
405   /* This next statement will likely not work on many machines */
406
407   pthread_attr_destroy(&nattr);
408 }
409 #endif
410
411 #ifdef DSTM
412 void CALL12(___Thread______start____I, int ___mid___, struct ___Thread___ * ___this___, int ___mid___) {
413   startRemoteThread((unsigned int)VAR(___this___), ___mid___);
414 }
415 #endif
416
417 #ifdef DSTM
418 void globalDestructor(void *value) {
419   free(value);
420   pthread_setspecific(oidval, NULL);
421 }
422
423 void initDSMthread(int *ptr) {
424   objheader_t *tmp;
425   void *threadData;
426   int oid=ptr[0];
427   int type=ptr[1];
428   free(ptr);
429 #ifdef PRECISE_GC
430   int p[]={1, 0 /* NULL */, oid};
431 #ifdef MAC
432   struct listitem litem;
433   pthread_setspecific(litemkey, &litem);
434 #endif
435
436   //Add our litem to list of threads
437   litem.prev=NULL;
438   pthread_mutex_lock(&gclistlock);
439   litem.next=list;
440   if(list!=NULL)
441     list->prev=&litem;
442   list=&litem;
443   pthread_mutex_unlock(&gclistlock);
444
445   ((void(*) (void *))virtualtable[type*MAXCOUNT+RUNMETHOD])(p);
446 #else
447   ((void(*) (void *))virtualtable[type*MAXCOUNT+RUNMETHOD])(oid);
448 #endif
449   threadData = calloc(1, sizeof(unsigned int));
450   *((unsigned int *) threadData) = oid;
451   pthread_setspecific(oidval, threadData);
452   pthread_mutex_lock(&gclistlock);
453
454 #ifdef THREADS
455   pthread_setspecific(threadlocks, litem.locklist);
456 #endif
457   if (litem.prev==NULL) {
458     list=litem.next;
459   } else {
460     litem.prev->next=litem.next;
461   }
462   if (litem.next!=NULL) {
463     litem.next->prev=litem.prev;
464   }
465   threadcount--;
466   pthread_cond_signal(&gccond);
467   pthread_mutex_unlock(&gclistlock);
468   /* Add transaction to check if thread finished for join operation */
469   goto transstart;
470 transstart:
471   {
472     transStart();
473     tmp  = transRead((unsigned int) oid);
474     ((struct ___Thread___ *)tmp)->___threadDone___ = 1;
475     *((unsigned int *)&((struct ___Object___ *) tmp)->___localcopy___) |=DIRTY;
476     if(transCommit()!= 0) {
477       goto transstart;
478     }
479   }
480   pthread_exit(NULL);
481 }
482
483 void startDSMthread(int oid, int objType) {
484   pthread_t thread;
485   int retval;
486   pthread_attr_t nattr;
487
488   pthread_mutex_lock(&gclistlock);
489   threadcount++;
490   pthread_mutex_unlock(&gclistlock);
491   pthread_attr_init(&nattr);
492   pthread_attr_setdetachstate(&nattr, PTHREAD_CREATE_DETACHED);
493   int * ptr=malloc(sizeof(int)*2);
494   ptr[0]=oid;
495   ptr[1]=objType;
496   pthread_key_create(&oidval, globalDestructor);
497   do {
498     retval=pthread_create(&thread, &nattr, (void * (*)(void *)) &initDSMthread,  ptr);
499     if (retval!=0)
500       usleep(1);
501   } while(retval!=0);
502
503   pthread_attr_destroy(&nattr);
504 }
505
506 #endif