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