Bug fix: save Converse handler so we don't use msg
[charm.git] / src / conv-core / convcore.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <errno.h>
12
13 #include "converse.h"
14 #include "conv-trace.h"
15 #include "sockRoutines.h"
16 #include "queueing.h"
17 #include "conv-ccs.h"
18 #include "ccs-server.h"
19 #include "memory-isomalloc.h"
20 #include "converseEvents.h"             /* projector */
21 #include "traceCoreCommon.h"    /* projector */
22 #include "machineEvents.h"     /* projector */
23
24 CpvExtern(int, _traceCoreOn);   /* projector */
25 extern void CcdModuleInit(char **);
26 extern void CmiMemoryInit(char **);
27 extern void CldModuleInit(void);
28
29 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #endif
33
34 #if CMK_TIMER_USE_TIMES
35 #include <sys/times.h>
36 #include <limits.h>
37 #include <unistd.h>
38 #endif
39
40 #if CMK_TIMER_USE_GETRUSAGE
41 #include <sys/time.h>
42 #include <sys/resource.h>
43 #endif
44
45 #if CMK_TIMER_USE_RDTSC
46 #include <string.h>
47 #include <unistd.h>
48 #include <time.h>
49 #include <stdio.h>
50 #include <sys/time.h>
51 #include <sys/resource.h>
52 #endif
53
54 #ifdef CMK_TIMER_USE_WIN32API
55 #include <stdlib.h>
56 #include <time.h>
57 #include <sys/types.h>
58 #include <sys/timeb.h>
59 #endif
60
61 #include "quiescence.h"
62
63 /*****************************************************************************
64  *
65  * Unix Stub Functions
66  *
67  ****************************************************************************/
68
69 #ifdef MEMMONITOR
70 typedef unsigned long mmulong;
71 CpvDeclare(mmulong,MemoryUsage);
72 CpvDeclare(mmulong,HiWaterMark);
73 CpvDeclare(mmulong,ReportedHiWaterMark);
74 CpvDeclare(int,AllocCount);
75 CpvDeclare(int,BlocksAllocated);
76 #endif
77
78 #define MAX_HANDLERS 512
79
80 #if CMK_NODE_QUEUE_AVAILABLE
81 void  *CmiGetNonLocalNodeQ();
82 #endif
83
84 CpvDeclare(void*, CsdSchedQueue);
85 #if CMK_NODE_QUEUE_AVAILABLE
86 CsvDeclare(void*, CsdNodeQueue);
87 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
88 #endif
89 CpvDeclare(int,   CsdStopFlag);
90
91 /*****************************************************************************
92  *
93  * Command-Line Argument (CLA) parsing routines.
94  *
95  *****************************************************************************/
96
97 static int usageChecked=0; /* set when argv has been searched for a usage request */
98 static int printUsage=0; /* if set, print command-line usage information */
99 static const char *CLAformatString="%20s %10s %s\n";
100
101 /* This little list of CLA's holds the argument descriptions until it's
102    safe to print them--it's needed because the net- versions don't have 
103    printf until they're pretty well started.
104  */
105 typedef struct {
106         const char *arg; /* Flag name, like "-foo"*/
107         const char *param; /* Argument's parameter type, like "integer" or "none"*/
108         const char *desc; /* Human-readable description of what it does */
109 } CLA;
110 static int CLAlistLen=0;
111 static int CLAlistMax=0;
112 static CLA *CLAlist=NULL;
113
114 /* Add this CLA */
115 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
116         int i;
117         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
118         if (desc==NULL) return; /*It's an internal argument*/
119         if (usageChecked) { /* Printf should work now */
120                 if (printUsage)
121                         CmiPrintf(CLAformatString,arg,param,desc);
122         }
123         else { /* Printf doesn't work yet-- just add to the list.
124                 This assumes the const char *'s are static references,
125                 which is probably reasonable. */
126                 i=CLAlistLen++;
127                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
128                         CLAlistMax=16+2*CLAlistLen;
129                         CLAlist=realloc(CLAlist,sizeof(CLA)*CLAlistMax);\
130                 }
131                 CLAlist[i].arg=arg;
132                 CLAlist[i].param=param;
133                 CLAlist[i].desc=desc;
134         }
135 }
136
137 /* Print out the stored list of CLA's */
138 static void CmiPrintCLAs(void) {
139         int i;
140         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
141         CmiPrintf("Converse Machine Command-line Parameters:\n ");
142         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
143         for (i=0;i<CLAlistLen;i++) {
144                 CLA *c=&CLAlist[i];
145                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
146         }
147 }
148
149 /**
150  * Determines if command-line usage information should be printed--
151  * that is, if a "-?", "-h", or "--help" flag is present.
152  * Must be called after printf is setup.
153  */
154 void CmiArgInit(char **argv) {
155         int i;
156         for (i=0;argv[i]!=NULL;i++)
157         {
158                 if (0==strcmp(argv[i],"-?") ||
159                     0==strcmp(argv[i],"-h") ||
160                     0==strcmp(argv[i],"--help")) 
161                 {
162                         printUsage=1;
163                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
164                           Leave it there for user program to see... */
165                         CmiPrintCLAs();
166                 }
167         }
168         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
169                 CLAlistLen=CLAlistMax=0;
170                 free(CLAlist); CLAlist=NULL;
171         }
172         usageChecked=1;
173 }
174
175 /* Return 1 if we're currently printing command-line usage information. */
176 int CmiArgGivingUsage(void) {
177         return (CmiMyPe()==0) && printUsage;
178 }
179
180 /* Identifies the module that accepts the following command-line parameters */
181 void CmiArgGroup(const char *parentName,const char *groupName) {
182         if (CmiArgGivingUsage()) {
183                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
184                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
185         }
186 }
187
188 /*Count the number of non-NULL arguments in list*/
189 int CmiGetArgc(char **argv)
190 {
191         int i=0,argc=0;
192         while (argv[i++]!=NULL)
193                 argc++;
194         return argc;
195 }
196
197 /*Return a new, heap-allocated copy of the argv array*/
198 char **CmiCopyArgs(char **argv)
199 {
200         int argc=CmiGetArgc(argv);
201         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
202         int i;
203         for (i=0;i<=argc;i++)
204                 ret[i]=argv[i];
205         return ret;
206 }
207
208 /*Delete the first k argument from the given list, shifting
209 all other arguments down by k spaces.
210 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
211 argv={"d",NULL,"c","d",NULL}
212 */
213 void CmiDeleteArgs(char **argv,int k)
214 {
215         int i=0;
216         while ((argv[i]=argv[i+k])!=NULL)
217                 i++;
218 }
219
220 /*Find the given argment and string option in argv.
221 If the argument is present, set the string option and
222 delete both from argv.  If not present, return NULL.
223 e.g., arg=="-name" returns "bob" from
224 argv=={"a.out","foo","-name","bob","bar"},
225 and sets argv={"a.out","foo","bar"};
226 */
227 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
228 {
229         int i;
230         CmiAddCLA(arg,"string",desc);
231         for (i=0;argv[i]!=NULL;i++)
232                 if (0==strcmp(argv[i],arg))
233                 {/*We found the argument*/
234                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
235                         *optDest=argv[i+1];
236                         CmiDeleteArgs(&argv[i],2);
237                         return 1;
238                 }
239         return 0;/*Didn't find the argument*/
240 }
241 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
242         return CmiGetArgStringDesc(argv,arg,optDest,"");
243 }
244
245 /*Find the given argument and floating-point option in argv.
246 Remove it and return 1; or return 0.
247 */
248 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
249         char *number=NULL;
250         CmiAddCLA(arg,"number",desc);
251         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
252         if (1!=sscanf(number,"%lg",optDest)) return 0;
253         return 1;
254 }
255 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
256         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
257 }
258
259 /*Find the given argument and integer option in argv.
260 If the argument is present, parse and set the numeric option,
261 delete both from argv, and return 1. If not present, return 0.
262 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
263 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
264 but not argv=={...,"-packsize",...}.
265 */
266 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
267 {
268         int i;
269         int argLen=strlen(arg);
270         CmiAddCLA(arg,"integer",desc);
271         for (i=0;argv[i]!=NULL;i++)
272                 if (0==strncmp(argv[i],arg,argLen))
273                 {/*We *may* have found the argument*/
274                         const char *opt=NULL;
275                         int nDel=0;
276                         switch(argv[i][argLen]) {
277                         case 0: /* like "-p","27" */
278                                 opt=argv[i+1]; nDel=2; break;
279                         case '=': /* like "-p=27" */
280                                 opt=&argv[i][argLen+1]; nDel=1; break;
281                         case '-':case '+':
282                         case '0':case '1':case '2':case '3':case '4':
283                         case '5':case '6':case '7':case '8':case '9':
284                                 /* like "-p27" */
285                                 opt=&argv[i][argLen]; nDel=1; break;
286                         default:
287                                 continue; /*False alarm-- skip it*/
288                         }
289                         if (opt==NULL) continue; /*False alarm*/
290                         if (sscanf(opt,"%i",optDest)<1) {
291                         /*Bad command line argument-- die*/
292                                 fprintf(stderr,"Cannot parse %s option '%s' "
293                                         "as an integer.\n",arg,opt);
294                                 CmiAbort("Bad command-line argument\n");
295                         }
296                         CmiDeleteArgs(&argv[i],nDel);
297                         return 1;
298                 }
299         return 0;/*Didn't find the argument-- dest is unchanged*/       
300 }
301 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
302         return CmiGetArgIntDesc(argv,arg,optDest,"");
303 }
304
305 /*Find the given argument in argv.  If present, delete
306 it and return 1; if not present, return 0.
307 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
308 argv={...,"-foobar",...}.
309 */
310 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
311 {
312         int i;
313         CmiAddCLA(arg,"",desc);
314         for (i=0;argv[i]!=NULL;i++)
315                 if (0==strcmp(argv[i],arg))
316                 {/*We found the argument*/
317                         CmiDeleteArgs(&argv[i],1);
318                         return 1;
319                 }
320         return 0;/*Didn't find the argument*/
321 }
322 int CmiGetArgFlag(char **argv,const char *arg) {
323         return CmiGetArgFlagDesc(argv,arg,"");
324 }
325
326
327 /*****************************************************************************
328  *
329  * Stack tracing routines.
330  *
331  *****************************************************************************/
332 #include "cmibacktrace.c"
333
334 /*
335 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
336 the next parenthesis.  Operates in-place on the character data.
337 */
338 static char *_implTrimParenthesis(char *str) {
339   char *lParen=str, *ret=NULL, *rParen=NULL;
340   while (*lParen!='(') {
341     if (*lParen==0) return str; /* No left parenthesis at all. */
342     lParen++;
343   }
344   /* now *lParen=='(', so trim it*/
345   ret=lParen+1;
346   rParen=ret;
347   while (*rParen!=')') {
348     if (*rParen==0) return ret; /* No right parenthesis at all. */
349     rParen++;
350   }
351   /* now *rParen==')', so trim it*/
352   *rParen=' ';
353   return ret;  
354 }
355
356 /*
357 Return the text description of this trimmed routine name, if 
358 it's a system-generated routine where we should stop printing. 
359 This is probably overkill, but improves the appearance of callbacks.
360 */
361 static const char* _implGetBacktraceSys(const char *name) {
362   if (0==strncmp(name,"_call",5)) 
363   { /*it might be something we're interested in*/
364     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
365     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
366   }
367   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
368   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
369   
370   return 0; /*ordinary user routine-- just print normally*/
371 }
372
373 void CmiPrintStackTrace(int nSkip) {
374 #if CMK_USE_BACKTRACE
375   int i,max=0;
376   char **names=CmiBacktrace(&max);
377   nSkip+=2; /*Since "CmiPrintStackTrace" and "CmiBacktrace" will be in list.*/
378   if (max>nSkip) {
379     CmiPrintf("Stack Traceback:\n");
380     for (i=nSkip;i<max;i++) {
381       const char *trimmed=_implTrimParenthesis(names[i]);
382       const char *print=trimmed;
383       const char *sys=_implGetBacktraceSys(print);
384       if (sys) {
385           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i-nSkip,sys,print);
386           break; /*Stop when we hit Charm++ runtime.*/
387       } else {
388           CmiPrintf("  [%d] %s\n",i-nSkip,print);
389       }
390     }
391   }
392   free(names);
393 #endif
394 }
395
396
397 /*****************************************************************************
398  *
399  * Statistics: currently, the following statistics are not updated by converse.
400  *
401  *****************************************************************************/
402
403 CpvDeclare(int, CstatsMaxChareQueueLength);
404 CpvDeclare(int, CstatsMaxForChareQueueLength);
405 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
406 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
407 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
408
409 void CstatsInit(argv)
410 char **argv;
411 {
412
413 #ifdef MEMMONITOR
414   CpvInitialize(mmulong,MemoryUsage);
415   CpvAccess(MemoryUsage) = 0;
416   CpvInitialize(mmulong,HiWaterMark);
417   CpvAccess(HiWaterMark) = 0;
418   CpvInitialize(mmulong,ReportedHiWaterMark);
419   CpvAccess(ReportedHiWaterMark) = 0;
420   CpvInitialize(int,AllocCount);
421   CpvAccess(AllocCount) = 0;
422   CpvInitialize(int,BlocksAllocated);
423   CpvAccess(BlocksAllocated) = 0;
424 #endif
425
426   CpvInitialize(int, CstatsMaxChareQueueLength);
427   CpvInitialize(int, CstatsMaxForChareQueueLength);
428   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
429   CpvInitialize(int, CstatPrintQueueStatsFlag);
430   CpvInitialize(int, CstatPrintMemStatsFlag);
431
432   CpvAccess(CstatsMaxChareQueueLength) = 0;
433   CpvAccess(CstatsMaxForChareQueueLength) = 0;
434   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
435   CpvAccess(CstatPrintQueueStatsFlag) = 0;
436   CpvAccess(CstatPrintMemStatsFlag) = 0;
437
438 #if 0
439   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
440     CpvAccess(CstatPrintMemStatsFlag)=1;
441   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
442     CpvAccess(CstatPrintQueueStatsFlag)=1;
443 #endif
444 }
445
446 int CstatMemory(i)
447 int i;
448 {
449   return 0;
450 }
451
452 int CstatPrintQueueStats()
453 {
454   return CpvAccess(CstatPrintQueueStatsFlag);
455 }
456
457 int CstatPrintMemStats()
458 {
459   return CpvAccess(CstatPrintMemStatsFlag);
460 }
461
462 /*****************************************************************************
463  *
464  * Cmi handler registration
465  *
466  *****************************************************************************/
467
468 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
469 CpvStaticDeclare(int  , CmiHandlerCount);
470 CpvStaticDeclare(int  , CmiHandlerLocal);
471 CpvStaticDeclare(int  , CmiHandlerGlobal);
472 CpvDeclare(int,         CmiHandlerMax);
473
474 static void CmiExtendHandlerTable(int atLeastLen) {
475     int max = CpvAccess(CmiHandlerMax);
476     int newmax = (atLeastLen+(atLeastLen>>2)+32);
477     int bytes = max*sizeof(CmiHandlerInfo);
478     int newbytes = newmax*sizeof(CmiHandlerInfo);
479     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
480     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
481     _MEMCHECK(nu);
482     memcpy(nu, tab, bytes);
483     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
484     free(tab); tab=nu;
485     CpvAccess(CmiHandlerTable) = tab;
486     CpvAccess(CmiHandlerMax) = newmax;
487 }
488
489 void CmiNumberHandler(int n, CmiHandler h)
490 {
491   CmiHandlerInfo *tab;
492   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
493   tab = CpvAccess(CmiHandlerTable);
494   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
495   tab[n].userPtr = 0;
496 }
497 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
498   CmiHandlerInfo *tab;
499   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
500   tab = CpvAccess(CmiHandlerTable);
501   tab[n].hdlr = h;
502   tab[n].userPtr=userPtr;
503 }
504
505 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
506 #  define DIST_BETWEEN_HANDLERS 3
507 #else /*No local or global handlers; ordinary handlers are back-to-back*/
508 #  define DIST_BETWEEN_HANDLERS 1
509 #endif
510
511 int CmiRegisterHandler(CmiHandler h)
512 {
513   int Count = CpvAccess(CmiHandlerCount);
514   CmiNumberHandler(Count, h);
515   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
516   return Count;
517 }
518 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
519 {
520   int Count = CpvAccess(CmiHandlerCount);
521   CmiNumberHandlerEx(Count, h, userPtr);
522   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
523   return Count;
524 }
525
526
527 #if CMI_LOCAL_GLOBAL_AVAILABLE
528 int CmiRegisterHandlerLocal(h)
529 CmiHandler h;
530 {
531   int Local = CpvAccess(CmiHandlerLocal);
532   CmiNumberHandler(Local, h);
533   CpvAccess(CmiHandlerLocal) = Local+3;
534   return Local;
535 }
536
537 int CmiRegisterHandlerGlobal(h)
538 CmiHandler h;
539 {
540   int Global = CpvAccess(CmiHandlerGlobal);
541   if (CmiMyPe()!=0) 
542     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
543   CmiNumberHandler(Global, h);
544   CpvAccess(CmiHandlerGlobal) = Global+3;
545   return Global;
546 }
547 #endif
548
549 static void CmiHandlerInit()
550 {
551   CpvInitialize(CmiHandler *, CmiHandlerTable);
552   CpvInitialize(int         , CmiHandlerCount);
553   CpvInitialize(int         , CmiHandlerLocal);
554   CpvInitialize(int         , CmiHandlerGlobal);
555   CpvInitialize(int         , CmiHandlerMax);
556   CpvAccess(CmiHandlerCount)  = 0;
557   CpvAccess(CmiHandlerLocal)  = 1;
558   CpvAccess(CmiHandlerGlobal) = 2;
559   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
560   CpvAccess(CmiHandlerTable) = NULL;
561 }
562
563
564 /******************************************************************************
565  *
566  * CmiTimer
567  *
568  * Here are two possible implementations of CmiTimer.  Some machines don't
569  * select either, and define the timer in machine.c instead.
570  *
571  *****************************************************************************/
572
573 #if CMK_TIMER_USE_TIMES
574
575 CpvStaticDeclare(double, clocktick);
576 CpvStaticDeclare(int,inittime_wallclock);
577 CpvStaticDeclare(int,inittime_virtual);
578
579 void CmiTimerInit()
580 {
581   struct tms temp;
582   CpvInitialize(double, clocktick);
583   CpvInitialize(int, inittime_wallclock);
584   CpvInitialize(int, inittime_virtual);
585   CpvAccess(inittime_wallclock) = times(&temp);
586   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
587   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
588 }
589
590 double CmiWallTimer()
591 {
592   struct tms temp;
593   double currenttime;
594   int now;
595
596   now = times(&temp);
597   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
598   return (currenttime);
599 }
600
601 double CmiCpuTimer()
602 {
603   struct tms temp;
604   double currenttime;
605   int now;
606
607   times(&temp);
608   now = temp.tms_stime + temp.tms_utime;
609   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
610   return (currenttime);
611 }
612
613 double CmiTimer()
614 {
615   return CmiCpuTimer();
616 }
617
618 #endif
619
620 #if CMK_TIMER_USE_GETRUSAGE
621
622 static double inittime_wallclock;
623 CpvStaticDeclare(double, inittime_virtual);
624
625 void CmiTimerInit()
626 {
627   struct timeval tv;
628   struct rusage ru;
629   CpvInitialize(double, inittime_virtual);
630   gettimeofday(&tv,0);
631   inittime_wallclock = (tv.tv_sec * 1.0) + (tv.tv_usec*0.000001);
632   getrusage(0, &ru); 
633   CpvAccess(inittime_virtual) =
634     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
635     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
636 }
637
638 double CmiCpuTimer()
639 {
640   struct rusage ru;
641   double currenttime;
642
643   getrusage(0, &ru);
644   currenttime =
645     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
646     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
647   return currenttime - CpvAccess(inittime_virtual);
648 }
649
650 double CmiWallTimer()
651 {
652   struct timeval tv;
653   double currenttime;
654
655   gettimeofday(&tv,0);
656   currenttime = (tv.tv_sec * 1.0) + (tv.tv_usec * 0.000001);
657   return currenttime - inittime_wallclock;
658 }
659
660 double CmiTimer()
661 {
662   return CmiCpuTimer();
663 }
664
665 #endif
666
667 #if CMK_TIMER_USE_RDTSC
668
669 static double readMHz(void)
670 {
671   double x;
672   char str[1000];
673   char buf[100];
674   FILE *fp = fopen("/proc/cpuinfo", "r");
675   while(fgets(str, 1000, fp)!=0) {
676     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
677     {
678       char *s = strchr(str, ':'); s=s+1;
679       sscanf(s, "%lf", &x);
680       fclose(fp);
681       return x;
682     }
683   }
684   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
685   return 0.0;
686 }
687
688 double cpu_speed_factor;
689 CpvStaticDeclare(double, inittime_virtual);
690
691 void CmiTimerInit()
692 {
693   struct rusage ru;
694   cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
695   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
696   CpvInitialize(double, inittime_virtual);
697   getrusage(0, &ru); 
698   CpvAccess(inittime_virtual) =
699     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
700     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
701 }
702
703 double CmiCpuTimer()
704 {
705   struct rusage ru;
706   double currenttime;
707
708   getrusage(0, &ru);
709   currenttime =
710     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
711     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
712   return currenttime - CpvAccess(inittime_virtual);
713 }
714
715 #endif
716
717 #if CMK_TIMER_USE_WIN32API
718
719 CpvStaticDeclare(double, inittime_wallclock);
720 CpvStaticDeclare(double, inittime_virtual);
721
722 void CmiTimerInit()
723 {
724 #ifdef __CYGWIN__
725         struct timeb tv;
726 #else
727         struct _timeb tv;
728 #endif
729         clock_t       ru;
730
731         CpvInitialize(double, inittime_wallclock);
732         CpvInitialize(double, inittime_virtual);
733         _ftime(&tv);
734         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
735         ru = clock();
736         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
737 }
738
739 double CmiCpuTimer()
740 {
741         clock_t ru;
742         double currenttime;
743
744         ru = clock();
745         currenttime = (double) ru/CLOCKS_PER_SEC;
746
747         return currenttime - CpvAccess(inittime_virtual);
748 }
749
750 double CmiWallTimer()
751 {
752 #ifdef __CYGWIN__
753         struct timeb tv;
754 #else
755         struct _timeb tv;
756 #endif
757         double currenttime;
758
759         _ftime(&tv);
760         currenttime = tv.time*1.0 + tv.millitm*0.001;
761
762         return currenttime - CpvAccess(inittime_wallclock);
763 }
764         
765
766 double CmiTimer()
767 {
768         return CmiCpuTimer();
769 }
770
771 #endif
772
773 #if CMK_SIGNAL_USE_SIGACTION
774 #include <signal.h>
775 void CmiSignal(sig1, sig2, sig3, handler)
776 int sig1, sig2, sig3;
777 void (*handler)();
778 {
779   struct sigaction in, out ;
780   in.sa_handler = handler;
781   sigemptyset(&in.sa_mask);
782   if (sig1) sigaddset(&in.sa_mask, sig1);
783   if (sig2) sigaddset(&in.sa_mask, sig2);
784   if (sig3) sigaddset(&in.sa_mask, sig3);
785   in.sa_flags = 0;
786   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
787   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
788   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
789 }
790 #endif
791
792 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
793 #include <signal.h>
794 void CmiSignal(sig1, sig2, sig3, handler)
795 int sig1, sig2, sig3;
796 void (*handler)();
797 {
798   struct sigaction in, out ;
799   in.sa_handler = handler;
800   sigemptyset(&in.sa_mask);
801   if (sig1) sigaddset(&in.sa_mask, sig1);
802   if (sig2) sigaddset(&in.sa_mask, sig2);
803   if (sig3) sigaddset(&in.sa_mask, sig3);
804   in.sa_flags = SA_RESTART;
805   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
806   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
807   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
808 }
809 #endif
810
811 /*****************************************************************************
812  *
813  * The following is the CsdScheduler function.  A common
814  * implementation is provided below.  The machine layer can provide an
815  * alternate implementation if it so desires.
816  *
817  * void CmiDeliversInit()
818  *
819  *      - CmiInit promises to call this before calling CmiDeliverMsgs
820  *        or any of the other functions in this section.
821  *
822  * int CmiDeliverMsgs(int maxmsgs)
823  *
824  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
825  *        with the Cmi, and will invoke their handlers.  It does not wait
826  *        if no message is unavailable.  Instead, it returns the quantity
827  *        (maxmsgs-delivered), where delivered is the number of messages it
828  *        delivered.
829  *
830  * void CmiDeliverSpecificMsg(int handlerno)
831  *
832  *      - Waits for a message with the specified handler to show up, then
833  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
834  *        This function _does_ wait.
835  *
836  * For this common implementation to work, the machine layer must provide the
837  * following:
838  *
839  * void *CmiGetNonLocal()
840  *
841  *      - returns a message just retrieved from some other PE, not from
842  *        local.  If no such message exists, returns 0.
843  *
844  * CpvExtern(CdsFifo, CmiLocalQueue);
845  *
846  *      - a FIFO queue containing all messages from the local processor.
847  *
848  *****************************************************************************/
849
850 void CsdBeginIdle(void)
851 {
852   CcdCallBacks();
853 #ifndef CMK_OPTIMIZE
854   _LOG_E_PROC_IDLE();   /* projector */
855 #endif
856   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
857 }
858
859 void CsdStillIdle(void)
860 {
861   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
862 }
863
864 void CsdEndIdle(void)
865 {
866 #ifndef CMK_OPTIMIZE    
867   _LOG_E_PROC_BUSY();   /* projector */
868 #endif
869   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
870 }
871
872 void CmiHandleMessage(void *msg)
873 {
874 /* this is wrong because it counts the Charm++ messages in sched queue
875         CpvAccess(cQdState)->mProcessed++;
876 */
877          CmiHandlerInfo *h;
878 #ifndef CMK_OPTIMIZE
879         int handler=CmiGetHandler(msg); /* Save handler for use after msg is gone */
880         _LOG_E_HANDLER_BEGIN(handler); /* projector */
881 #endif
882         h=&CmiGetHandlerInfo(msg);
883         (h->hdlr)(msg,h->userPtr);
884 #ifndef CMK_OPTIMIZE
885         _LOG_E_HANDLER_END(handler);    /* projector */
886 #endif
887 }
888
889 #if CMK_CMIDELIVERS_USE_COMMON_CODE
890
891 void CmiDeliversInit()
892 {
893 }
894
895 int CmiDeliverMsgs(int maxmsgs)
896 {
897   return CsdScheduler(maxmsgs);
898 }
899
900 void CsdSchedulerState_new(CsdSchedulerState_t *s)
901 {
902         s->localQ=CpvAccess(CmiLocalQueue);
903         s->schedQ=CpvAccess(CsdSchedQueue);
904 #if CMK_NODE_QUEUE_AVAILABLE
905         s->nodeQ=CsvAccess(CsdNodeQueue);
906         s->nodeLock=CsvAccess(CsdNodeQueueLock);
907 #endif
908 }
909
910 void *CsdNextMessage(CsdSchedulerState_t *s) {
911         void *msg;
912         if (NULL!=(msg=CmiGetNonLocal()) ||
913             NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
914           CpvAccess(cQdState)->mProcessed++;
915           return msg;
916         }
917 #if CMK_NODE_QUEUE_AVAILABLE
918         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
919         if (!CqsEmpty(s->nodeQ)
920          && !CqsPrioGT(CqsGetPriority(s->nodeQ),
921                        CqsGetPriority(s->schedQ))) {
922           CmiLock(s->nodeLock);
923           CqsDequeue(s->nodeQ,(void **)&msg);
924           CmiUnlock(s->nodeLock);
925           if (msg!=NULL) return msg;
926         }
927 #endif
928         CqsDequeue(s->schedQ,(void **)&msg);
929         if (msg!=NULL) return msg;
930         return NULL;
931 }
932
933 int CsdScheduler(int maxmsgs)
934 {
935         if (maxmsgs<0) CsdScheduleForever();    
936         else if (maxmsgs==0)
937                 CsdSchedulePoll();
938         else /*(maxmsgs>0)*/ 
939                 return CsdScheduleCount(maxmsgs);
940         return 0;
941 }
942
943 /*Declare the standard scheduler housekeeping*/
944 #define SCHEDULE_TOP \
945       void *msg;\
946       int cycle = CpvAccess(CsdStopFlag); \
947       CsdSchedulerState_t state;\
948       CsdSchedulerState_new(&state);\
949
950 /*A message is available-- process it*/
951 #define SCHEDULE_MESSAGE \
952       CmiHandleMessage(msg);\
953       if (CpvAccess(CsdStopFlag) != cycle) break;\
954
955 /*No message available-- go (or remain) idle*/
956 #define SCHEDULE_IDLE \
957       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
958       else CsdStillIdle();\
959       if (CpvAccess(CsdStopFlag) != cycle) {\
960         CsdEndIdle();\
961         break;\
962       }\
963
964 void CsdScheduleForever(void)
965 {
966   int isIdle=0;
967   SCHEDULE_TOP
968   while (1) {
969     msg = CsdNextMessage(&state);
970     if (msg) { /*A message is available-- process it*/
971       if (isIdle) {isIdle=0;CsdEndIdle();}
972       SCHEDULE_MESSAGE
973     } else { /*No message available-- go (or remain) idle*/
974       SCHEDULE_IDLE
975     }
976     CsdPeriodic();
977   }
978 }
979 int CsdScheduleCount(int maxmsgs)
980 {
981   int isIdle=0;
982   SCHEDULE_TOP
983   while (1) {
984     msg = CsdNextMessage(&state);
985     if (msg) { /*A message is available-- process it*/
986       if (isIdle) {isIdle=0;CsdEndIdle();}
987       maxmsgs--; 
988       SCHEDULE_MESSAGE
989       if (maxmsgs==0) break;
990     } else { /*No message available-- go (or remain) idle*/
991       SCHEDULE_IDLE
992     }
993     CsdPeriodic();
994   }
995   return maxmsgs;
996 }
997
998 void CsdSchedulePoll(void)
999 {
1000   SCHEDULE_TOP
1001   while (1)
1002   {
1003         CsdPeriodic();
1004         if (NULL!=(msg = CsdNextMessage(&state)))
1005         {
1006              SCHEDULE_MESSAGE 
1007         }
1008         else break;
1009   }
1010 }
1011
1012 void CmiDeliverSpecificMsg(handler)
1013 int handler;
1014 {
1015   int *msg; int side;
1016   void *localqueue = CpvAccess(CmiLocalQueue);
1017  
1018   side = 0;
1019   while (1) {
1020     side ^= 1;
1021     if (side) msg = CmiGetNonLocal();
1022     else      msg = CdsFifo_Dequeue(localqueue);
1023     if (msg) {
1024       if (CmiGetHandler(msg)==handler) {
1025         CpvAccess(cQdState)->mProcessed++;
1026         CmiHandleMessage(msg);
1027         return;
1028       } else {
1029         CdsFifo_Enqueue(localqueue, msg);
1030       }
1031     }
1032     CsdPeriodic();
1033   }
1034 }
1035  
1036 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1037
1038 /***************************************************************************
1039  *
1040  * Standin Schedulers.
1041  *
1042  * We use the following strategy to make sure somebody's always running
1043  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1044  * is responsible for this.  If the main thread blocks, we create a
1045  * "standin scheduler" thread to replace it.  If the standin scheduler
1046  * blocks, we create another standin scheduler to replace that one,
1047  * ad infinitum.  Collectively, the main thread and all the standin
1048  * schedulers are called "scheduling threads".
1049  *
1050  * Suppose the main thread is blocked waiting for data, and a standin
1051  * scheduler is running instead.  Suppose, then, that the data shows
1052  * up and the main thread is CthAwakened.  This causes a token to be
1053  * pushed into the queue.  When the standin pulls the token from the
1054  * queue and handles it, the standin goes to sleep, and control shifts
1055  * back to the main thread.  In this way, unnecessary standins are put
1056  * back to sleep.  These sleeping standins are stored on the
1057  * CthSleepingStandins list.
1058  *
1059  ***************************************************************************/
1060
1061 CpvStaticDeclare(CthThread, CthMainThread);
1062 CpvStaticDeclare(CthThread, CthSchedulingThread);
1063 CpvStaticDeclare(CthThread, CthSleepingStandins);
1064 CpvStaticDeclare(int      , CthResumeNormalThreadIdx);
1065 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1066
1067
1068 void CthStandinCode()
1069 {
1070   while (1) CsdScheduler(0);
1071 }
1072
1073 CthThread CthSuspendNormalThread()
1074 {
1075   return CpvAccess(CthSchedulingThread);
1076 }
1077
1078 void CthEnqueueSchedulingThread(CthThread t, int, int, unsigned int*);
1079 CthThread CthSuspendSchedulingThread();
1080
1081 CthThread CthSuspendSchedulingThread()
1082 {
1083   CthThread succ = CpvAccess(CthSleepingStandins);
1084
1085   if (succ) {
1086     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
1087   } else {
1088     succ = CthCreate(CthStandinCode, 0, 256000);
1089     CthSetStrategy(succ,
1090                    CthEnqueueSchedulingThread,
1091                    CthSuspendSchedulingThread);
1092   }
1093   
1094   CpvAccess(CthSchedulingThread) = succ;
1095   return succ;
1096 }
1097
1098 void CthResumeNormalThread(CthThread t)
1099 {
1100 #ifndef CMK_OPTIMIZE
1101   if(CpvAccess(traceOn))
1102     CthTraceResume(t);
1103 /*    if(CpvAccess(_traceCoreOn)) 
1104                 resumeTraceCore();*/
1105 #endif
1106     
1107   CthResume(t);
1108 }
1109
1110 void CthResumeSchedulingThread(CthThread t)
1111 {
1112   CthThread me = CthSelf();
1113   if (me == CpvAccess(CthMainThread)) {
1114     CthEnqueueSchedulingThread(me,CQS_QUEUEING_FIFO, 0, 0);
1115   } else {
1116     CthSetNext(me, CpvAccess(CthSleepingStandins));
1117     CpvAccess(CthSleepingStandins) = me;
1118   }
1119   CpvAccess(CthSchedulingThread) = t;
1120   CthResume(t);
1121 }
1122
1123 void CthEnqueueNormalThread(CthThread t, int s, 
1124                                    int pb,unsigned int *prio)
1125 {
1126   CmiSetHandler(t, CpvAccess(CthResumeNormalThreadIdx));
1127   CsdEnqueueGeneral(t, s, pb, prio);
1128 }
1129
1130 void CthEnqueueSchedulingThread(CthThread t, int s, 
1131                                        int pb,unsigned int *prio)
1132 {
1133   CmiSetHandler(t, CpvAccess(CthResumeSchedulingThreadIdx));
1134   CsdEnqueueGeneral(t, s, pb, prio);
1135 }
1136
1137 void CthSetStrategyDefault(CthThread t)
1138 {
1139   CthSetStrategy(t,
1140                  CthEnqueueNormalThread,
1141                  CthSuspendNormalThread);
1142 }
1143
1144 void CthSchedInit()
1145 {
1146   CpvInitialize(CthThread, CthMainThread);
1147   CpvInitialize(CthThread, CthSchedulingThread);
1148   CpvInitialize(CthThread, CthSleepingStandins);
1149   CpvInitialize(int      , CthResumeNormalThreadIdx);
1150   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
1151
1152   CpvAccess(CthMainThread) = CthSelf();
1153   CpvAccess(CthSchedulingThread) = CthSelf();
1154   CpvAccess(CthSleepingStandins) = 0;
1155   CpvAccess(CthResumeNormalThreadIdx) =
1156     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
1157   CpvAccess(CthResumeSchedulingThreadIdx) =
1158     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
1159   CthSetStrategy(CthSelf(),
1160                  CthEnqueueSchedulingThread,
1161                  CthSuspendSchedulingThread);
1162 }
1163
1164 void CsdInit(argv)
1165   char **argv;
1166 {
1167   CpvInitialize(void *, CsdSchedQueue);
1168   CpvInitialize(int,   CsdStopFlag);
1169   
1170   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
1171
1172 #if CMK_NODE_QUEUE_AVAILABLE
1173   CsvInitialize(CmiLock, CsdNodeQueueLock);
1174   CsvInitialize(void *, CsdNodeQueue);
1175   if (CmiMyRank() ==0) {
1176         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
1177         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
1178   }
1179   CmiNodeBarrier();
1180 #endif
1181
1182   CpvAccess(CsdStopFlag)  = 0;
1183 }
1184
1185
1186 /*****************************************************************************
1187  *
1188  * Vector Send
1189  *
1190  ****************************************************************************/
1191
1192 #if CMK_VECTOR_SEND_USES_COMMON_CODE
1193
1194 void CmiSyncVectorSend(destPE, n, sizes, msgs)
1195 int destPE, n;
1196 int *sizes;
1197 char **msgs;
1198 {
1199   int i, total;
1200   char *mesg, *tmp;
1201   
1202   for(i=0,total=0;i<n;i++) total += sizes[i];
1203   mesg = (char *) CmiAlloc(total);
1204   for(i=0,tmp=mesg;i<n;i++) {
1205     memcpy(tmp, msgs[i],sizes[i]);
1206     tmp += sizes[i];
1207   }
1208   CmiSyncSendAndFree(destPE, total, mesg);
1209 }
1210
1211 CmiCommHandle CmiAsyncVectorSend(destPE, n, sizes, msgs)
1212 int destPE, n;
1213 int *sizes;
1214 char **msgs;
1215 {
1216   CmiSyncVectorSend(destPE,n,sizes,msgs);
1217   return NULL;
1218 }
1219
1220 void CmiSyncVectorSendAndFree(destPE, n, sizes, msgs)
1221 int destPE, n;
1222 int *sizes;
1223 char **msgs;
1224 {
1225   int i;
1226
1227   CmiSyncVectorSend(destPE,n,sizes,msgs);
1228   for(i=0;i<n;i++) CmiFree(msgs[i]);
1229   CmiFree(sizes);
1230   CmiFree(msgs);
1231 }
1232
1233 #endif
1234
1235 /*****************************************************************************
1236  *
1237  * Multicast groups
1238  *
1239  ****************************************************************************/
1240
1241 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
1242
1243 typedef struct GroupDef
1244 {
1245   union {
1246     char core[CmiMsgHeaderSizeBytes];
1247     struct GroupDef *next;
1248   } core;
1249   CmiGroup group;
1250   int npes;
1251   int pes[1];
1252 }
1253 *GroupDef;
1254
1255 #define GROUPTAB_SIZE 101
1256
1257 CpvStaticDeclare(int, CmiGroupHandlerIndex);
1258 CpvStaticDeclare(int, CmiGroupCounter);
1259 CpvStaticDeclare(GroupDef *, CmiGroupTable);
1260
1261 void CmiGroupHandler(GroupDef def)
1262 {
1263   /* receive group definition, insert into group table */
1264   GroupDef *table = CpvAccess(CmiGroupTable);
1265   unsigned int hashval, bucket;
1266   hashval = (def->group.id ^ def->group.pe);
1267   bucket = hashval % GROUPTAB_SIZE;
1268   def->core.next = table[bucket];
1269   table[bucket] = def;
1270 }
1271
1272 CmiGroup CmiEstablishGroup(int npes, int *pes)
1273 {
1274   /* build new group definition, broadcast it */
1275   CmiGroup grp; GroupDef def; int len, i;
1276   grp.id = CpvAccess(CmiGroupCounter)++;
1277   grp.pe = CmiMyPe();
1278   len = sizeof(struct GroupDef)+(npes*sizeof(int));
1279   def = (GroupDef)CmiAlloc(len);
1280   def->group = grp;
1281   def->npes = npes;
1282   for (i=0; i<npes; i++)
1283     def->pes[i] = pes[i];
1284   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
1285   CmiSyncBroadcastAllAndFree(len, def);
1286   return grp;
1287 }
1288
1289 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
1290 {
1291   unsigned int hashval, bucket;  GroupDef def;
1292   GroupDef *table = CpvAccess(CmiGroupTable);
1293   hashval = (grp.id ^ grp.pe);
1294   bucket = hashval % GROUPTAB_SIZE;
1295   for (def=table[bucket]; def; def=def->core.next) {
1296     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
1297       *npes = def->npes;
1298       *pes = def->pes;
1299       return;
1300     }
1301   }
1302   *npes = 0; *pes = 0;
1303 }
1304
1305 void CmiGroupInit()
1306 {
1307   CpvInitialize(int, CmiGroupHandlerIndex);
1308   CpvInitialize(int, CmiGroupCounter);
1309   CpvInitialize(GroupDef *, CmiGroupTable);
1310   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
1311   CpvAccess(CmiGroupCounter) = 0;
1312   CpvAccess(CmiGroupTable) =
1313     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
1314   if (CpvAccess(CmiGroupTable) == 0)
1315     CmiAbort("Memory Allocation Error");
1316 }
1317
1318 #endif
1319
1320 /*****************************************************************************
1321  *
1322  * Common List-Cast and Multicast Code
1323  *
1324  ****************************************************************************/
1325
1326 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
1327
1328 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
1329 {
1330   CmiError("ListSend not implemented.");
1331 }
1332
1333 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
1334 {
1335   CmiError("ListSend not implemented.");
1336   return (CmiCommHandle) 0;
1337 }
1338
1339 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
1340 {
1341   /*CmiError("ListSend not implemented.");*/
1342   int i;
1343   for(i=0;i<npes;i++) {
1344     CmiSyncSend(pes[i], len, msg);
1345   }
1346   CmiFree(msg);
1347 }
1348
1349 #endif
1350
1351 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
1352
1353 typedef struct MultiMsg
1354 {
1355   char core[CmiMsgHeaderSizeBytes];
1356   CmiGroup group;
1357   int pos;
1358   int origlen;
1359 }
1360 *MultiMsg;
1361
1362 CpvDeclare(int, CmiMulticastHandlerIndex);
1363
1364 void CmiMulticastDeliver(MultiMsg msg)
1365 {
1366   int npes, *pes; int olen, nlen, pos, child1, child2;
1367   olen = msg->origlen;
1368   nlen = olen + sizeof(struct MultiMsg);
1369   CmiLookupGroup(msg->group, &npes, &pes);
1370   if (pes==0) {
1371     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
1372     return;
1373   }
1374   if (npes==0) {
1375     CmiFree(msg);
1376     return;
1377   }
1378   if (msg->pos == -1) {
1379     msg->pos=0;
1380     CmiSyncSendAndFree(pes[0], nlen, msg);
1381     return;
1382   }
1383   pos = msg->pos;
1384   child1 = ((pos+1)<<1);
1385   child2 = child1-1;
1386   if (child1 < npes) {
1387     msg->pos = child1;
1388     CmiSyncSend(pes[child1], nlen, msg);
1389   }
1390   if (child2 < npes) {
1391     msg->pos = child2;
1392     CmiSyncSend(pes[child2], nlen, msg);
1393   }
1394   if(olen < sizeof(struct MultiMsg)) {
1395     memcpy(msg, msg+1, olen);
1396   } else {
1397     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
1398   }
1399   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
1400 }
1401
1402 void CmiMulticastHandler(MultiMsg msg)
1403 {
1404   CmiMulticastDeliver(msg);
1405 }
1406
1407 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
1408 {
1409   int newlen; MultiMsg newmsg;
1410   newlen = len + sizeof(struct MultiMsg);
1411   newmsg = (MultiMsg)CmiAlloc(newlen);
1412   if(len < sizeof(struct MultiMsg)) {
1413     memcpy(newmsg+1, msg, len);
1414   } else {
1415     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
1416     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
1417   }
1418   newmsg->group = grp;
1419   newmsg->origlen = len;
1420   newmsg->pos = -1;
1421   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
1422   CmiMulticastDeliver(newmsg);
1423 }
1424
1425 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
1426 {
1427   CmiSyncMulticastFn(grp, len, msg);
1428   CmiFree(msg);
1429 }
1430
1431 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
1432 {
1433   CmiError("Async Multicast not implemented.");
1434   return (CmiCommHandle) 0;
1435 }
1436
1437 void CmiMulticastInit()
1438 {
1439   CpvInitialize(int, CmiMulticastHandlerIndex);
1440   CpvAccess(CmiMulticastHandlerIndex) =
1441     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
1442 }
1443
1444 #endif
1445
1446 /***************************************************************************
1447  *
1448  * Memory Allocation routines 
1449  *
1450  * A block of memory can consist of multiple chunks.  Each chunk has
1451  * a sizefield and a refcount.  The first chunk's refcount is a reference
1452  * count.  That's how many CmiFrees it takes to free the message.
1453  * Subsequent chunks have a refcount which is less than zero.  This is
1454  * the offset back to the start of the first chunk.
1455  *
1456  ***************************************************************************/
1457
1458 #define SIMPLE_CMIALLOC 0
1459
1460 #if SIMPLE_CMIALLOC
1461 void *CmiAlloc(int size)
1462 {
1463         return malloc_nomigrate(size);
1464 }
1465
1466 void CmiReference(void *blk)
1467 {
1468         CmiAbort("CmiReference not supported!\n");
1469 }
1470
1471 int CmiSize(void *blk)
1472 {
1473         CmiAbort("CmiSize not supported!\n");
1474         return 0;
1475 }
1476
1477 void CmiFree(void *blk)
1478 {
1479         free_nomigrate(blk);
1480 }
1481
1482 #else /*!SIMPLE_CMIALLOC*/
1483
1484 #define SIZEFIELD(m) ((int *)((char *)(m)-2*sizeof(int)))[0]
1485 #define REFFIELD(m) ((int *)((char *)(m)-sizeof(int)))[0]
1486 #define BLKSTART(m) ((char *)m-2*sizeof(int))
1487
1488 void *CmiAlloc(size)
1489 int size;
1490 {
1491   char *res;
1492   res =(char *)malloc_nomigrate(size+2*sizeof(int));
1493   _MEMCHECK(res);
1494
1495 #ifdef MEMMONITOR
1496   CpvAccess(MemoryUsage) += size+2*sizeof(int);
1497   CpvAccess(AllocCount)++;
1498   CpvAccess(BlocksAllocated)++;
1499   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
1500     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
1501   }
1502   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
1503     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
1504             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
1505             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
1506     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
1507   }
1508   if ((CpvAccess(AllocCount) % 1000) == 0) {
1509     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
1510             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
1511             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
1512   }
1513 #endif
1514
1515   ((int *)res)[0]=size;
1516   ((int *)res)[1]=1;
1517   return (void *)(res+2*sizeof(int));
1518 }
1519
1520 void CmiReference(blk)
1521 void *blk;
1522 {
1523   int refCount = REFFIELD(blk);
1524   if (refCount < 0) {
1525     blk = (void *)((char*)blk+refCount);
1526     refCount = REFFIELD(blk);
1527   }
1528   REFFIELD(blk) = refCount+1;
1529 }
1530
1531 int CmiSize(blk)
1532 void *blk;
1533 {
1534   return SIZEFIELD(blk);
1535 }
1536
1537 void CmiFree(blk)
1538 void *blk;
1539 {
1540   int refCount;
1541
1542   refCount = REFFIELD(blk);
1543   if (refCount < 0) {
1544     blk = (void *)((char*)blk+refCount);
1545     refCount = REFFIELD(blk);
1546   }
1547   if(refCount==0) {
1548 #ifdef MEMMONITOR
1549     if (SIZEFIELD(blk) > 100000)
1550       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",SIZEFIELD(blk));
1551     CpvAccess(MemoryUsage) -= (SIZEFIELD(blk) + 2*sizeof(int));
1552     CpvAccess(BlocksAllocated)--;
1553     CmiPrintf("Refcount 0 case called\n");
1554 #endif
1555     free_nomigrate(BLKSTART(blk));
1556     return;
1557   }
1558   refCount--;
1559   if(refCount==0) {
1560 #ifdef MEMMONITOR
1561     if (SIZEFIELD(blk) > 100000)
1562       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",SIZEFIELD(blk));
1563     CpvAccess(MemoryUsage) -= (SIZEFIELD(blk) + 2*sizeof(int));
1564     CpvAccess(BlocksAllocated)--;
1565 #endif
1566     free_nomigrate(BLKSTART(blk));
1567     return;
1568   }
1569   REFFIELD(blk) = refCount;
1570 }
1571 #endif /*!SIMPLE_CMIALLOC*/
1572
1573 /******************************************************************************
1574
1575   Multiple Send function                               
1576
1577   ****************************************************************************/
1578
1579 CpvDeclare(int, CmiMainHandlerIDP); /* Main handler that is run on every node */
1580
1581 /****************************************************************************
1582 * DESCRIPTION : This function call allows the user to send multiple messages
1583 *               from one processor to another, all intended for differnet 
1584 *               handlers.
1585 *
1586 *               Parameters :
1587 *
1588 *               destPE, len, int sizes[], char *messages[]
1589 *
1590 * ASSUMPTION  : The sizes[] and the messages[] array begin their indexing FROM 1.
1591 *               (i.e They should have memory allocated for n + 1)
1592 *               This is important to ensure that the call works correctly
1593 *
1594 ****************************************************************************/
1595
1596 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
1597 {
1598   char *header;
1599   int i;
1600   int *newSizes;
1601   char **newMsgComps;
1602   int mask = ~7; /* to mask off the last 3 bits */
1603   char *pad = "                 "; /* padding required - 16 bytes long w.case */
1604
1605   /* Allocate memory for the newSizes array and the newMsgComps array*/
1606   newSizes = (int *)CmiAlloc(2 * (len + 1) * sizeof(int));
1607   newMsgComps = (char **)CmiAlloc(2 * (len + 1) * sizeof(char *));
1608
1609   /* Construct the newSizes array from the old sizes array */
1610   newSizes[0] = (CmiMsgHeaderSizeBytes + (len + 1)*sizeof(int));
1611   newSizes[1] = ((CmiMsgHeaderSizeBytes + (len + 1)*sizeof(int) + 7)&mask) - newSizes[0] + 2*sizeof(int);
1612                      /* To allow the extra 8 bytes for the CmiSize & the Ref Count */
1613
1614   for(i = 1; i < len + 1; i++){
1615     newSizes[2*i] = (sizes[i - 1]);
1616     newSizes[2*i + 1] = ((sizes[i -1] + 7)&mask) - newSizes[2*i] + 2*sizeof(int); 
1617              /* To allow the extra 8 bytes for the CmiSize & the Ref Count */
1618   }
1619     
1620   header = (char *)CmiAlloc(newSizes[0]*sizeof(char));
1621
1622   /* Set the len field in the buffer */
1623   *(int *)(header + CmiMsgHeaderSizeBytes) = len;
1624
1625   /* and the induvidual lengths */
1626   for(i = 1; i < len + 1; i++){
1627     *((int *)(header + CmiMsgHeaderSizeBytes) + i) = newSizes[2*i] + newSizes[2*i + 1];
1628   }
1629
1630   /* This message shd be recd by the main handler */
1631   CmiSetHandler(header, CpvAccess(CmiMainHandlerIDP));
1632   newMsgComps[0] = header;
1633   newMsgComps[1] = pad;
1634
1635   for(i = 1; i < (len + 1); i++){
1636     newMsgComps[2*i] =  msgComps[i - 1];
1637     newMsgComps[2*i + 1] = pad;
1638   }
1639
1640   CmiSyncVectorSend(destPE, 2*(len + 1), newSizes, newMsgComps);
1641   CmiFree(newSizes);
1642   CmiFree(newMsgComps);
1643   CmiFree(header);
1644 }
1645
1646 /****************************************************************************
1647 * DESCRIPTION : This function initializes the main handler required for the
1648 *               CmiMultipleSendP() function to work. 
1649 *               
1650 *               This function should be called once in any Converse program
1651 *               that uses CmiMultipleSendP()
1652 *
1653 ****************************************************************************/
1654
1655 static void CmiMultiMsgHandler(char *msgWhole);
1656
1657 void CmiInitMultipleSend(void)
1658 {
1659   CpvInitialize(int,CmiMainHandlerIDP); 
1660   CpvAccess(CmiMainHandlerIDP) =
1661     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
1662 }
1663
1664 /****************************************************************************
1665 * DESCRIPTION : This function initializes the main handler required for the
1666 *               Immediate message
1667 *               
1668 *               This function should be called once in any Converse program
1669 *
1670 ****************************************************************************/
1671
1672 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
1673
1674 /* xdl is the real handler */
1675 static void CmiImmediateMsgHandler(char *msg)
1676 {
1677   CmiSetHandler(msg, CmiGetXHandler(msg));
1678   CmiHandleMessage(msg);
1679 }
1680
1681 void CmiInitImmediateMsg(void)
1682 {
1683   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
1684   CpvAccess(CmiImmediateMsgHandlerIdx) =
1685     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
1686 }
1687
1688 #if !CMK_IMMEDIATE_MSG
1689 void CmiProbeImmediateMsg()
1690 {
1691 }
1692 #endif 
1693
1694 /****************************************************************************
1695 * DESCRIPTION : This function is the main handler required for the
1696 *               CmiMultipleSendP() function to work. 
1697 *
1698 ****************************************************************************/
1699
1700 static void memChop(char *msgWhole);
1701
1702 static void CmiMultiMsgHandler(char *msgWhole)
1703 {
1704   int len;
1705   int *sizes;
1706   int i;
1707   int offset;
1708   int mask = ~7; /* to mask off the last 3 bits */
1709   
1710   /* Number of messages */
1711   offset = CmiMsgHeaderSizeBytes;
1712   len = *(int *)(msgWhole + offset);
1713   offset += sizeof(int);
1714
1715   /* Allocate array to store sizes */
1716   sizes = (int *)(msgWhole + offset);
1717   offset += sizeof(int)*len;
1718
1719   /* This is needed since the header may or may not be aligned on an 8 bit boundary */
1720   offset = (offset + 7)&mask;
1721
1722   /* To cross the 8 bytes inserted in between */
1723   offset += 2*sizeof(int);
1724
1725   /* Call memChop() */
1726   memChop(msgWhole);
1727
1728   /* Send the messages to their respective handlers (on the same machine) */
1729   /* Currently uses CmiSyncSend(), later modify to use Scheduler enqueuing */
1730   for(i = 0; i < len; i++){
1731     CmiSyncSendAndFree(CmiMyPe(), sizes[i], ((char *)(msgWhole + offset))); 
1732     offset += sizes[i];
1733   }
1734 }
1735
1736 static void memChop(char *msgWhole)
1737 {
1738   int len;
1739   int *sizes;
1740   int i;
1741   int offset;
1742   int mask = ~7; /* to mask off the last 3 bits */
1743   
1744   /* Number of messages */
1745   offset = CmiMsgHeaderSizeBytes;
1746   len = *(int *)(msgWhole + offset);
1747   offset += sizeof(int);
1748
1749   /* Set Reference count in the CmiAlloc header*/
1750   /* Reference Count includes the header also, hence (len + 1) */
1751   ((int *)(msgWhole - sizeof(int)))[0] = len + 1;
1752
1753   /* Allocate array to store sizes */
1754   sizes = (int *)(msgWhole + offset);
1755   offset += sizeof(int)*len;
1756
1757   /* This is needed since the header may or may not be aligned on an 8 bit boundary */
1758   offset = (offset + 7)&mask;
1759
1760   /* To cross the 8 bytes inserted in between */
1761   offset += 2*sizeof(int);
1762
1763   /* update the sizes and offsets for all the chunks */
1764   for(i = 0; i < len; i++){
1765     /* put in the size value for that part */
1766     ((int *)(msgWhole + offset - 2*sizeof(int)))[0] = sizes[i] - 2*sizeof(int);
1767     
1768     /* now put in the offset (a negative value) to get right back to the begining */
1769     ((int *)(msgWhole + offset - sizeof(int)))[0] = (-1)*offset;
1770     
1771     offset += sizes[i];
1772   }
1773 }
1774
1775
1776
1777 /******** Idle timeout module (+idletimeout=30) *********/
1778
1779 typedef struct {
1780   int idle_timeout;/*Milliseconds to wait idle before aborting*/
1781   int is_idle;/*Boolean currently-idle flag*/
1782   int call_count;/*Number of timeout calls currently in flight*/
1783 } cmi_cpu_idlerec;
1784
1785 static void on_timeout(cmi_cpu_idlerec *rec)
1786 {
1787   rec->call_count--;
1788   if(rec->call_count==0 && rec->is_idle==1) {
1789     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
1790     CmiAbort("Exiting.\n");
1791   }
1792 }
1793 static void on_idle(cmi_cpu_idlerec *rec)
1794 {
1795   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
1796   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
1797   rec->is_idle = 1;
1798 }
1799 static void on_busy(cmi_cpu_idlerec *rec)
1800 {
1801   rec->is_idle = 0;
1802 }
1803 static void CIdleTimeoutInit(char **argv)
1804 {
1805   int idle_timeout=0; /*Seconds to wait*/
1806   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
1807   if(idle_timeout != 0) {
1808     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
1809     _MEMCHECK(rec);
1810     rec->idle_timeout=idle_timeout*1000;
1811     rec->is_idle=0;
1812     rec->call_count=0;
1813     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
1814     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
1815   }
1816 }
1817
1818
1819 /*****************************************************************************
1820  *
1821  * Converse Initialization
1822  *
1823  *****************************************************************************/
1824
1825 extern void CrnInit(void);
1826 extern void CmiIsomallocInit(char **argv);
1827
1828 void CommunicationServerInit()
1829 {
1830 #if CMK_IMMEDIATE_MSG
1831   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
1832 #endif
1833 }
1834
1835 void ConverseCommonInit(char **argv)
1836 {
1837   CmiArgInit(argv);
1838   CmiMemoryInit(argv);
1839   CmiTimerInit();
1840   CstatsInit(argv);
1841   CcdModuleInit(argv);
1842   CmiHandlerInit();
1843   CIdleTimeoutInit(argv);
1844   
1845 #ifndef CMK_OPTIMIZE
1846   traceInit(argv);
1847 /*initTraceCore(argv);*/ /* projector */
1848 #endif
1849
1850 #if CMK_CCS_AVAILABLE
1851   CcsInit(argv);
1852 #endif
1853   CmiPersistentInit();
1854   CmiIsomallocInit(argv);
1855   CpdInit();
1856   CmiDeliversInit();
1857   CsdInit(argv);
1858   CthSchedInit();
1859   CmiGroupInit();
1860   CmiMulticastInit();
1861   CmiInitMultipleSend();
1862   CQdInit();
1863
1864   CldModuleInit();
1865   CrnInit();
1866
1867   CmiInitImmediateMsg();
1868 }
1869
1870 void ConverseCommonExit(void)
1871 {
1872   CcsImpl_kill();
1873
1874 #ifndef CMK_OPTIMIZE
1875   traceClose();
1876 /*closeTraceCore();*/ /* projector */
1877 #endif
1878
1879 }
1880
1881
1882 #if CMK_CMIPRINTF_IS_JUST_PRINTF
1883
1884 void CmiPrintf(const char *format, ...)
1885 {
1886   va_list args;
1887   va_start(args,format);
1888   vprintf(format, args);
1889   fflush(stdout);
1890   va_end(args);
1891 }
1892
1893 void CmiError(const char *format, ...)
1894 {
1895   va_list args;
1896   va_start(args,format);
1897   vfprintf(stderr,format, args);
1898   fflush(stderr);
1899   va_end(args);
1900 }
1901
1902 #endif
1903
1904 void __cmi_assert(const char *expr, const char *file, int line)
1905 {
1906   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
1907       CmiMyPe(), expr, file, line);
1908   CmiAbort("");
1909 }