make it a strict c code (declare varaible anywhere is not strict c code)
[charm.git] / src / conv-core / convcore.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /** @defgroup Converse
9  * \brief Converse--a parallel portability layer.
10
11  * Converse is the lowest level inside the Charm++ hierarchy. It stands on top
12  * of the machine layer, and it provides all the common functionality across
13  * platforms.
14
15  * One converse program is running on every processor (or node in the smp
16  * version). it manages the message transmission, and the memory allocation.
17  * Charm++, which is on top of Converse, uses its functionality for
18  * interprocess *communication.
19
20  * In order to maintain multiple independent objects inside a single user space
21  * program, it uses a personalized version of threads, which can be executed,
22  * suspended, and migrated across processors.
23
24  * It provides a scheduler for message delivery: methods can be registered to
25  * the scheduler, and then messages allocated through CmiAlloc can be sent to
26  * the correspondent method in a remote processor. This is done through the
27  * converse header (which has few common fields, but is architecture dependent).
28 */
29
30 /** @file
31  * converse main core
32  * @ingroup Converse
33  */
34
35 /**
36  * @addtogroup Converse
37  * @{
38  */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44 #ifndef _WIN32
45 #include <sys/time.h>
46 #include <sys/resource.h>
47 #endif
48
49 #include "converse.h"
50 #include "conv-trace.h"
51 #include "sockRoutines.h"
52 #include "queueing.h"
53 #include "conv-ccs.h"
54 #include "ccs-server.h"
55 #include "memory-isomalloc.h"
56 #include "converseEvents.h"             /* projector */
57 #include "traceCoreCommon.h"    /* projector */
58 #include "machineEvents.h"     /* projector */
59
60 #if CMK_OUT_OF_CORE
61 #include "conv-ooc.h"
62 #endif
63
64 #if CONVERSE_POOL
65 #include "cmipool.h"
66 #endif
67
68 #if CMK_CONDS_USE_SPECIAL_CODE
69 CmiSwitchToPEFnPtr CmiSwitchToPE;
70 #endif
71
72 CpvExtern(int, _traceCoreOn);   /* projector */
73 extern void CcdModuleInit(char **);
74 extern void CmiMemoryInit(char **);
75 extern void CldModuleInit(char **);
76
77 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
78 #include <sys/types.h>
79 #include <sys/time.h>
80 #endif
81
82 #if CMK_TIMER_USE_TIMES
83 #include <sys/times.h>
84 #include <limits.h>
85 #include <unistd.h>
86 #endif
87
88 #if CMK_TIMER_USE_GETRUSAGE
89 #include <sys/time.h>
90 #include <sys/resource.h>
91 #endif
92
93 #if CMK_TIMER_USE_RDTSC
94 #include <string.h>
95 #include <unistd.h>
96 #include <time.h>
97 #include <stdio.h>
98 #include <sys/time.h>
99 #include <sys/resource.h>
100 #endif
101
102 #ifdef CMK_TIMER_USE_WIN32API
103 #include <stdlib.h>
104 #include <time.h>
105 #include <sys/types.h>
106 #include <sys/timeb.h>
107 #endif
108
109 #include "quiescence.h"
110
111 int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
112
113 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
114
115 /*****************************************************************************
116  *
117  * Unix Stub Functions
118  *
119  ****************************************************************************/
120
121 #ifdef MEMMONITOR
122 typedef unsigned long mmulong;
123 CpvDeclare(mmulong,MemoryUsage);
124 CpvDeclare(mmulong,HiWaterMark);
125 CpvDeclare(mmulong,ReportedHiWaterMark);
126 CpvDeclare(int,AllocCount);
127 CpvDeclare(int,BlocksAllocated);
128 #endif
129
130 #define MAX_HANDLERS 512
131
132 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
133 CpvDeclare(int,expIOFlushFlag);
134 #if CMI_IO_BUFFER_EXPLICIT
135 /* 250k not too large depending on how slow terminal IO is */
136 #define DEFAULT_IO_BUFFER_SIZE 250000
137 CpvDeclare(char*,explicitIOBuffer);
138 CpvDeclare(int,expIOBufferSize);
139 #endif
140 #endif
141
142 #if CMK_NODE_QUEUE_AVAILABLE
143 void  *CmiGetNonLocalNodeQ();
144 #endif
145
146 CpvDeclare(void*, CsdSchedQueue);
147
148 #if CMK_OUT_OF_CORE
149 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
150 CpvDeclare(void*, CsdPrefetchQueue);
151 pthread_mutex_t prefetchLock;
152 #endif
153
154 #if CMK_NODE_QUEUE_AVAILABLE
155 CsvDeclare(void*, CsdNodeQueue);
156 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
157 #endif
158 CpvDeclare(int,   CsdStopFlag);
159 CpvDeclare(int,   CsdLocalCounter);
160
161 CmiNodeLock smp_mutex;               /* for smp */
162
163 #if CONVERSE_VERSION_VMI
164 void *CMI_VMI_CmiAlloc (int size);
165 void CMI_VMI_CmiFree (void *ptr);
166 #endif
167
168 #if CONVERSE_VERSION_ELAN
169 void* elan_CmiAlloc(int size);
170 #endif
171
172 #if CMK_USE_IBVERBS
173 void *infi_CmiAlloc(int size);
174 void infi_CmiFree(void *ptr);
175 #endif
176
177
178 #if CMK_GRID_QUEUE_AVAILABLE
179 CpvDeclare(void *, CkGridObject);
180 CpvDeclare(void *, CsdGridQueue);
181 #endif
182
183
184 /*****************************************************************************
185  *
186  * Command-Line Argument (CLA) parsing routines.
187  *
188  *****************************************************************************/
189
190 static int usageChecked=0; /* set when argv has been searched for a usage request */
191 static int printUsage=0; /* if set, print command-line usage information */
192 static const char *CLAformatString="%20s %10s %s\n";
193
194 /* This little list of CLA's holds the argument descriptions until it's
195    safe to print them--it's needed because the net- versions don't have 
196    printf until they're pretty well started.
197  */
198 typedef struct {
199         const char *arg; /* Flag name, like "-foo"*/
200         const char *param; /* Argument's parameter type, like "integer" or "none"*/
201         const char *desc; /* Human-readable description of what it does */
202 } CLA;
203 static int CLAlistLen=0;
204 static int CLAlistMax=0;
205 static CLA *CLAlist=NULL;
206
207 /* Add this CLA */
208 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
209         int i;
210         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
211         if (desc==NULL) return; /*It's an internal argument*/
212         if (usageChecked) { /* Printf should work now */
213                 if (printUsage)
214                         CmiPrintf(CLAformatString,arg,param,desc);
215         }
216         else { /* Printf doesn't work yet-- just add to the list.
217                 This assumes the const char *'s are static references,
218                 which is probably reasonable. */
219                 i=CLAlistLen++;
220                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
221                         CLAlistMax=16+2*CLAlistLen;
222                         CLAlist=realloc(CLAlist,sizeof(CLA)*CLAlistMax);\
223                 }
224                 CLAlist[i].arg=arg;
225                 CLAlist[i].param=param;
226                 CLAlist[i].desc=desc;
227         }
228 }
229
230 /* Print out the stored list of CLA's */
231 static void CmiPrintCLAs(void) {
232         int i;
233         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
234         CmiPrintf("Converse Machine Command-line Parameters:\n ");
235         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
236         for (i=0;i<CLAlistLen;i++) {
237                 CLA *c=&CLAlist[i];
238                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
239         }
240 }
241
242 /**
243  * Determines if command-line usage information should be printed--
244  * that is, if a "-?", "-h", or "--help" flag is present.
245  * Must be called after printf is setup.
246  */
247 void CmiArgInit(char **argv) {
248         int i;
249         for (i=0;argv[i]!=NULL;i++)
250         {
251                 if (0==strcmp(argv[i],"-?") ||
252                     0==strcmp(argv[i],"-h") ||
253                     0==strcmp(argv[i],"--help")) 
254                 {
255                         printUsage=1;
256                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
257                           Leave it there for user program to see... */
258                         CmiPrintCLAs();
259                 }
260         }
261         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
262                 CLAlistLen=CLAlistMax=0;
263                 free(CLAlist); CLAlist=NULL;
264         }
265         usageChecked=1;
266 }
267
268 /* Return 1 if we're currently printing command-line usage information. */
269 int CmiArgGivingUsage(void) {
270         return (CmiMyPe()==0) && printUsage;
271 }
272
273 /* Identifies the module that accepts the following command-line parameters */
274 void CmiArgGroup(const char *parentName,const char *groupName) {
275         if (CmiArgGivingUsage()) {
276                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
277                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
278         }
279 }
280
281 /*Count the number of non-NULL arguments in list*/
282 int CmiGetArgc(char **argv)
283 {
284         int i=0,argc=0;
285         while (argv[i++]!=NULL)
286                 argc++;
287         return argc;
288 }
289
290 /*Return a new, heap-allocated copy of the argv array*/
291 char **CmiCopyArgs(char **argv)
292 {
293         int argc=CmiGetArgc(argv);
294         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
295         int i;
296         for (i=0;i<=argc;i++)
297                 ret[i]=argv[i];
298         return ret;
299 }
300
301 /*Delete the first k argument from the given list, shifting
302 all other arguments down by k spaces.
303 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
304 argv={"d",NULL,"c","d",NULL}
305 */
306 void CmiDeleteArgs(char **argv,int k)
307 {
308         int i=0;
309         while ((argv[i]=argv[i+k])!=NULL)
310                 i++;
311 }
312
313 /*Find the given argment and string option in argv.
314 If the argument is present, set the string option and
315 delete both from argv.  If not present, return NULL.
316 e.g., arg=="-name" returns "bob" from
317 argv=={"a.out","foo","-name","bob","bar"},
318 and sets argv={"a.out","foo","bar"};
319 */
320 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
321 {
322         int i;
323         CmiAddCLA(arg,"string",desc);
324         for (i=0;argv[i]!=NULL;i++)
325                 if (0==strcmp(argv[i],arg))
326                 {/*We found the argument*/
327                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
328                         *optDest=argv[i+1];
329                         CmiDeleteArgs(&argv[i],2);
330                         return 1;
331                 }
332         return 0;/*Didn't find the argument*/
333 }
334 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
335         return CmiGetArgStringDesc(argv,arg,optDest,"");
336 }
337
338 /*Find the given argument and floating-point option in argv.
339 Remove it and return 1; or return 0.
340 */
341 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
342         char *number=NULL;
343         CmiAddCLA(arg,"number",desc);
344         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
345         if (1!=sscanf(number,"%lg",optDest)) return 0;
346         return 1;
347 }
348 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
349         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
350 }
351
352 /*Find the given argument and integer option in argv.
353 If the argument is present, parse and set the numeric option,
354 delete both from argv, and return 1. If not present, return 0.
355 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
356 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
357 but not argv=={...,"-packsize",...}.
358 */
359 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
360 {
361         int i;
362         int argLen=strlen(arg);
363         CmiAddCLA(arg,"integer",desc);
364         for (i=0;argv[i]!=NULL;i++)
365                 if (0==strncmp(argv[i],arg,argLen))
366                 {/*We *may* have found the argument*/
367                         const char *opt=NULL;
368                         int nDel=0;
369                         switch(argv[i][argLen]) {
370                         case 0: /* like "-p","27" */
371                                 opt=argv[i+1]; nDel=2; break;
372                         case '=': /* like "-p=27" */
373                                 opt=&argv[i][argLen+1]; nDel=1; break;
374                         case '-':case '+':
375                         case '0':case '1':case '2':case '3':case '4':
376                         case '5':case '6':case '7':case '8':case '9':
377                                 /* like "-p27" */
378                                 opt=&argv[i][argLen]; nDel=1; break;
379                         default:
380                                 continue; /*False alarm-- skip it*/
381                         }
382                         if (opt==NULL) continue; /*False alarm*/
383                         if (sscanf(opt,"%i",optDest)<1) {
384                         /*Bad command line argument-- die*/
385                                 fprintf(stderr,"Cannot parse %s option '%s' "
386                                         "as an integer.\n",arg,opt);
387                                 CmiAbort("Bad command-line argument\n");
388                         }
389                         CmiDeleteArgs(&argv[i],nDel);
390                         return 1;
391                 }
392         return 0;/*Didn't find the argument-- dest is unchanged*/       
393 }
394 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
395         return CmiGetArgIntDesc(argv,arg,optDest,"");
396 }
397
398 /*Find the given argument in argv.  If present, delete
399 it and return 1; if not present, return 0.
400 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
401 argv={...,"-foobar",...}.
402 */
403 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
404 {
405         int i;
406         CmiAddCLA(arg,"",desc);
407         for (i=0;argv[i]!=NULL;i++)
408                 if (0==strcmp(argv[i],arg))
409                 {/*We found the argument*/
410                         CmiDeleteArgs(&argv[i],1);
411                         return 1;
412                 }
413         return 0;/*Didn't find the argument*/
414 }
415 int CmiGetArgFlag(char **argv,const char *arg) {
416         return CmiGetArgFlagDesc(argv,arg,"");
417 }
418
419
420 /*****************************************************************************
421  *
422  * Stack tracing routines.
423  *
424  *****************************************************************************/
425 #include "cmibacktrace.c"
426
427 /*
428 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
429 the next parenthesis.  Operates in-place on the character data.
430 */
431 static char *_implTrimParenthesis(char *str) {
432   char *lParen=str, *ret=NULL, *rParen=NULL;
433   while (*lParen!='(') {
434     if (*lParen==0) return str; /* No left parenthesis at all. */
435     lParen++;
436   }
437   /* now *lParen=='(', so trim it*/
438   ret=lParen+1;
439   rParen=ret;
440   while (*rParen!=')') {
441     if (*rParen==0) return ret; /* No right parenthesis at all. */
442     rParen++;
443   }
444   /* now *rParen==')', so trim it*/
445   *rParen=' ';
446   return ret;  
447 }
448
449 /*
450 Return the text description of this trimmed routine name, if 
451 it's a system-generated routine where we should stop printing. 
452 This is probably overkill, but improves the appearance of callbacks.
453 */
454 static const char* _implGetBacktraceSys(const char *name) {
455   if (0==strncmp(name,"_call",5)) 
456   { /*it might be something we're interested in*/
457     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
458     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
459   }
460   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
461   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
462   
463   return 0; /*ordinary user routine-- just print normally*/
464 }
465
466 /** Print out the names of these function pointers. */
467 void CmiBacktracePrint(void **retPtrs,int nLevels) {
468   if (nLevels>0) {
469     int i;
470     char **names=CmiBacktraceLookup(retPtrs,nLevels);
471     if (names==NULL) return;
472     CmiPrintf("Stack Traceback:\n");
473     for (i=0;i<nLevels;i++) {
474       const char *trimmed=_implTrimParenthesis(names[i]);
475       const char *print=trimmed;
476       const char *sys=_implGetBacktraceSys(print);
477       if (sys) {
478           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
479           break; /*Stop when we hit Charm++ runtime.*/
480       } else {
481           CmiPrintf("  [%d] %s\n",i,print);
482       }
483     }
484     free(names);
485   }
486 }
487
488 /* Print (to stdout) the names of the functions that have been 
489    called up to this point. nSkip is the number of routines on the
490    top of the stack to *not* print out. */
491 void CmiPrintStackTrace(int nSkip) {
492 #if CMK_USE_BACKTRACE
493         int nLevels=max_stack;
494         void *stackPtrs[max_stack];
495         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
496         CmiBacktracePrint(stackPtrs,nLevels);
497 #endif
498 }
499
500 /*****************************************************************************
501  *
502  * Statistics: currently, the following statistics are not updated by converse.
503  *
504  *****************************************************************************/
505
506 CpvDeclare(int, CstatsMaxChareQueueLength);
507 CpvDeclare(int, CstatsMaxForChareQueueLength);
508 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
509 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
510 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
511
512 void CstatsInit(argv)
513 char **argv;
514 {
515
516 #ifdef MEMMONITOR
517   CpvInitialize(mmulong,MemoryUsage);
518   CpvAccess(MemoryUsage) = 0;
519   CpvInitialize(mmulong,HiWaterMark);
520   CpvAccess(HiWaterMark) = 0;
521   CpvInitialize(mmulong,ReportedHiWaterMark);
522   CpvAccess(ReportedHiWaterMark) = 0;
523   CpvInitialize(int,AllocCount);
524   CpvAccess(AllocCount) = 0;
525   CpvInitialize(int,BlocksAllocated);
526   CpvAccess(BlocksAllocated) = 0;
527 #endif
528
529   CpvInitialize(int, CstatsMaxChareQueueLength);
530   CpvInitialize(int, CstatsMaxForChareQueueLength);
531   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
532   CpvInitialize(int, CstatPrintQueueStatsFlag);
533   CpvInitialize(int, CstatPrintMemStatsFlag);
534
535   CpvAccess(CstatsMaxChareQueueLength) = 0;
536   CpvAccess(CstatsMaxForChareQueueLength) = 0;
537   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
538   CpvAccess(CstatPrintQueueStatsFlag) = 0;
539   CpvAccess(CstatPrintMemStatsFlag) = 0;
540
541 #if 0
542   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
543     CpvAccess(CstatPrintMemStatsFlag)=1;
544   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
545     CpvAccess(CstatPrintQueueStatsFlag)=1;
546 #endif
547 }
548
549 int CstatMemory(i)
550 int i;
551 {
552   return 0;
553 }
554
555 int CstatPrintQueueStats()
556 {
557   return CpvAccess(CstatPrintQueueStatsFlag);
558 }
559
560 int CstatPrintMemStats()
561 {
562   return CpvAccess(CstatPrintMemStatsFlag);
563 }
564
565 /*****************************************************************************
566  *
567  * Cmi handler registration
568  *
569  *****************************************************************************/
570
571 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
572 CpvStaticDeclare(int  , CmiHandlerCount);
573 CpvStaticDeclare(int  , CmiHandlerLocal);
574 CpvStaticDeclare(int  , CmiHandlerGlobal);
575 CpvDeclare(int,         CmiHandlerMax);
576
577 static void CmiExtendHandlerTable(int atLeastLen) {
578     int max = CpvAccess(CmiHandlerMax);
579     int newmax = (atLeastLen+(atLeastLen>>2)+32);
580     int bytes = max*sizeof(CmiHandlerInfo);
581     int newbytes = newmax*sizeof(CmiHandlerInfo);
582     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
583     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
584     _MEMCHECK(nu);
585     memcpy(nu, tab, bytes);
586     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
587     free(tab); tab=nu;
588     CpvAccess(CmiHandlerTable) = tab;
589     CpvAccess(CmiHandlerMax) = newmax;
590 }
591
592 void CmiNumberHandler(int n, CmiHandler h)
593 {
594   CmiHandlerInfo *tab;
595   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
596   tab = CpvAccess(CmiHandlerTable);
597   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
598   tab[n].userPtr = 0;
599 }
600 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
601   CmiHandlerInfo *tab;
602   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
603   tab = CpvAccess(CmiHandlerTable);
604   tab[n].hdlr = h;
605   tab[n].userPtr=userPtr;
606 }
607
608 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
609 #  define DIST_BETWEEN_HANDLERS 3
610 #else /*No local or global handlers; ordinary handlers are back-to-back*/
611 #  define DIST_BETWEEN_HANDLERS 1
612 #endif
613
614 int CmiRegisterHandler(CmiHandler h)
615 {
616   int Count = CpvAccess(CmiHandlerCount);
617   CmiNumberHandler(Count, h);
618   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
619   return Count;
620 }
621 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
622 {
623   int Count = CpvAccess(CmiHandlerCount);
624   CmiNumberHandlerEx(Count, h, userPtr);
625   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
626   return Count;
627 }
628
629
630 #if CMI_LOCAL_GLOBAL_AVAILABLE
631 int CmiRegisterHandlerLocal(h)
632 CmiHandler h;
633 {
634   int Local = CpvAccess(CmiHandlerLocal);
635   CmiNumberHandler(Local, h);
636   CpvAccess(CmiHandlerLocal) = Local+3;
637   return Local;
638 }
639
640 int CmiRegisterHandlerGlobal(h)
641 CmiHandler h;
642 {
643   int Global = CpvAccess(CmiHandlerGlobal);
644   if (CmiMyPe()!=0) 
645     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
646   CmiNumberHandler(Global, h);
647   CpvAccess(CmiHandlerGlobal) = Global+3;
648   return Global;
649 }
650 #endif
651
652 static void _cmiZeroHandler(void *msg) {
653         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
654 }
655
656 static void CmiHandlerInit()
657 {
658   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
659   CpvInitialize(int         , CmiHandlerCount);
660   CpvInitialize(int         , CmiHandlerLocal);
661   CpvInitialize(int         , CmiHandlerGlobal);
662   CpvInitialize(int         , CmiHandlerMax);
663   CpvAccess(CmiHandlerCount)  = 0;
664   CpvAccess(CmiHandlerLocal)  = 1;
665   CpvAccess(CmiHandlerGlobal) = 2;
666   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
667   CpvAccess(CmiHandlerTable) = NULL;
668   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
669 }
670
671
672 /******************************************************************************
673  *
674  * CmiTimer
675  *
676  * Here are two possible implementations of CmiTimer.  Some machines don't
677  * select either, and define the timer in machine.c instead.
678  *
679  *****************************************************************************/
680
681 #if CMK_TIMER_USE_TIMES
682
683 CpvStaticDeclare(double, clocktick);
684 CpvStaticDeclare(int,inittime_wallclock);
685 CpvStaticDeclare(int,inittime_virtual);
686
687 int CmiTimerIsSynchronized()
688 {
689   return 0;
690 }
691
692 void CmiTimerInit()
693 {
694   struct tms temp;
695   CpvInitialize(double, clocktick);
696   CpvInitialize(int, inittime_wallclock);
697   CpvInitialize(int, inittime_virtual);
698   CpvAccess(inittime_wallclock) = times(&temp);
699   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
700   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
701 }
702
703 double CmiWallTimer()
704 {
705   struct tms temp;
706   double currenttime;
707   int now;
708
709   now = times(&temp);
710   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
711   return (currenttime);
712 }
713
714 double CmiCpuTimer()
715 {
716   struct tms temp;
717   double currenttime;
718   int now;
719
720   times(&temp);
721   now = temp.tms_stime + temp.tms_utime;
722   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
723   return (currenttime);
724 }
725
726 double CmiTimer()
727 {
728   return CmiCpuTimer();
729 }
730
731 #endif
732
733 #if CMK_TIMER_USE_GETRUSAGE
734
735 static double inittime_wallclock;
736 CpvStaticDeclare(double, inittime_virtual);
737
738 int CmiTimerIsSynchronized()
739 {
740   return 0;
741 }
742
743 void CmiTimerInit()
744 {
745   struct timeval tv;
746   struct rusage ru;
747   CpvInitialize(double, inittime_virtual);
748
749   /* try to synchronize calling barrier */
750   CmiBarrier();
751   CmiBarrier();
752   CmiBarrier();
753
754   gettimeofday(&tv,0);
755   inittime_wallclock = (tv.tv_sec * 1.0) + (tv.tv_usec*0.000001);
756   getrusage(0, &ru); 
757   CpvAccess(inittime_virtual) =
758     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
759     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
760
761   CmiBarrierZero();
762 }
763
764 double CmiCpuTimer()
765 {
766   struct rusage ru;
767   double currenttime;
768
769   getrusage(0, &ru);
770   currenttime =
771     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
772     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
773   return currenttime - CpvAccess(inittime_virtual);
774 }
775
776 static double lastT = -1.0;
777
778 double CmiWallTimer()
779 {
780   struct timeval tv;
781   double currenttime;
782
783   gettimeofday(&tv,0);
784   currenttime = (tv.tv_sec * 1.0) + (tv.tv_usec * 0.000001);
785 #ifndef CMK_OPTIMIZE
786   if (lastT > 0.0 && currenttime < lastT) {
787     currenttime = lastT;
788   }
789   lastT = currenttime;
790 #endif
791   return currenttime - inittime_wallclock;
792 }
793
794 double CmiTimer()
795 {
796   return CmiCpuTimer();
797 }
798
799 #endif
800
801 #if CMK_TIMER_USE_RDTSC
802
803 static double readMHz(void)
804 {
805   double x;
806   char str[1000];
807   char buf[100];
808   FILE *fp;
809   CmiLock(smp_mutex);
810   fp = fopen("/proc/cpuinfo", "r");
811   if (fp != NULL)
812   while(fgets(str, 1000, fp)!=0) {
813     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
814     {
815       char *s = strchr(str, ':'); s=s+1;
816       sscanf(s, "%lf", &x);
817       fclose(fp);
818       CmiUnlock(smp_mutex);
819       return x;
820     }
821   }
822   CmiUnlock(smp_mutex);
823   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
824   return 0.0;
825 }
826
827 double _cpu_speed_factor;
828 CpvStaticDeclare(double, inittime_virtual);
829 CpvStaticDeclare(double, inittime_walltime);
830
831 double  CmiStartTimer(void)
832 {
833   return CpvAccess(inittime_walltime);
834 }
835
836 void CmiTimerInit()
837 {
838   struct rusage ru;
839
840   CmiBarrier();
841   CmiBarrier();
842
843   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
844   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
845   CpvInitialize(double, inittime_walltime);
846   CpvAccess(inittime_walltime) = CmiWallTimer();
847   CpvInitialize(double, inittime_virtual);
848   getrusage(0, &ru); 
849   CpvAccess(inittime_virtual) =
850     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
851     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
852
853   CmiBarrierZero();
854 }
855
856 double CmiCpuTimer()
857 {
858   struct rusage ru;
859   double currenttime;
860
861   getrusage(0, &ru);
862   currenttime =
863     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
864     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
865   return currenttime - CpvAccess(inittime_virtual);
866 }
867
868 #endif
869
870 #if CMK_VERSION_BLUEGENE || CMK_BLUEGENEP
871 #include "dcopy.h"
872 #endif
873
874 #if CMK_TIMER_USE_BLUEGENEL
875
876 #include "rts.h"
877
878 #if 0 
879 #define SPRN_TBRL 0x10C  /* Time Base Read Lower Register (user & sup R/O) */
880 #define SPRN_TBRU 0x10D  /* Time Base Read Upper Register (user & sup R/O) */
881 #define SPRN_PIR  0x11E  /* CPU id */
882
883 static inline unsigned long long BGLTimebase(void)
884 {
885   unsigned volatile u1, u2, lo;
886   union
887   {
888     struct { unsigned hi, lo; } w;
889     unsigned long long d;
890   } result;
891                                                                                 
892   do {
893     asm volatile ("mfspr %0,%1" : "=r" (u1) : "i" (SPRN_TBRU));
894     asm volatile ("mfspr %0,%1" : "=r" (lo) : "i" (SPRN_TBRL));
895     asm volatile ("mfspr %0,%1" : "=r" (u2) : "i" (SPRN_TBRU));
896   } while (u1!=u2);
897                                                                                 
898   result.w.lo = lo;
899   result.w.hi = u2;
900   return result.d;
901 }
902 #endif
903
904 static unsigned long long inittime_wallclock = 0;
905 CpvStaticDeclare(double, clocktick);
906
907 int CmiTimerIsSynchronized()
908 {
909   return 0;
910 }
911
912 void CmiTimerInit()
913 {
914   BGLPersonality dst;
915   CpvInitialize(double, clocktick);
916   int size = sizeof(BGLPersonality);
917   rts_get_personality(&dst, size);
918   CpvAccess(clocktick) = 1.0 / dst.clockHz;
919
920   /* try to synchronize calling barrier */
921   CmiBarrier();
922   CmiBarrier();
923   CmiBarrier();
924
925   /* inittime_wallclock = rts_get_timebase(); */
926   inittime_wallclock = 0.0;    /* use bgl absolute time */
927 }
928
929 double CmiWallTimer()
930 {
931   unsigned long long currenttime;
932   currenttime = rts_get_timebase();
933   return CpvAccess(clocktick)*(currenttime-inittime_wallclock);
934 }
935
936 double CmiCpuTimer()
937 {
938   return CmiWallTimer();
939 }
940
941 double CmiTimer()
942 {
943   return CmiWallTimer();
944 }
945
946 #endif
947
948 #if CMK_TIMER_USE_BLUEGENEP  /* This module just compiles with GCC charm. */
949
950 void CmiTimerInit() {}
951
952 #if 0
953 #include "common/bgp_personality.h"
954 #include <spi/bgp_SPI.h>
955
956 #define SPRN_TBRL 0x10C  /* Time Base Read Lower Register (user & sup R/O) */
957 #define SPRN_TBRU 0x10D  /* Time Base Read Upper Register (user & sup R/O) */
958 #define SPRN_PIR  0x11E  /* CPU id */
959
960 static inline unsigned long long BGPTimebase(void)
961 {
962   unsigned volatile u1, u2, lo;
963   union
964   {
965     struct { unsigned hi, lo; } w;
966     unsigned long long d;
967   } result;
968                                                                          
969   do {
970     asm volatile ("mfspr %0,%1" : "=r" (u1) : "i" (SPRN_TBRU));
971     asm volatile ("mfspr %0,%1" : "=r" (lo) : "i" (SPRN_TBRL));
972     asm volatile ("mfspr %0,%1" : "=r" (u2) : "i" (SPRN_TBRU));
973   } while (u1!=u2);
974                                                                          
975   result.w.lo = lo;
976   result.w.hi = u2;
977   return result.d;
978 }
979
980 static unsigned long long inittime_wallclock = 0;
981 CpvStaticDeclare(double, clocktick);
982
983 int CmiTimerIsSynchronized()
984 {
985   return 0;
986 }
987
988 void CmiTimerInit()
989 {
990   _BGP_Personality_t dst;
991   CpvInitialize(double, clocktick);
992   int size = sizeof(_BGP_Personality_t);
993   rts_get_personality(&dst, size);
994
995   CpvAccess(clocktick) = 1.0 / (dst.Kernel_Config.FreqMHz * 1e6);
996
997   /* try to synchronize calling barrier */
998   CmiBarrier();
999   CmiBarrier();
1000   CmiBarrier();
1001
1002   inittime_wallclock = BGPTimebase (); 
1003 }
1004
1005 double CmiWallTimer()
1006 {
1007   unsigned long long currenttime;
1008   currenttime = BGPTimebase();
1009   return CpvAccess(clocktick)*(currenttime-inittime_wallclock);
1010 }
1011 #endif
1012
1013 #include "dcmf.h"
1014
1015 double CmiWallTimer () {
1016   return DCMF_Timer();
1017 }
1018
1019 double CmiCpuTimer()
1020 {
1021   return CmiWallTimer();
1022 }
1023
1024 double CmiTimer()
1025 {
1026   return CmiWallTimer();
1027 }
1028
1029 #endif
1030
1031
1032 #if CMK_TIMER_USE_WIN32API
1033
1034 CpvStaticDeclare(double, inittime_wallclock);
1035 CpvStaticDeclare(double, inittime_virtual);
1036
1037 void CmiTimerInit()
1038 {
1039 #ifdef __CYGWIN__
1040         struct timeb tv;
1041 #else
1042         struct _timeb tv;
1043 #endif
1044         clock_t       ru;
1045
1046         CpvInitialize(double, inittime_wallclock);
1047         CpvInitialize(double, inittime_virtual);
1048         _ftime(&tv);
1049         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1050         ru = clock();
1051         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1052 }
1053
1054 double CmiCpuTimer()
1055 {
1056         clock_t ru;
1057         double currenttime;
1058
1059         ru = clock();
1060         currenttime = (double) ru/CLOCKS_PER_SEC;
1061
1062         return currenttime - CpvAccess(inittime_virtual);
1063 }
1064
1065 double CmiWallTimer()
1066 {
1067 #ifdef __CYGWIN__
1068         struct timeb tv;
1069 #else
1070         struct _timeb tv;
1071 #endif
1072         double currenttime;
1073
1074         _ftime(&tv);
1075         currenttime = tv.time*1.0 + tv.millitm*0.001;
1076
1077         return currenttime - CpvAccess(inittime_wallclock);
1078 }
1079         
1080
1081 double CmiTimer()
1082 {
1083         return CmiCpuTimer();
1084 }
1085
1086 #endif
1087
1088 #if CMK_TIMER_USE_RTC
1089
1090 #if __crayx1
1091  /* For _rtc() on Cray X1 */
1092 #include <intrinsics.h>
1093 #endif
1094
1095 static double clocktick;
1096 CpvStaticDeclare(long long, inittime_wallclock);
1097
1098 void CmiTimerInit()
1099 {
1100   CpvInitialize(long long, inittime_wallclock);
1101   CpvAccess(inittime_wallclock) = _rtc();
1102   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1103 }
1104
1105 double CmiWallTimer()
1106 {
1107   long long now;
1108
1109   now = _rtc();
1110   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1111 }
1112
1113 double CmiCpuTimer()
1114 {
1115   return CmiWallTimer();
1116 }
1117
1118 double CmiTimer()
1119 {
1120   return CmiCpuTimer();
1121 }
1122
1123 #endif
1124
1125 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1126 /** Return 1 if our outgoing message queue 
1127    for this node is longer than this many bytes. */
1128 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1129   return 0;
1130 }
1131 #endif
1132
1133 #if CMK_SIGNAL_USE_SIGACTION
1134 #include <signal.h>
1135 void CmiSignal(sig1, sig2, sig3, handler)
1136 int sig1, sig2, sig3;
1137 void (*handler)();
1138 {
1139   struct sigaction in, out ;
1140   in.sa_handler = handler;
1141   sigemptyset(&in.sa_mask);
1142   if (sig1) sigaddset(&in.sa_mask, sig1);
1143   if (sig2) sigaddset(&in.sa_mask, sig2);
1144   if (sig3) sigaddset(&in.sa_mask, sig3);
1145   in.sa_flags = 0;
1146   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1147   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1148   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1149 }
1150 #endif
1151
1152 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1153 #include <signal.h>
1154 void CmiSignal(sig1, sig2, sig3, handler)
1155 int sig1, sig2, sig3;
1156 void (*handler)();
1157 {
1158   struct sigaction in, out ;
1159   in.sa_handler = handler;
1160   sigemptyset(&in.sa_mask);
1161   if (sig1) sigaddset(&in.sa_mask, sig1);
1162   if (sig2) sigaddset(&in.sa_mask, sig2);
1163   if (sig3) sigaddset(&in.sa_mask, sig3);
1164   in.sa_flags = SA_RESTART;
1165   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1166   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1167   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1168 }
1169 #endif
1170
1171 /*****************************************************************************
1172  *
1173  * The following is the CsdScheduler function.  A common
1174  * implementation is provided below.  The machine layer can provide an
1175  * alternate implementation if it so desires.
1176  *
1177  * void CmiDeliversInit()
1178  *
1179  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1180  *        or any of the other functions in this section.
1181  *
1182  * int CmiDeliverMsgs(int maxmsgs)
1183  *
1184  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1185  *        with the Cmi, and will invoke their handlers.  It does not wait
1186  *        if no message is unavailable.  Instead, it returns the quantity
1187  *        (maxmsgs-delivered), where delivered is the number of messages it
1188  *        delivered.
1189  *
1190  * void CmiDeliverSpecificMsg(int handlerno)
1191  *
1192  *      - Waits for a message with the specified handler to show up, then
1193  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1194  *        This function _does_ wait.
1195  *
1196  * For this common implementation to work, the machine layer must provide the
1197  * following:
1198  *
1199  * void *CmiGetNonLocal()
1200  *
1201  *      - returns a message just retrieved from some other PE, not from
1202  *        local.  If no such message exists, returns 0.
1203  *
1204  * CpvExtern(CdsFifo, CmiLocalQueue);
1205  *
1206  *      - a FIFO queue containing all messages from the local processor.
1207  *
1208  *****************************************************************************/
1209
1210 void CsdBeginIdle(void)
1211 {
1212   CcdCallBacks();
1213   _LOG_E_PROC_IDLE();   /* projector */
1214   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1215 }
1216
1217 void CsdStillIdle(void)
1218 {
1219   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1220 }
1221
1222 void CsdEndIdle(void)
1223 {
1224   _LOG_E_PROC_BUSY();   /* projector */
1225   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1226 }
1227
1228 #if CMK_MEM_CHECKPOINT
1229 #define MESSAGE_PHASE_CHECK     \
1230         {       \
1231           int phase = CmiGetRestartPhase(msg);  \
1232           if (phase < cur_restart_phase) {      \
1233             /*CmiPrintf("[%d] discard message of phase %d cur_restart_phase:%d handler:%d. \n", CmiMyPe(), phase, cur_restart_phase, handler);*/        \
1234             CmiFree(msg);       \
1235             return;     \
1236           }     \
1237         }
1238 #else
1239 #define MESSAGE_PHASE_CHECK
1240 #endif
1241
1242 extern int _exitHandlerIdx;
1243
1244 void CmiHandleMessage(void *msg)
1245 {
1246 /* this is wrong because it counts the Charm++ messages in sched queue
1247         CpvAccess(cQdState)->mProcessed++;
1248 */
1249         CmiHandlerInfo *h;
1250 #ifndef CMK_OPTIMIZE
1251         CmiUInt2 handler=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1252         _LOG_E_HANDLER_BEGIN(handler); /* projector */
1253         setMemoryStatus(1)  /* charmdebug */
1254 #endif
1255
1256 /*
1257         FAULT_EVAC
1258 */
1259 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1260                 return;
1261         }*/
1262         
1263         MESSAGE_PHASE_CHECK
1264
1265         h=&CmiGetHandlerInfo(msg);
1266         (h->hdlr)(msg,h->userPtr);
1267 #ifndef CMK_OPTIMIZE
1268         setMemoryStatus(0)  /* charmdebug */
1269         _LOG_E_HANDLER_END(handler);    /* projector */
1270 #endif
1271 }
1272
1273 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1274
1275 void CmiDeliversInit()
1276 {
1277 }
1278
1279 int CmiDeliverMsgs(int maxmsgs)
1280 {
1281   return CsdScheduler(maxmsgs);
1282 }
1283
1284 #if CMK_OBJECT_QUEUE_AVAILABLE
1285 CpvDeclare(void *, CsdObjQueue);
1286 #endif
1287
1288 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1289 {
1290 #if CMK_OBJECT_QUEUE_AVAILABLE
1291         s->objQ=CpvAccess(CsdObjQueue);
1292 #endif
1293         s->localQ=CpvAccess(CmiLocalQueue);
1294         s->schedQ=CpvAccess(CsdSchedQueue);
1295         s->localCounter=&(CpvAccess(CsdLocalCounter));
1296 #if CMK_NODE_QUEUE_AVAILABLE
1297         s->nodeQ=CsvAccess(CsdNodeQueue);
1298         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1299 #endif
1300 #if CMK_GRID_QUEUE_AVAILABLE
1301         s->gridQ=CpvAccess(CsdGridQueue);
1302 #endif
1303 }
1304
1305 void *CsdNextMessage(CsdSchedulerState_t *s) {
1306         void *msg;
1307         if((*(s->localCounter))-- >0)
1308           {
1309               /* This avoids a race condition with migration detected by megatest*/
1310               msg=CdsFifo_Dequeue(s->localQ);
1311               if (msg!=NULL)
1312                 {
1313                   CpvAccess(cQdState)->mProcessed++;
1314                   return msg;       
1315                 }
1316               CqsDequeue(s->schedQ,(void **)&msg);
1317               if (msg!=NULL) return msg;
1318           }
1319         
1320         *(s->localCounter)=CsdLocalMax;
1321         if ( NULL!=(msg=CmiGetNonLocal()) || 
1322              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1323             CpvAccess(cQdState)->mProcessed++;
1324             return msg;
1325         }
1326 #if CMK_GRID_QUEUE_AVAILABLE
1327         CqsDequeue (s->gridQ, (void **) &msg);
1328         if (msg != NULL) {
1329           return (msg);
1330         }
1331 #endif
1332 #if CMK_NODE_QUEUE_AVAILABLE
1333         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1334         if (!CqsEmpty(s->nodeQ)
1335          && !CqsPrioGT(CqsGetPriority(s->nodeQ),
1336                        CqsGetPriority(s->schedQ))) {
1337           CmiLock(s->nodeLock);
1338           CqsDequeue(s->nodeQ,(void **)&msg);
1339           CmiUnlock(s->nodeLock);
1340           if (msg!=NULL) return msg;
1341         }
1342 #endif
1343 #if CMK_OBJECT_QUEUE_AVAILABLE
1344         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1345           return msg;
1346         }
1347 #endif
1348         if(!CsdLocalMax) {
1349           CqsDequeue(s->schedQ,(void **)&msg);
1350             if (msg!=NULL) return msg;      
1351         }
1352
1353         return NULL;
1354 }
1355
1356 int CsdScheduler(int maxmsgs)
1357 {
1358         if (maxmsgs<0) CsdScheduleForever();    
1359         else if (maxmsgs==0)
1360                 CsdSchedulePoll();
1361         else /*(maxmsgs>0)*/ 
1362                 return CsdScheduleCount(maxmsgs);
1363         return 0;
1364 }
1365
1366 /*Declare the standard scheduler housekeeping*/
1367 #define SCHEDULE_TOP \
1368       void *msg;\
1369                         int rank = CmiMyRank();\
1370       int cycle = Cpv_CsdStopFlag_[rank]; \
1371       CsdSchedulerState_t state;\
1372       CsdSchedulerState_new(&state);\
1373
1374 /*A message is available-- process it*/
1375 #define SCHEDULE_MESSAGE \
1376       CmiHandleMessage(msg);\
1377       if (Cpv_CsdStopFlag_[rank] != cycle) break;\
1378
1379 /*No message available-- go (or remain) idle*/
1380 #define SCHEDULE_IDLE \
1381       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1382       else CsdStillIdle();\
1383       if (Cpv_CsdStopFlag_[rank] != cycle) {\
1384         CsdEndIdle();\
1385         break;\
1386       }\
1387 /*
1388         EVAC
1389 */
1390 extern void CkClearAllArrayElements();
1391
1392
1393 extern void machine_OffloadAPIProgress();
1394
1395 void CsdScheduleForever(void)
1396 {
1397   #if CMK_CELL
1398     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1399     int progressCount = CMK_CELL_PROGRESS_FREQ;
1400   #endif
1401
1402   int isIdle=0;
1403   SCHEDULE_TOP
1404   while (1) {
1405     msg = CsdNextMessage(&state);
1406     if (msg) { /*A message is available-- process it*/
1407       if (isIdle) {isIdle=0;CsdEndIdle();}
1408       SCHEDULE_MESSAGE
1409
1410       #if CMK_CELL
1411         if (progressCount <= 0) {
1412           //OffloadAPIProgress();
1413           machine_OffloadAPIProgress();
1414           progressCount = CMK_CELL_PROGRESS_FREQ;
1415         }
1416         progressCount--;
1417       #endif
1418
1419     } else { /*No message available-- go (or remain) idle*/
1420       SCHEDULE_IDLE
1421
1422       #if CMK_CELL
1423         //OffloadAPIProgress();
1424         machine_OffloadAPIProgress();
1425         progressCount = CMK_CELL_PROGRESS_FREQ;
1426       #endif
1427
1428     }
1429     CsdPeriodic();
1430   }
1431 }
1432 int CsdScheduleCount(int maxmsgs)
1433 {
1434   int isIdle=0;
1435   SCHEDULE_TOP
1436   while (1) {
1437     msg = CsdNextMessage(&state);
1438     if (msg) { /*A message is available-- process it*/
1439       if (isIdle) {isIdle=0;CsdEndIdle();}
1440       maxmsgs--; 
1441       SCHEDULE_MESSAGE
1442       if (maxmsgs==0) break;
1443     } else { /*No message available-- go (or remain) idle*/
1444       SCHEDULE_IDLE
1445     }
1446     CsdPeriodic();
1447   }
1448   return maxmsgs;
1449 }
1450
1451 void CsdSchedulePoll(void)
1452 {
1453   SCHEDULE_TOP
1454   while (1)
1455   {
1456         CsdPeriodic();
1457         /*CmiMachineProgressImpl(); ??? */
1458         if (NULL!=(msg = CsdNextMessage(&state)))
1459         {
1460              SCHEDULE_MESSAGE 
1461         }
1462         else break;
1463   }
1464 }
1465
1466 void CmiDeliverSpecificMsg(handler)
1467 int handler;
1468 {
1469   int *msg; int side;
1470   void *localqueue = CpvAccess(CmiLocalQueue);
1471  
1472   side = 0;
1473   while (1) {
1474     CsdPeriodic();
1475     side ^= 1;
1476     if (side) msg = CmiGetNonLocal();
1477     else      msg = CdsFifo_Dequeue(localqueue);
1478     if (msg) {
1479       if (CmiGetHandler(msg)==handler) {
1480         CpvAccess(cQdState)->mProcessed++;
1481         CmiHandleMessage(msg);
1482         return;
1483       } else {
1484         CdsFifo_Enqueue(localqueue, msg);
1485       }
1486     }
1487   }
1488 }
1489  
1490 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1491
1492 /***************************************************************************
1493  *
1494  * Standin Schedulers.
1495  *
1496  * We use the following strategy to make sure somebody's always running
1497  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1498  * is responsible for this.  If the main thread blocks, we create a
1499  * "standin scheduler" thread to replace it.  If the standin scheduler
1500  * blocks, we create another standin scheduler to replace that one,
1501  * ad infinitum.  Collectively, the main thread and all the standin
1502  * schedulers are called "scheduling threads".
1503  *
1504  * Suppose the main thread is blocked waiting for data, and a standin
1505  * scheduler is running instead.  Suppose, then, that the data shows
1506  * up and the main thread is CthAwakened.  This causes a token to be
1507  * pushed into the queue.  When the standin pulls the token from the
1508  * queue and handles it, the standin goes to sleep, and control shifts
1509  * back to the main thread.  In this way, unnecessary standins are put
1510  * back to sleep.  These sleeping standins are stored on the
1511  * CthSleepingStandins list.
1512  *
1513  ***************************************************************************/
1514
1515 CpvStaticDeclare(CthThread, CthMainThread);
1516 CpvStaticDeclare(CthThread, CthSchedulingThread);
1517 CpvStaticDeclare(CthThread, CthSleepingStandins);
1518 CpvStaticDeclare(int      , CthResumeNormalThreadIdx);
1519 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1520
1521
1522 void CthStandinCode()
1523 {
1524   while (1) CsdScheduler(0);
1525 }
1526
1527 /* this fix the function pointer for thread migration and pup */
1528 static CthThread CthSuspendNormalThread()
1529 {
1530   return CpvAccess(CthSchedulingThread);
1531 }
1532
1533 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
1534 CthThread CthSuspendSchedulingThread();
1535
1536 CthThread CthSuspendSchedulingThread()
1537 {
1538   CthThread succ = CpvAccess(CthSleepingStandins);
1539
1540   if (succ) {
1541     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
1542   } else {
1543     succ = CthCreate(CthStandinCode, 0, 256000);
1544     CthSetStrategy(succ,
1545                    CthEnqueueSchedulingThread,
1546                    CthSuspendSchedulingThread);
1547   }
1548   
1549   CpvAccess(CthSchedulingThread) = succ;
1550   return succ;
1551 }
1552
1553 void CthResumeNormalThread(CthThreadToken* token)
1554 {
1555   CthThread t = token->thread;
1556   if(t == NULL){
1557     free(token);
1558     return;
1559   }
1560 #ifndef CMK_OPTIMIZE
1561 #if ! CMK_TRACE_IN_CHARM
1562   if(CpvAccess(traceOn))
1563     CthTraceResume(t);
1564 /*    if(CpvAccess(_traceCoreOn)) 
1565                 resumeTraceCore();*/
1566 #endif
1567 #endif
1568     
1569   CthResume(t);
1570 }
1571
1572 void CthResumeSchedulingThread(CthThreadToken  *token)
1573 {
1574   CthThread t = token->thread;
1575   CthThread me = CthSelf();
1576   if (me == CpvAccess(CthMainThread)) {
1577     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
1578   } else {
1579     CthSetNext(me, CpvAccess(CthSleepingStandins));
1580     CpvAccess(CthSleepingStandins) = me;
1581   }
1582   CpvAccess(CthSchedulingThread) = t;
1583 #ifndef CMK_OPTIMIZE
1584 #if ! CMK_TRACE_IN_CHARM
1585   if(CpvAccess(traceOn))
1586     CthTraceResume(t);
1587 /*    if(CpvAccess(_traceCoreOn)) 
1588                 resumeTraceCore();*/
1589 #endif
1590 #endif
1591   CthResume(t);
1592 }
1593
1594 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
1595                                    int pb,unsigned int *prio)
1596 {
1597   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
1598   CsdEnqueueGeneral(token, s, pb, prio);
1599 }
1600
1601 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
1602                                        int pb,unsigned int *prio)
1603 {
1604   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
1605   CsdEnqueueGeneral(token, s, pb, prio);
1606 }
1607
1608 void CthSetStrategyDefault(CthThread t)
1609 {
1610   CthSetStrategy(t,
1611                  CthEnqueueNormalThread,
1612                  CthSuspendNormalThread);
1613 }
1614
1615 void CthSchedInit()
1616 {
1617   CpvInitialize(CthThread, CthMainThread);
1618   CpvInitialize(CthThread, CthSchedulingThread);
1619   CpvInitialize(CthThread, CthSleepingStandins);
1620   CpvInitialize(int      , CthResumeNormalThreadIdx);
1621   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
1622
1623   CpvAccess(CthMainThread) = CthSelf();
1624   CpvAccess(CthSchedulingThread) = CthSelf();
1625   CpvAccess(CthSleepingStandins) = 0;
1626   CpvAccess(CthResumeNormalThreadIdx) =
1627     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
1628   CpvAccess(CthResumeSchedulingThreadIdx) =
1629     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
1630   CthSetStrategy(CthSelf(),
1631                  CthEnqueueSchedulingThread,
1632                  CthSuspendSchedulingThread);
1633 }
1634
1635 void CsdInit(argv)
1636   char **argv;
1637 {
1638   CpvInitialize(void *, CsdSchedQueue);
1639   CpvInitialize(int,   CsdStopFlag);
1640   CpvInitialize(int,   CsdLocalCounter);
1641   if(!CmiGetArgIntDesc(argv,"+csdLocalMax",&CsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages."))
1642     {
1643       CsdLocalMax= CSD_LOCAL_MAX_DEFAULT;
1644     }
1645   CpvAccess(CsdLocalCounter) = CsdLocalMax;
1646   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
1647
1648 #if CMK_OBJECT_QUEUE_AVAILABLE
1649   CpvInitialize(void *,CsdObjQueue);
1650   CpvAccess(CsdObjQueue) = CdsFifo_Create();
1651 #endif
1652
1653 #if CMK_NODE_QUEUE_AVAILABLE
1654   CsvInitialize(CmiLock, CsdNodeQueueLock);
1655   CsvInitialize(void *, CsdNodeQueue);
1656   if (CmiMyRank() ==0) {
1657         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
1658         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
1659   }
1660   CmiNodeAllBarrier();
1661 #endif
1662
1663 #if CMK_GRID_QUEUE_AVAILABLE
1664   CsvInitialize(void *, CsdGridQueue);
1665   CpvAccess(CsdGridQueue) = (void *)CqsCreate();
1666 #endif
1667
1668   CpvAccess(CsdStopFlag)  = 0;
1669 }
1670
1671
1672 /*****************************************************************************
1673  *
1674  * Vector Send
1675  *
1676  * The last parameter "system" is by default at zero, in which case the normal
1677  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
1678  * CmiAllocced message will also be sent (except for the first one). Useful for
1679  * AllToAll communication, and other system features. If system is 1, also all
1680  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
1681  * that.
1682  *
1683  ****************************************************************************/
1684
1685 #if CMK_VECTOR_SEND_USES_COMMON_CODE
1686
1687 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
1688   int total;
1689   char *mesg;
1690   VECTOR_COMPACT(total, mesg, n, sizes, msgs);
1691   CmiSyncSendAndFree(destPE, total, mesg);
1692 }
1693
1694 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
1695   CmiSyncVectorSend(destPE, n, sizes, msgs);
1696   return NULL;
1697 }
1698
1699 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
1700   int i;
1701   CmiSyncVectorSend(destPE, n, sizes, msgs);
1702   for(i=0;i<n;i++) CmiFree(msgs[i]);
1703   CmiFree(sizes);
1704   CmiFree(msgs);
1705 }
1706
1707 #endif
1708
1709 /*****************************************************************************
1710  *
1711  * Reduction management
1712  *
1713  * Only one reduction can be active at a single time in the program.
1714  * Moreover, since every call is supposed to pass in the same arguments,
1715  * having some static variables is not a problem for multithreading.
1716  * 
1717  * Except for "data" and "size", all the other parameters (which are all function
1718  * pointers) MUST be the same in every processor. Having different processors
1719  * pass in different function pointers results in an undefined behaviour.
1720  * 
1721  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
1722  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
1723  * functions is deleted with the provided function, or it is left intact if no
1724  * function is specified.
1725  * 
1726  * The destination handler for the the first form MUST be embedded into the
1727  * message's header.
1728  * 
1729  * The pup function is used to pup the input data structure into a message to
1730  * be sent to the parent processor. This pup routine is currently used only
1731  * for sizing and packing, NOT unpacking. It MUST be non-null.
1732  * 
1733  * The merge function receives as first parameter the input "data", being it
1734  * a message or a complex data structure (it is up to the user to interpret it
1735  * correctly), and a list of incoming (packed) messages from the children.
1736  * The merge function is responsible to delete "data" if this is no longer needed.
1737  * The system will be in charge of deleting the messages passed in as the second
1738  * argument, and the return value of the function (using the provided deleteFn in
1739  * the second version, or CmiFree in the first). The merge function can return
1740  * data if the merge can be performed in-place. It MUST be non-null.
1741  * 
1742  * At the destination, on processor zero, the final data returned by the last
1743  * merge call will not be deleted by the system, and the CmiHandler function
1744  * will be in charge of its deletion.
1745  * 
1746  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
1747  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
1748  * particular by the rank zero in each node.
1749  ****************************************************************************/
1750
1751 CpvStaticDeclare(int, CmiReductionMessageHandler);
1752 CpvStaticDeclare(int, _reduce_num_children);
1753 CpvStaticDeclare(int, _reduce_parent);
1754 CpvStaticDeclare(int, _reduce_received);
1755 CpvStaticDeclare(void**, _reduce_msg_list);
1756 CpvStaticDeclare(void*, _reduce_data);
1757 CpvStaticDeclare(int, _reduce_data_size);
1758 static CmiHandler _reduce_destination;
1759 static void * (*_reduce_mergeFn)(void*,void**,int);
1760 static void (*_reduce_pupFn)(void*,void*);
1761 static void (*_reduce_deleteFn)(void*);
1762
1763 CmiReductionsInit() {
1764   CpvInitialize(int, CmiReductionMessageHandler);
1765   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
1766   CpvInitialize(int, _reduce_num_children);
1767   CpvInitialize(int, _reduce_parent);
1768   CpvInitialize(int, _reduce_received);
1769   CpvInitialize(void**, _reduce_msg_list);
1770   CpvInitialize(void*, _reduce_data);
1771   CpvInitialize(int, _reduce_data_size);
1772   CpvAccess(_reduce_num_children) = 0;
1773   CpvAccess(_reduce_received) = 0;
1774   CpvAccess(_reduce_msg_list) = (void**)malloc(CmiNumSpanTreeChildren(CmiMyPe())*sizeof(void*));
1775 }
1776
1777 void CmiSendReduce() {
1778   void *mergedData = CpvAccess(_reduce_data);
1779   void *msg;
1780   int msg_size;
1781   if (CpvAccess(_reduce_num_children) > 0) {
1782     int i, offset=0;
1783     if (_reduce_pupFn != NULL) {
1784       offset = CmiMsgHeaderSizeBytes;
1785       for (i=0; i<CpvAccess(_reduce_num_children); ++i) (char*)(CpvAccess(_reduce_msg_list)[i]) += offset;
1786     }
1787     mergedData = _reduce_mergeFn(CpvAccess(_reduce_data), CpvAccess(_reduce_msg_list), CpvAccess(_reduce_num_children));
1788     for (i=0; i<CpvAccess(_reduce_num_children); ++i) CmiFree((char *)(CpvAccess(_reduce_msg_list)[i]) - offset);
1789   }
1790   CpvAccess(_reduce_num_children) = 0;
1791   CpvAccess(_reduce_received) = 0;
1792   msg = mergedData;
1793   msg_size = CpvAccess(_reduce_data_size);
1794   if (CmiMyPe() != 0) {
1795     if (_reduce_pupFn != NULL) {
1796       pup_er p = pup_new_sizer();
1797       _reduce_pupFn(p, mergedData);
1798       msg_size = pup_size(p) + CmiMsgHeaderSizeBytes;
1799       pup_destroy(p);
1800       msg = CmiAlloc(msg_size);
1801       p = pup_new_toMem((void*)(((char*)msg)+CmiMsgHeaderSizeBytes));
1802       _reduce_pupFn(p, mergedData);
1803       pup_destroy(p);
1804       if (_reduce_deleteFn != NULL) _reduce_deleteFn(CpvAccess(_reduce_data));
1805     }
1806     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
1807     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,CpvAccess(_reduce_parent));*/
1808     CmiSyncSendAndFree(CpvAccess(_reduce_parent), msg_size, msg);
1809   } else {
1810     _reduce_destination(msg);
1811   }
1812 }
1813
1814 void CmiReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
1815   CpvAccess(_reduce_data) = data;
1816   CpvAccess(_reduce_data_size) = size;
1817   CpvAccess(_reduce_parent) = CmiSpanTreeParent(CmiMyPe());
1818   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
1819   _reduce_pupFn = NULL;
1820   _reduce_mergeFn = mergeFn;
1821   CpvAccess(_reduce_num_children) = CmiNumSpanTreeChildren(CmiMyPe());
1822   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
1823 }
1824
1825 void CmiReduceStruct(void *data, void (*pupFn)(void*,void*),
1826                      void * (*mergeFn)(void*,void**,int), CmiHandler dest,
1827                      void (*deleteFn)(void*)) {
1828   CpvAccess(_reduce_data) = data;
1829   CpvAccess(_reduce_parent) = CmiSpanTreeParent(CmiMyPe());
1830   _reduce_destination = dest;
1831   _reduce_pupFn = pupFn;
1832   _reduce_mergeFn = mergeFn;
1833   _reduce_deleteFn = deleteFn;
1834   CpvAccess(_reduce_num_children) = CmiNumSpanTreeChildren(CmiMyPe());
1835   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
1836   /*else CmiPrintf("CmiReduceStruct(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
1837 }
1838
1839 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
1840   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
1841   CpvAccess(_reduce_data) = data;
1842   CpvAccess(_reduce_data_size) = size;
1843   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
1844   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
1845   _reduce_pupFn = NULL;
1846   _reduce_mergeFn = mergeFn;
1847   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
1848   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
1849 }
1850
1851 void CmiNodeReduceStruct(void *data, void (*pupFn)(void*,void*),
1852                          void * (*mergeFn)(void*,void**,int), CmiHandler dest,
1853                          void (*deleteFn)(void*)) {
1854   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
1855   CpvAccess(_reduce_data) = data;
1856   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
1857   _reduce_destination = dest;
1858   _reduce_pupFn = pupFn;
1859   _reduce_mergeFn = mergeFn;
1860   _reduce_deleteFn = deleteFn;
1861   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
1862   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
1863 }
1864
1865 void CmiHandleReductionMessage(void *msg) {
1866   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
1867   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
1868   /*else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
1869 }
1870
1871 /*****************************************************************************
1872  *
1873  * Multicast groups
1874  *
1875  ****************************************************************************/
1876
1877 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
1878
1879 typedef struct GroupDef
1880 {
1881   union {
1882     char core[CmiMsgHeaderSizeBytes];
1883     struct GroupDef *next;
1884   } core;
1885   CmiGroup group;
1886   int npes;
1887   int pes[1];
1888 }
1889 *GroupDef;
1890
1891 #define GROUPTAB_SIZE 101
1892
1893 CpvStaticDeclare(int, CmiGroupHandlerIndex);
1894 CpvStaticDeclare(int, CmiGroupCounter);
1895 CpvStaticDeclare(GroupDef *, CmiGroupTable);
1896
1897 void CmiGroupHandler(GroupDef def)
1898 {
1899   /* receive group definition, insert into group table */
1900   GroupDef *table = CpvAccess(CmiGroupTable);
1901   unsigned int hashval, bucket;
1902   hashval = (def->group.id ^ def->group.pe);
1903   bucket = hashval % GROUPTAB_SIZE;
1904   def->core.next = table[bucket];
1905   table[bucket] = def;
1906 }
1907
1908 CmiGroup CmiEstablishGroup(int npes, int *pes)
1909 {
1910   /* build new group definition, broadcast it */
1911   CmiGroup grp; GroupDef def; int len, i;
1912   grp.id = CpvAccess(CmiGroupCounter)++;
1913   grp.pe = CmiMyPe();
1914   len = sizeof(struct GroupDef)+(npes*sizeof(int));
1915   def = (GroupDef)CmiAlloc(len);
1916   def->group = grp;
1917   def->npes = npes;
1918   for (i=0; i<npes; i++)
1919     def->pes[i] = pes[i];
1920   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
1921   CmiSyncBroadcastAllAndFree(len, def);
1922   return grp;
1923 }
1924
1925 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
1926 {
1927   unsigned int hashval, bucket;  GroupDef def;
1928   GroupDef *table = CpvAccess(CmiGroupTable);
1929   hashval = (grp.id ^ grp.pe);
1930   bucket = hashval % GROUPTAB_SIZE;
1931   for (def=table[bucket]; def; def=def->core.next) {
1932     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
1933       *npes = def->npes;
1934       *pes = def->pes;
1935       return;
1936     }
1937   }
1938   *npes = 0; *pes = 0;
1939 }
1940
1941 void CmiGroupInit()
1942 {
1943   CpvInitialize(int, CmiGroupHandlerIndex);
1944   CpvInitialize(int, CmiGroupCounter);
1945   CpvInitialize(GroupDef *, CmiGroupTable);
1946   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
1947   CpvAccess(CmiGroupCounter) = 0;
1948   CpvAccess(CmiGroupTable) =
1949     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
1950   if (CpvAccess(CmiGroupTable) == 0)
1951     CmiAbort("Memory Allocation Error");
1952 }
1953
1954 #endif
1955
1956 /*****************************************************************************
1957  *
1958  * Common List-Cast and Multicast Code
1959  *
1960  ****************************************************************************/
1961
1962 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
1963
1964 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
1965 {
1966   int i;
1967   for(i=0;i<npes;i++) {
1968     CmiSyncSend(pes[i], len, msg);
1969   }
1970 }
1971
1972 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
1973 {
1974   /* A better asynchronous implementation may be wanted, but at least it works */
1975   CmiSyncListSendFn(npes, pes, len, msg);
1976   return (CmiCommHandle) 0;
1977 }
1978
1979 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
1980 {
1981   int i;
1982   for(i=0;i<npes-1;i++) {
1983     CmiSyncSend(pes[i], len, msg);
1984   }
1985   if (npes)
1986     CmiSyncSendAndFree(pes[npes-1], len, msg);
1987   else 
1988     CmiFree(msg);
1989 }
1990
1991 #endif
1992
1993 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
1994
1995 typedef struct MultiMsg
1996 {
1997   char core[CmiMsgHeaderSizeBytes];
1998   CmiGroup group;
1999   int pos;
2000   int origlen;
2001 }
2002 *MultiMsg;
2003
2004 CpvDeclare(int, CmiMulticastHandlerIndex);
2005
2006 void CmiMulticastDeliver(MultiMsg msg)
2007 {
2008   int npes, *pes; int olen, nlen, pos, child1, child2;
2009   olen = msg->origlen;
2010   nlen = olen + sizeof(struct MultiMsg);
2011   CmiLookupGroup(msg->group, &npes, &pes);
2012   if (pes==0) {
2013     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2014     return;
2015   }
2016   if (npes==0) {
2017     CmiFree(msg);
2018     return;
2019   }
2020   if (msg->pos == -1) {
2021     msg->pos=0;
2022     CmiSyncSendAndFree(pes[0], nlen, msg);
2023     return;
2024   }
2025   pos = msg->pos;
2026   child1 = ((pos+1)<<1);
2027   child2 = child1-1;
2028   if (child1 < npes) {
2029     msg->pos = child1;
2030     CmiSyncSend(pes[child1], nlen, msg);
2031   }
2032   if (child2 < npes) {
2033     msg->pos = child2;
2034     CmiSyncSend(pes[child2], nlen, msg);
2035   }
2036   if(olen < sizeof(struct MultiMsg)) {
2037     memcpy(msg, msg+1, olen);
2038   } else {
2039     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
2040   }
2041   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2042 }
2043
2044 void CmiMulticastHandler(MultiMsg msg)
2045 {
2046   CmiMulticastDeliver(msg);
2047 }
2048
2049 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2050 {
2051   int newlen; MultiMsg newmsg;
2052   newlen = len + sizeof(struct MultiMsg);
2053   newmsg = (MultiMsg)CmiAlloc(newlen);
2054   if(len < sizeof(struct MultiMsg)) {
2055     memcpy(newmsg+1, msg, len);
2056   } else {
2057     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
2058     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
2059   }
2060   newmsg->group = grp;
2061   newmsg->origlen = len;
2062   newmsg->pos = -1;
2063   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2064   CmiMulticastDeliver(newmsg);
2065 }
2066
2067 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2068 {
2069   CmiSyncMulticastFn(grp, len, msg);
2070   CmiFree(msg);
2071 }
2072
2073 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2074 {
2075   CmiError("Async Multicast not implemented.");
2076   return (CmiCommHandle) 0;
2077 }
2078
2079 void CmiMulticastInit()
2080 {
2081   CpvInitialize(int, CmiMulticastHandlerIndex);
2082   CpvAccess(CmiMulticastHandlerIndex) =
2083     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2084 }
2085
2086 #endif
2087
2088 /***************************************************************************
2089  *
2090  * Memory Allocation routines 
2091  *
2092  * A block of memory can consist of multiple chunks.  Each chunk has
2093  * a sizefield and a refcount.  The first chunk's refcount is a reference
2094  * count.  That's how many CmiFrees it takes to free the message.
2095  * Subsequent chunks have a refcount which is less than zero.  This is
2096  * the offset back to the start of the first chunk.
2097  *
2098  * Each chunk has a CmiChunkHeader before the user data, with the fields:
2099  *
2100  *  size: The user-allocated size of the chunk, in bytes.
2101  *
2102  *  ref: A magic reference count object. Ordinary blocks start with
2103  *     reference count 1.  When the reference count reaches zero,
2104  *     the block is deleted.  To support nested buffers, the 
2105  *     reference count can also be negative, which means it is 
2106  *     a byte offset to the enclosing buffer's reference count.
2107  *
2108  ***************************************************************************/
2109
2110
2111 void *CmiAlloc(int size)
2112 {
2113   char *res;
2114
2115 #if CONVERSE_VERSION_ELAN
2116   res = (char *) elan_CmiAlloc(size+sizeof(CmiChunkHeader));
2117 #elif CONVERSE_VERSION_VMI
2118   res = (char *) CMI_VMI_CmiAlloc(size+sizeof(CmiChunkHeader));
2119 #elif CMK_USE_IBVERBS
2120         res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
2121 #elif CONVERSE_POOL
2122   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
2123 #else
2124   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
2125 #endif
2126
2127   _MEMCHECK(res);
2128
2129 #ifdef MEMMONITOR
2130   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
2131   CpvAccess(AllocCount)++;
2132   CpvAccess(BlocksAllocated)++;
2133   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
2134     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
2135   }
2136   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
2137     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2138             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2139             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2140     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
2141   }
2142   if ((CpvAccess(AllocCount) % 1000) == 0) {
2143     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2144             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2145             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2146   }
2147 #endif
2148
2149   res+=sizeof(CmiChunkHeader);
2150   SIZEFIELD(res)=size;
2151   REFFIELD(res)=1;
2152   return (void *)res;
2153 }
2154
2155 /** Follow the header links out to the most enclosing block */
2156 static void *CmiAllocFindEnclosing(void *blk) {
2157   int refCount = REFFIELD(blk);
2158   while (refCount < 0) {
2159     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
2160     refCount = REFFIELD(blk);
2161   }
2162   return blk;
2163 }
2164
2165 /** Increment the reference count for this block's owner.
2166     This call must be matched by an equivalent CmiFree. */
2167 void CmiReference(void *blk)
2168 {
2169   REFFIELD(CmiAllocFindEnclosing(blk))++;
2170 }
2171
2172 /** Return the size of the user portion of this block. */
2173 int CmiSize(void *blk)
2174 {
2175   return SIZEFIELD(blk);
2176 }
2177
2178 /** Decrement the reference count for this block. */
2179 void CmiFree(void *blk)
2180 {
2181   void *parentBlk=CmiAllocFindEnclosing(blk);
2182   int refCount=REFFIELD(parentBlk);
2183 #ifndef CMK_OPTIMIZE
2184   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
2185     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
2186 #endif
2187   refCount--;
2188   REFFIELD(parentBlk) = refCount;
2189   if(refCount==0) { /* This was the last reference to the block-- free it */
2190 #ifdef MEMMONITOR
2191     int size=SIZEFIELD(parentBlk);
2192     if (size > 1000000000) /* Absurdly large size field-- warning */
2193       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
2194     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader);
2195     CpvAccess(BlocksAllocated)--;
2196 #endif
2197
2198 #if CONVERSE_VERSION_ELAN
2199     elan_CmiFree(BLKSTART(parentBlk));
2200 #elif CONVERSE_VERSION_VMI
2201     CMI_VMI_CmiFree(BLKSTART(parentBlk));
2202 #elif CMK_USE_IBVERBS
2203                 infi_CmiFree(BLKSTART(parentBlk));
2204 #elif CONVERSE_POOL
2205     CmiPoolFree(BLKSTART(parentBlk));
2206 #else
2207     free_nomigrate(BLKSTART(parentBlk));
2208 #endif
2209   }
2210 }
2211
2212
2213 /***************************************************************************
2214  *
2215  * Temporary-memory Allocation routines 
2216  *
2217  *  This buffer augments the storage available on the regular machine stack
2218  * for fairly large temporary buffers, which allows us to use smaller machine
2219  * stacks.
2220  *
2221  ***************************************************************************/
2222
2223 #define CMI_TMP_BUF_MAX 128*1024 /* Allow this much temporary storage. */
2224
2225 typedef struct {
2226   char *buf; /* Start of temporary buffer */
2227   int cur; /* First unused location in temporary buffer */
2228   int max; /* Length of temporary buffer */
2229 } CmiTmpBuf_t;
2230 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
2231
2232 static void CmiTmpSetup(CmiTmpBuf_t *b) {
2233   b->buf=malloc(CMI_TMP_BUF_MAX);
2234   b->cur=0;
2235   b->max=CMI_TMP_BUF_MAX;
2236 }
2237
2238 void *CmiTmpAlloc(int size) {
2239   if (!CpvInitialized(CmiTmpBuf)) {
2240     return malloc(size);
2241   }
2242   else { /* regular case */
2243     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
2244     void *t;
2245     if (b->cur+size>b->max) {
2246       if (b->max==0) /* We're just uninitialized */
2247         CmiTmpSetup(b);
2248       else /* We're really out of space! */
2249         CmiAbort("CmiTmpAlloc: asked for too much temporary buffer space");
2250     }
2251     t=b->buf+b->cur;
2252     b->cur+=size;
2253     return t;
2254   }
2255 }
2256 void CmiTmpFree(void *t) {
2257   if (!CpvInitialized(CmiTmpBuf)) {
2258     free(t);
2259   }
2260   else { /* regular case */
2261     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
2262     /* t should point into our temporary buffer: figure out where */
2263     int cur=((const char *)t)-b->buf;
2264 #ifndef CMK_OPTIMIZE
2265     if (cur<0 || cur>b->max)
2266       CmiAbort("CmiTmpFree: called with an invalid pointer");
2267 #endif
2268     b->cur=cur;
2269   }
2270 }
2271
2272 void CmiTmpInit(char **argv) {
2273   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
2274   /* Set up this processor's temporary buffer */
2275   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
2276 }
2277
2278 /******************************************************************************
2279
2280   Cross-platform directory creation
2281
2282   ****************************************************************************/
2283 #ifdef _MSC_VER
2284 /* Windows directory creation: */
2285 #include <windows.h>
2286
2287 void CmiMkdir(const char *dirName) {
2288         CreateDirectory(dirName,NULL);
2289 }
2290
2291 #else /* !_MSC_VER */
2292 /* UNIX directory creation */
2293 #include <unistd.h> 
2294 #include <sys/stat.h> /* from "mkdir" man page */
2295 #include <sys/types.h>
2296
2297 void CmiMkdir(const char *dirName) {
2298         mkdir(dirName,0777);
2299 }
2300
2301 #endif
2302
2303
2304 /******************************************************************************
2305
2306   Multiple Send function                               
2307
2308   ****************************************************************************/
2309
2310 CpvDeclare(int, CmiMainHandlerIDP); /* Main handler that is run on every node */
2311
2312 /****************************************************************************
2313 * DESCRIPTION : This function call allows the user to send multiple messages
2314 *               from one processor to another, all intended for differnet 
2315 *               handlers.
2316 *
2317 *               Parameters :
2318 *
2319 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
2320 *
2321 ****************************************************************************/
2322 /* Round up message size to the message granularity. 
2323    Does this by adding, then truncating.
2324 */
2325 static int roundUpSize(unsigned int s) {
2326   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
2327 }
2328 /* Return the amount of message padding required for a message
2329    with this many user bytes. 
2330  */
2331 static int paddingSize(unsigned int s) {
2332   return roundUpSize(s)-s;
2333 }
2334
2335 /* Message header for a bundle of multiple-sent messages */
2336 typedef struct {
2337   char convHeader[CmiMsgHeaderSizeBytes];
2338   int nMessages; /* Number of distinct messages bundled below. */
2339   double pad; /* To align the first message, which follows this header */
2340 } CmiMultipleSendHeader;
2341
2342 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
2343 {
2344   CmiMultipleSendHeader header;
2345   int m; /* Outgoing message */
2346   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
2347   double pad = 0; /* padding required */
2348   int vecLen; /* Number of pieces in outgoing message vector */
2349   int *vecSizes; /* Sizes of each piece we're sending out. */
2350   char **vecPtrs; /* Pointers to each piece we're sending out. */
2351   int vec; /* Entry we're currently filling out in above array */
2352
2353   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
2354   /* Allocate memory for the outgoing vector*/
2355   vecLen=1+3*len; /* Header and 3 parts per message */
2356   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
2357   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
2358   vec=0;
2359   
2360   /* Build the header */
2361   header.nMessages=len;
2362   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
2363 #if CMK_IMMEDIATE_MSG
2364   if (immed) CmiBecomeImmediate(&header);
2365 #endif
2366   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
2367   vec++;
2368
2369   /* Build an entry for each message: 
2370          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
2371   */
2372   for (m=0;m<len;m++) {
2373     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
2374     msgHdr[m].ref=0; /* Reference count will be filled out on receive side */
2375     
2376     /* First send the message's CmiChunkHeader (for use on receive side) */
2377     vecSizes[vec]=sizeof(CmiChunkHeader); vecPtrs[vec]=(char *)&msgHdr[m];
2378     vec++;
2379     
2380     /* Now send the actual message data */
2381     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
2382     vec++;
2383     
2384     /* Now send padding to align the next message on a double-boundary */
2385     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
2386     vec++;
2387   }
2388   CmiAssert(vec==vecLen);
2389   
2390   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
2391   
2392   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
2393   CmiTmpFree(vecSizes);
2394   CmiTmpFree(msgHdr);
2395 }
2396
2397 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
2398 {
2399   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
2400 }
2401
2402 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
2403 {
2404   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
2405 }
2406
2407 /****************************************************************************
2408 * DESCRIPTION : This function initializes the main handler required for the
2409 *               CmiMultipleSend() function to work. 
2410 *               
2411 *               This function should be called once in any Converse program
2412 *               that uses CmiMultipleSend()
2413 *
2414 ****************************************************************************/
2415
2416 static void CmiMultiMsgHandler(char *msgWhole);
2417
2418 void CmiInitMultipleSend(void)
2419 {
2420   CpvInitialize(int,CmiMainHandlerIDP); 
2421   CpvAccess(CmiMainHandlerIDP) =
2422     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
2423 }
2424
2425 /****************************************************************************
2426 * DESCRIPTION : This function is the main handler that splits up the messages
2427 *               CmiMultipleSend() pastes together. 
2428 *
2429 ****************************************************************************/
2430
2431 static void CmiMultiMsgHandler(char *msgWhole)
2432 {
2433   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
2434   int offset=sizeof(CmiMultipleSendHeader);
2435   int m;
2436   for (m=0;m<len;m++) {
2437     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
2438     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
2439     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
2440     /* Link new message to owner via a negative ref pointer */
2441     ch->ref=msgWhole-msg; 
2442     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
2443     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
2444     offset+= sizeof(CmiChunkHeader) + msgSize;
2445   }
2446   /* Release our reference to the whole message.  The message will
2447      only actually be deleted once all its sub-messages are free'd as well. */
2448   CmiFree(msgWhole);
2449 }
2450
2451 /****************************************************************************
2452 * Hypercube broadcast message passing.
2453 ****************************************************************************/
2454
2455 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
2456   int num_pes = 0;
2457   for ( ; k>=0; --k) {
2458     /* add the processor destination at level k if it exist */
2459     dest_pes[num_pes] = mype ^ (1<<k);
2460     if (dest_pes[num_pes] >= total_pes) {
2461       /* find the first proc in the other part of the current dimention */
2462       dest_pes[num_pes] &= (-1)<<k;
2463       /* if the first proc there is over CmiNumPes() then there is no other
2464          dimension, otherwise if it is valid compute my correspondent in such
2465          a way to minimize the load for every processor */
2466       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((-1)<<k))) % (total_pes - dest_pes[num_pes]);
2467       }
2468     if (dest_pes[num_pes] < total_pes) {
2469       /* if the destination is in the acceptable range increment num_pes */
2470       ++num_pes;
2471     }
2472   }
2473   return num_pes;
2474 }
2475
2476
2477 /****************************************************************************
2478 * DESCRIPTION : This function initializes the main handler required for the
2479 *               Immediate message
2480 *               
2481 *               This function should be called once in any Converse program
2482 *
2483 ****************************************************************************/
2484
2485 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
2486 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
2487
2488 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
2489
2490 /* xdl is the real handler */
2491 static void CmiImmediateMsgHandler(char *msg)
2492 {
2493   CmiSetHandler(msg, CmiGetXHandler(msg));
2494   CmiHandleMessage(msg);
2495 }
2496
2497 void CmiInitImmediateMsg(void)
2498 {
2499   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
2500   CpvAccess(CmiImmediateMsgHandlerIdx) =
2501     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
2502 }
2503
2504 #if !CMK_IMMEDIATE_MSG
2505 #if !CMK_MACHINE_PROGRESS_DEFINED
2506 void CmiProbeImmediateMsg()
2507 {
2508 }
2509 #endif
2510 #endif 
2511
2512 /******** Idle timeout module (+idletimeout=30) *********/
2513
2514 typedef struct {
2515   int idle_timeout;/*Milliseconds to wait idle before aborting*/
2516   int is_idle;/*Boolean currently-idle flag*/
2517   int call_count;/*Number of timeout calls currently in flight*/
2518 } cmi_cpu_idlerec;
2519
2520 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
2521 {
2522   rec->call_count--;
2523   if(rec->call_count==0 && rec->is_idle==1) {
2524     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
2525     CmiAbort("Exiting.\n");
2526   }
2527 }
2528 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
2529 {
2530   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
2531   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
2532   rec->is_idle = 1;
2533 }
2534 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
2535 {
2536   rec->is_idle = 0;
2537 }
2538 static void CIdleTimeoutInit(char **argv)
2539 {
2540   int idle_timeout=0; /*Seconds to wait*/
2541   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
2542   if(idle_timeout != 0) {
2543     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
2544     _MEMCHECK(rec);
2545     rec->idle_timeout=idle_timeout*1000;
2546     rec->is_idle=0;
2547     rec->call_count=0;
2548     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
2549     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
2550   }
2551 }
2552
2553 /*****************************************************************************
2554  *
2555  * Converse Initialization
2556  *
2557  *****************************************************************************/
2558
2559 extern void CrnInit(void);
2560 extern void CmiIsomallocInit(char **argv);
2561 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
2562 void CmiIOInit(char **argv);
2563 #endif
2564
2565 static void CmiProcessPriority(char **argv)
2566 {
2567   int dummy, nicelevel=-100;      /* process priority */
2568   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
2569   /* ignore others */
2570   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
2571   /* call setpriority once on each process to set process's priority */
2572   if (CmiMyRank() == 0 && nicelevel != -100)  {
2573 #ifndef _WIN32
2574     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
2575       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
2576       perror("setpriority");
2577       CmiAbort("setpriority failed.");
2578     }
2579     else
2580       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
2581 #else
2582     HANDLE hProcess = GetCurrentProcess();
2583     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
2584     char *prio_str = "NORMAL_PRIORITY_CLASS";
2585     BOOL status;
2586     /*
2587        <-20:      real time
2588        -20--10:   high 
2589        -10-0:     above normal
2590        0:         normal
2591        0-10:      below normal
2592        10-:       idle
2593     */
2594     if (0) ;
2595 #ifdef BELOW_NORMAL_PRIORITY_CLASS
2596     else if (nicelevel<10 && nicelevel>0) {
2597       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
2598       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
2599     }
2600 #endif
2601     else if (nicelevel>0) {
2602       dwPriorityClass = IDLE_PRIORITY_CLASS;
2603       prio_str = "IDLE_PRIORITY_CLASS";
2604     }
2605     else if (nicelevel<=-20) {
2606       dwPriorityClass = REALTIME_PRIORITY_CLASS;
2607       prio_str = "REALTIME_PRIORITY_CLASS";
2608     }
2609 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
2610     else if (nicelevel>-10 && nicelevel<0) {
2611       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
2612       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
2613     }
2614 #endif
2615     else if (nicelevel<0) {
2616       dwPriorityClass = HIGH_PRIORITY_CLASS;
2617       prio_str = "HIGH_PRIORITY_CLASS";
2618     }
2619     status = SetPriorityClass(hProcess, dwPriorityClass);
2620     if (!status)  {
2621         int err=GetLastError();
2622         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
2623         CmiAbort("SetPriorityClass failed.");
2624     }
2625     else
2626       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
2627 #endif
2628   }
2629 }
2630
2631 void CommunicationServerInit()
2632 {
2633 #if CMK_IMMEDIATE_MSG
2634   CQdCpvInit();
2635   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
2636 #endif
2637 }
2638
2639 /**
2640   Main Converse initialization routine.  This routine is 
2641   called by the machine file (machine.c) to set up Converse.
2642   It's "Common" because it's shared by all the machine.c files. 
2643   
2644   The main task of this routine is to set up all the Cpv's
2645   (message queues, handler tables, etc.) used during main execution.
2646   
2647   On SMP versions, this initialization routine is called by 
2648   *all* processors of a node simultaniously.  It's *also* called
2649   by the communication thread, which is rather strange but needed
2650   for immediate messages.  Each call to this routine expects a 
2651   different copy of the argv arguments, so use CmiCopyArgs(argv).
2652   
2653   Requires:
2654     - A working network layer.
2655     - Working Cpv's and CmiNodeBarrier.
2656     - CthInit to already have been called.  CthInit is called
2657       from the machine layer directly, because some machine layers
2658       (like uth) use Converse threads internally.
2659
2660   Initialization is somewhat subtle, in that various modules
2661   won't work properly until they're initialized.  For example,
2662   nobody can register handlers before calling CmiHandlerInit.
2663 */
2664 void ConverseCommonInit(char **argv)
2665 {
2666   CmiArgInit(argv);
2667   CmiMemoryInit(argv);
2668 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
2669   CmiIOInit(argv);
2670 #endif
2671 #if CONVERSE_POOL
2672   CmiPoolAllocInit(30);  
2673 #endif
2674   CmiTmpInit(argv);
2675   CmiTimerInit();
2676   CstatsInit(argv);
2677
2678   CcdModuleInit(argv);
2679   CmiHandlerInit();
2680   CmiReductionsInit();
2681   CIdleTimeoutInit(argv);
2682   
2683 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the net-*-smp versions*/
2684         if(CmiMyRank() == 0){
2685                 _Cmi_noprocforcommthread=0;
2686                 if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for net-smp-*) ?")){
2687                         _Cmi_noprocforcommthread=1;
2688                 }
2689         }
2690 #endif
2691         
2692 #ifndef CMK_OPTIMIZE
2693   traceInit(argv);
2694 /*initTraceCore(argv);*/ /* projector */
2695 #endif
2696   CmiProcessPriority(argv);
2697
2698 #if CMK_CCS_AVAILABLE
2699   CcsInit(argv);
2700 #endif
2701   CmiPersistentInit();
2702   CmiIsomallocInit(argv);
2703   CpdInit();
2704   CmiDeliversInit();
2705   CsdInit(argv);
2706   CthSchedInit();
2707   CmiGroupInit();
2708   CmiMulticastInit();
2709   CmiInitMultipleSend();
2710   CQdInit();
2711
2712   CrnInit();
2713   CmiInitImmediateMsg();
2714   CldModuleInit(argv);
2715   
2716 #if CMK_CELL
2717   void CmiInitCell();
2718   CmiInitCell();
2719 #endif
2720   /* main thread is suspendable */
2721 /*
2722   CthSetSuspendable(CthSelf(), 0);
2723 */
2724 }
2725
2726 void ConverseCommonExit(void)
2727 {
2728   CcsImpl_kill();
2729
2730 #ifndef CMK_OPTIMIZE
2731   traceClose();
2732 /*closeTraceCore();*/ /* projector */
2733 #endif
2734
2735 #if CMI_IO_BUFFER_EXPLICIT
2736   CmiFlush(stdout);  /* end of program, always flush */
2737 #endif
2738
2739 #if CMK_CELL
2740   CloseOffloadAPI();
2741 #endif
2742 }
2743
2744
2745 #if CMK_CELL
2746
2747 void CmiInitCell()
2748 {
2749   // Create a unique string for each PPE to use for the timing
2750   //   data file's name
2751   char fileNameBuf[128];
2752   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
2753
2754   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
2755   //CcdCallOnConditionKeep(CcdPERIODIC, 
2756   //      (CcdVoidFn) OffloadAPIProgress, NULL);
2757   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
2758       (CcdVoidFn) OffloadAPIProgress, NULL);
2759 }
2760
2761 #include "cell-api.c"
2762
2763 #endif
2764
2765 /****
2766  * CW Lee - 9/14/2005
2767  * Added a mechanism to allow some control over machines with extremely
2768  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
2769  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
2770  * coupled with a default setup using unbuffered stdout introduced
2771  * severe overheads (and hence limiting scaling) for applications like 
2772  * NAMD.
2773  */
2774 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
2775 void CmiIOInit(char **argv) {
2776   CpvInitialize(int, expIOFlushFlag);
2777 #if CMI_IO_BUFFER_EXPLICIT
2778   /* 
2779      Support for an explicit buffer only makes sense if the machine
2780      layer does not wish to make its own implementation.
2781
2782      Placing this after CmiMemoryInit() means that CmiMemoryInit()
2783      MUST NOT make use of stdout if an explicit buffer is requested.
2784
2785      The setvbuf function may only be used after opening a stream and
2786      before any other operations have been performed on it
2787   */
2788   CpvInitialize(char*, explicitIOBuffer);
2789   CpvInitialize(int, expIOBufferSize);
2790   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
2791                         "Explicit IO Buffer Size")) {
2792     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
2793   }
2794   if (CpvAccess(expIOBufferSize) <= 0) {
2795     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
2796   }
2797   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
2798                                                 sizeof(char));
2799   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
2800               CpvAccess(expIOBufferSize))) {
2801     CmiAbort("Explicit IO Buffering failed\n");
2802   }
2803 #endif
2804 #if CMI_IO_FLUSH_USER
2805   /* system default to have user control flushing of IO */
2806   /* Now look for user override */
2807   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
2808                                                  "System Controls IO Flush");
2809 #else
2810   /* system default to have system handle IO flushing */
2811   /* Now look for user override */
2812   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
2813                                                 "User Controls IO Flush");
2814 #endif
2815 }
2816 #endif
2817
2818 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
2819
2820 void CmiPrintf(const char *format, ...)
2821 {
2822   va_list args;
2823   va_start(args,format);
2824   vfprintf(stdout,format, args);
2825   if (!CpvAccess(expIOFlushFlag)) {
2826     CmiFlush(stdout);
2827   }
2828   va_end(args);
2829 }
2830
2831 void CmiError(const char *format, ...)
2832 {
2833   va_list args;
2834   va_start(args,format);
2835   vfprintf(stderr,format, args);
2836   CmiFlush(stderr);  /* stderr is always flushed */
2837   va_end(args);
2838 }
2839
2840 #endif
2841
2842 void __cmi_assert(const char *expr, const char *file, int line)
2843 {
2844   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
2845       CmiMyPe(), expr, file, line);
2846   CmiAbort("");
2847 }
2848
2849 char *CmiCopyMsg(char *msg, int len)
2850 {
2851   char *copy = (char *)CmiAlloc(len);
2852   _MEMCHECK(copy);
2853   memcpy(copy, msg, len);
2854   return copy;
2855 }
2856
2857 unsigned char computeCheckSum(unsigned char *data, int len)
2858 {
2859   int i;
2860   unsigned char ret = 0;
2861   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
2862   return ret;
2863 }
2864
2865 /*@}*/