runtime support for read only TRANSREADS
[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] = 0;
202     }
203   }
204 #endif
205 #endif
206 #ifdef MAC
207   struct listitem *litem=malloc(sizeof(struct listitem));
208   pthread_setspecific(litemkey, litem);
209   litem->prev=NULL;
210   litem->next=list;
211   if(list!=NULL)
212     list->prev=litem;
213   list=litem;
214 #else
215   //Add our litem to list of threads
216   litem.prev=NULL;
217   litem.next=list;
218   if(list!=NULL)
219     list->prev=&litem;
220   list=&litem;
221 #endif
222 }
223
224 #if defined(THREADS)||defined(STM)
225 void initthread(struct ___Thread___ * ___this___) {
226 #ifdef PRECISE_GC
227   INTPTR p[]={1, (INTPTR) NULL, (INTPTR) ___this___};
228   //Add our litem to list of threads
229 #ifdef MAC
230   struct listitem litem;
231   pthread_setspecific(litemkey, &litem);
232 #endif
233   litem.prev=NULL;
234   pthread_mutex_lock(&gclistlock);
235   litem.next=list;
236   if(list!=NULL)
237     list->prev=&litem;
238   list=&litem;
239   pthread_mutex_unlock(&gclistlock);
240   
241 #ifdef THREADS
242   ___Thread______staticStart____L___Thread___((struct ___Thread______staticStart____L___Thread____params *)p);
243 #else
244   newobjs=calloc(1, sizeof(struct objlist));
245 #ifdef STMSTATS
246   trec=calloc(1, sizeof(threadrec_t));
247   trec->blocked = 0;
248   lockedobjs=calloc(1, sizeof(struct objlist));
249 #endif
250   t_cache = objstrCreate(1048576);
251   t_reserve=NULL;
252   t_chashCreate(CHASH_SIZE, CLOADFACTOR);
253 #ifdef READSET
254   rd_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
255 #endif
256 #ifdef DELAYCOMP
257   dc_t_chashCreate(CHASH_SIZE, CLOADFACTOR);
258   ptrstack.count=0;
259   primstack.count=0;
260 #endif
261  ___Thread____NNR____staticStart____L___Thread___((struct ___Thread____NNR____staticStart____L___Thread____params *)p);
262  objstrDelete(t_cache);
263  objstrDelete(t_reserve);
264  t_chashDelete();
265  free(newobjs);
266 #ifdef STMSTATS
267  free(lockedobjs);
268 #endif
269 #endif
270   ___this___=(struct ___Thread___ *) p[2];
271 #else
272   ___Thread______staticStart____L___Thread___(___this___);
273 #endif
274   ___this___->___finished___=1;
275   pthread_mutex_lock(&joinlock);
276   pthread_cond_signal(&joincond);
277   pthread_mutex_unlock(&joinlock);
278
279   pthread_mutex_lock(&gclistlock);
280 #ifdef THREADS
281   pthread_setspecific(threadlocks, litem.locklist);
282 #endif
283   if (litem.prev==NULL) {
284     list=litem.next;
285   } else {
286     litem.prev->next=litem.next;
287   }
288   if (litem.next!=NULL) {
289     litem.next->prev=litem.prev;
290   }
291   threadcount--;
292   pthread_cond_signal(&gccond);
293   pthread_mutex_unlock(&gclistlock);
294 }
295 #endif
296
297 void CALL11(___Thread______sleep____J, long long ___millis___, long long ___millis___) {
298 #if defined(THREADS)||defined(STM)
299 #ifdef PRECISE_GC
300   stopforgc((struct garbagelist *)___params___);
301 #endif
302 #endif
303   usleep(___millis___);
304 #if defined(THREADS)||defined(STM)
305 #ifdef PRECISE_GC
306   restartaftergc();
307 #endif
308 #endif
309 }
310
311 #if defined(DSTM)|| defined(THREADS)||defined(STM)
312 void CALL00(___Thread______yield____) {
313   pthread_yield();
314 }
315 #endif
316
317 #ifdef DSTM
318 /* Add thread join capability */
319 void CALL01(___Thread______join____, struct ___Thread___ * ___this___) {
320   unsigned int *oidarray;
321   unsigned short *versionarray, version;
322   objheader_t *ptr;
323   /* Add transaction to check if thread finished for join operation */
324 transstart:
325   transStart();
326   ptr = transRead((unsigned int) VAR(___this___));
327   struct ___Thread___ *p = (struct ___Thread___ *) ptr;
328 #ifdef THREADJOINDEBUG
329   printf("Start join process for Oid = %x\n", (unsigned int) VAR(___this___));
330 #endif
331   if(p->___threadDone___ == 1) {
332 #ifdef THREADJOINDEBUG
333     printf("Thread oid = %x is done\n", (unsigned int) VAR(___this___));
334 #endif
335     transAbort();
336     return;
337   } else {
338
339     version = (ptr-1)->version;
340     if((oidarray = calloc(1, sizeof(unsigned int))) == NULL) {
341       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
342       return;
343     }
344
345     oidarray[0] = (unsigned int) VAR(___this___);
346
347     if((versionarray = calloc(1, sizeof(unsigned short))) == NULL) {
348       printf("Calloc error %s, %d\n", __FILE__, __LINE__);
349       free(oidarray);
350       return;
351     }
352     versionarray[0] = version;
353     /* Request Notification */
354 #ifdef PRECISE_GC
355     stopforgc((struct garbagelist *)___params___);
356 #endif
357     reqNotify(oidarray, versionarray, 1);
358 #ifdef PRECISE_GC
359     restartaftergc();
360 #endif
361     free(oidarray);
362     free(versionarray);
363     transAbort();
364     goto transstart;
365   }
366   return;
367 }
368 #endif
369
370 #if defined(THREADS)||defined(STM)
371 void CALL01(___Thread______nativeJoin____, struct ___Thread___ * ___this___) {
372   pthread_mutex_lock(&joinlock);
373   while(!VAR(___this___)->___finished___) {
374 #ifdef PRECISE_GC
375   stopforgc((struct garbagelist *)___params___);
376 #endif
377     pthread_cond_wait(&joincond, &joinlock);
378 #ifdef PRECISE_GC
379     restartaftergc();
380 #endif
381   }
382   pthread_mutex_unlock(&joinlock);
383 }
384
385 void CALL01(___Thread______nativeCreate____, struct ___Thread___ * ___this___) {
386   pthread_t thread;
387   int retval;
388   pthread_attr_t nattr;
389
390   pthread_mutex_lock(&gclistlock);
391   threadcount++;
392   pthread_mutex_unlock(&gclistlock);
393   pthread_attr_init(&nattr);
394   pthread_attr_setdetachstate(&nattr, PTHREAD_CREATE_DETACHED);
395   INTPTR stacksize;
396   pthread_attr_getstacksize(&nattr, &stacksize);
397   printf("STACKSIZE=%u\n",stacksize);
398   do {
399     retval=pthread_create(&thread, &nattr, (void * (*)(void *)) &initthread, VAR(___this___));
400     if (retval!=0)
401       usleep(1);
402   } while(retval!=0);
403   /* This next statement will likely not work on many machines */
404
405   pthread_attr_destroy(&nattr);
406 }
407 #endif
408
409 #ifdef DSTM
410 void CALL12(___Thread______start____I, int ___mid___, struct ___Thread___ * ___this___, int ___mid___) {
411   startRemoteThread((unsigned int)VAR(___this___), ___mid___);
412 }
413 #endif
414
415 #ifdef DSTM
416 void globalDestructor(void *value) {
417   free(value);
418   pthread_setspecific(oidval, NULL);
419 }
420
421 void initDSMthread(int *ptr) {
422   objheader_t *tmp;
423   void *threadData;
424   int oid=ptr[0];
425   int type=ptr[1];
426   free(ptr);
427 #ifdef PRECISE_GC
428   int p[]={1, 0 /* NULL */, oid};
429 #ifdef MAC
430   struct listitem litem;
431   pthread_setspecific(litemkey, &litem);
432 #endif
433
434   //Add our litem to list of threads
435   litem.prev=NULL;
436   pthread_mutex_lock(&gclistlock);
437   litem.next=list;
438   if(list!=NULL)
439     list->prev=&litem;
440   list=&litem;
441   pthread_mutex_unlock(&gclistlock);
442
443   ((void(*) (void *))virtualtable[type*MAXCOUNT+RUNMETHOD])(p);
444 #else
445   ((void(*) (void *))virtualtable[type*MAXCOUNT+RUNMETHOD])(oid);
446 #endif
447   threadData = calloc(1, sizeof(unsigned int));
448   *((unsigned int *) threadData) = oid;
449   pthread_setspecific(oidval, threadData);
450   pthread_mutex_lock(&gclistlock);
451
452 #ifdef THREADS
453   pthread_setspecific(threadlocks, litem.locklist);
454 #endif
455   if (litem.prev==NULL) {
456     list=litem.next;
457   } else {
458     litem.prev->next=litem.next;
459   }
460   if (litem.next!=NULL) {
461     litem.next->prev=litem.prev;
462   }
463   threadcount--;
464   pthread_cond_signal(&gccond);
465   pthread_mutex_unlock(&gclistlock);
466   /* Add transaction to check if thread finished for join operation */
467   goto transstart;
468 transstart:
469   {
470     transStart();
471     tmp  = transRead((unsigned int) oid);
472     ((struct ___Thread___ *)tmp)->___threadDone___ = 1;
473     *((unsigned int *)&((struct ___Object___ *) tmp)->___localcopy___) |=DIRTY;
474     if(transCommit()!= 0) {
475       goto transstart;
476     }
477   }
478   pthread_exit(NULL);
479 }
480
481 void startDSMthread(int oid, int objType) {
482   pthread_t thread;
483   int retval;
484   pthread_attr_t nattr;
485
486   pthread_mutex_lock(&gclistlock);
487   threadcount++;
488   pthread_mutex_unlock(&gclistlock);
489   pthread_attr_init(&nattr);
490   pthread_attr_setdetachstate(&nattr, PTHREAD_CREATE_DETACHED);
491   int * ptr=malloc(sizeof(int)*2);
492   ptr[0]=oid;
493   ptr[1]=objType;
494   pthread_key_create(&oidval, globalDestructor);
495   do {
496     retval=pthread_create(&thread, &nattr, (void * (*)(void *)) &initDSMthread,  ptr);
497     if (retval!=0)
498       usleep(1);
499   } while(retval!=0);
500
501   pthread_attr_destroy(&nattr);
502 }
503
504 #endif