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