Add a flag to provide timer for the case of no objs in Meta-Balancer
[charm.git] / src / conv-core / convcore.c
1 /** 
2   @defgroup Converse
3   \brief Converse--a parallel portability layer.
4
5   Converse is the lowest level inside the Charm++ hierarchy. It stands on top
6   of the machine layer, and it provides all the common functionality across
7   platforms.
8
9   One converse program is running on every processor (or node in the smp
10   version). it manages the message transmission, and the memory allocation.
11   Charm++, which is on top of Converse, uses its functionality for
12   interprocess *communication.
13
14   In order to maintain multiple independent objects inside a single user space
15   program, it uses a personalized version of threads, which can be executed,
16   suspended, and migrated across processors.
17
18   It provides a scheduler for message delivery: methods can be registered to
19   the scheduler, and then messages allocated through CmiAlloc can be sent to
20   the correspondent method in a remote processor. This is done through the
21   converse header (which has few common fields, but is architecture dependent).
22
23   @defgroup ConverseScheduler 
24   \brief The portion of Converse responsible for scheduling the execution of 
25   incoming messages.
26   
27   Converse provides a scheduler for message delivery: methods can be registered to 
28   the scheduler, and then messages allocated through CmiAlloc can be sent to 
29   the correspondent method in a remote processor. This is done through the
30   converse header (which has few common fields, but is architecture dependent).
31
32   In converse the CsdScheduleForever() routine will run an infinite while loop that
33   looks for available messages to process from the unprocessed message queues. The
34   details of the queues and the order in which they are emptied is hidden behind
35   CsdNextMessage(), which is used to dequeue the next message for processing by the
36   converse scheduler. When a message is taken from the queue it is then passed into
37   CmiHandleMessage() which calls the handler associated with the message.
38
39   Incoming messages that are destined for Charm++ will be passed to the 
40   \ref CharmScheduler "charm scheduling routines".
41
42   @file
43   converse main core
44   @ingroup Converse
45   @ingroup ConverseScheduler
46  
47   @addtogroup Converse
48   @{
49
50 */
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <errno.h>
56 #ifndef _WIN32
57 #include <sys/time.h>
58 #include <sys/resource.h>
59 #endif
60
61 #include "converse.h"
62 #include "conv-trace.h"
63 #include "sockRoutines.h"
64 #include "queueing.h"
65 #include "conv-ccs.h"
66 #include "ccs-server.h"
67 #include "memory-isomalloc.h"
68 #if CMK_PROJECTOR
69 #include "converseEvents.h"             /* projector */
70 #include "traceCoreCommon.h"    /* projector */
71 #include "machineEvents.h"     /* projector */
72 #endif
73
74 extern const char * const CmiCommitID;
75
76 #if CMK_OUT_OF_CORE
77 #include "conv-ooc.h"
78 #endif
79
80 #if CONVERSE_POOL
81 #include "cmipool.h"
82 #endif
83
84 #if CMK_CONDS_USE_SPECIAL_CODE
85 CmiSwitchToPEFnPtr CmiSwitchToPE;
86 #endif
87
88 CpvExtern(int, _traceCoreOn);   /* projector */
89 extern void CcdModuleInit(char **);
90 extern void CmiMemoryInit(char **);
91 extern void CldModuleInit(char **);
92
93 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
94 #include <sys/types.h>
95 #include <sys/time.h>
96 #endif
97
98 #if CMK_TIMER_USE_TIMES
99 #include <sys/times.h>
100 #include <limits.h>
101 #include <unistd.h>
102 #endif
103
104 #if CMK_TIMER_USE_GETRUSAGE
105 #include <sys/time.h>
106 #include <sys/resource.h>
107 #endif
108
109 #if CMK_TIMER_USE_RDTSC
110 #include <string.h>
111 #include <unistd.h>
112 #include <time.h>
113 #include <stdio.h>
114 #include <sys/time.h>
115 #include <sys/resource.h>
116 #endif
117
118 #ifdef CMK_TIMER_USE_WIN32API
119 #include <stdlib.h>
120 #include <time.h>
121 #include <sys/types.h>
122 #include <sys/timeb.h>
123 #endif
124
125 #ifdef CMK_HAS_ASCTIME
126 #include <time.h>
127 #endif
128
129 #ifdef CMK_CUDA
130 #include "cuda-hybrid-api.h"
131 #endif
132
133 #include "quiescence.h"
134
135 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
136 #include <mpi.h>
137 #endif
138
139 //int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
140 CpvDeclare(int,_curRestartPhase);
141 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
142
143 int CharmLibInterOperate = 0;
144 CpvDeclare(int,charmLibExitFlag);
145
146 CpvStaticDeclare(int, CmiMainHandlerIDP); /* Main handler for _CmiMultipleSend that is run on every node */
147
148 #if CMK_MEM_CHECKPOINT
149 void (*notify_crash_fn)(int) = NULL;
150 #endif
151
152 CpvDeclare(char *, _validProcessors);
153
154 /*****************************************************************************
155  *
156  * Unix Stub Functions
157  *
158  ****************************************************************************/
159
160 #ifdef MEMMONITOR
161 typedef unsigned long mmulong;
162 CpvDeclare(mmulong,MemoryUsage);
163 CpvDeclare(mmulong,HiWaterMark);
164 CpvDeclare(mmulong,ReportedHiWaterMark);
165 CpvDeclare(int,AllocCount);
166 CpvDeclare(int,BlocksAllocated);
167 #endif
168
169 #define MAX_HANDLERS 512
170
171 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
172 CpvDeclare(int,expIOFlushFlag);
173 #if CMI_IO_BUFFER_EXPLICIT
174 /* 250k not too large depending on how slow terminal IO is */
175 #define DEFAULT_IO_BUFFER_SIZE 250000
176 CpvDeclare(char*,explicitIOBuffer);
177 CpvDeclare(int,expIOBufferSize);
178 #endif
179 #endif
180
181 #if CMK_NODE_QUEUE_AVAILABLE
182 void  *CmiGetNonLocalNodeQ();
183 #endif
184
185 CpvDeclare(void*, CsdSchedQueue);
186
187 #if CMK_OUT_OF_CORE
188 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
189 CpvDeclare(void*, CsdPrefetchQueue);
190 pthread_mutex_t prefetchLock;
191 #endif
192
193 #if CMK_NODE_QUEUE_AVAILABLE
194 CsvDeclare(void*, CsdNodeQueue);
195 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
196 #endif
197 CpvDeclare(int,   CsdStopFlag);
198 CpvDeclare(int,   CsdLocalCounter);
199
200 CpvDeclare(int,   _urgentSend);
201
202 CmiNodeLock _smp_mutex;               /* for smp */
203
204 #if CONVERSE_VERSION_VMI
205 void *CMI_VMI_CmiAlloc (int size);
206 void CMI_VMI_CmiFree (void *ptr);
207 #endif
208
209 #if CONVERSE_VERSION_ELAN
210 void* elan_CmiAlloc(int size);
211 #endif
212
213 #if CMK_USE_IBVERBS | CMK_USE_IBUD
214 void *infi_CmiAlloc(int size);
215 void infi_CmiFree(void *ptr);
216 void infi_freeMultipleSend(void *ptr);
217 void infi_unregAndFreeMeta(void *ch);
218 #endif
219
220 #if CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
221 void * CmiAlloc_bgq (int     size);
222 void   CmiFree_bgq  (void  * buf);
223 #endif
224
225 #if CMK_GRID_QUEUE_AVAILABLE
226 CpvDeclare(void *, CkGridObject);
227 CpvDeclare(void *, CsdGridQueue);
228 #endif
229
230 #if CMK_CRAYXE
231 void* LrtsAlloc(int, int);
232 void  LrtsFree(void*);
233 #endif
234
235 CpvStaticDeclare(int, cmiMyPeIdle);
236 int CmiIsMyNodeIdle();
237
238 /*****************************************************************************
239  *
240  * Command-Line Argument (CLA) parsing routines.
241  *
242  *****************************************************************************/
243
244 static int usageChecked=0; /* set when argv has been searched for a usage request */
245 static int printUsage=0; /* if set, print command-line usage information */
246 static const char *CLAformatString="%20s %10s %s\n";
247
248 /** This little list of CLA's holds the argument descriptions until it's
249    safe to print them--it's needed because the net- versions don't have 
250    printf until they're pretty well started.
251  */
252 typedef struct {
253         const char *arg; /* Flag name, like "-foo"*/
254         const char *param; /* Argument's parameter type, like "integer" or "none"*/
255         const char *desc; /* Human-readable description of what it does */
256 } CLA;
257 static int CLAlistLen=0;
258 static int CLAlistMax=0;
259 static CLA *CLAlist=NULL;
260
261 /** Add this CLA */
262 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
263         int i;
264         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
265         if (desc==NULL) return; /*It's an internal argument*/
266         if (usageChecked) { /* Printf should work now */
267                 if (printUsage)
268                         CmiPrintf(CLAformatString,arg,param,desc);
269         }
270         else { /* Printf doesn't work yet-- just add to the list.
271                 This assumes the const char *'s are static references,
272                 which is probably reasonable. */
273                 i=CLAlistLen++;
274                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
275                         CLAlistMax=16+2*CLAlistLen;
276                         CLAlist=realloc(CLAlist,sizeof(CLA)*CLAlistMax);\
277                 }
278                 CLAlist[i].arg=arg;
279                 CLAlist[i].param=param;
280                 CLAlist[i].desc=desc;
281         }
282 }
283
284 /** Print out the stored list of CLA's */
285 static void CmiPrintCLAs(void) {
286         int i;
287         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
288         CmiPrintf("Converse Machine Command-line Parameters:\n ");
289         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
290         for (i=0;i<CLAlistLen;i++) {
291                 CLA *c=&CLAlist[i];
292                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
293         }
294 }
295
296 /**
297  * Determines if command-line usage information should be printed--
298  * that is, if a "-?", "-h", or "--help" flag is present.
299  * Must be called after printf is setup.
300  */
301 void CmiArgInit(char **argv) {
302         int i;
303         for (i=0;argv[i]!=NULL;i++)
304         {
305                 if (0==strcmp(argv[i],"-?") ||
306                     0==strcmp(argv[i],"-h") ||
307                     0==strcmp(argv[i],"--help")) 
308                 {
309                         printUsage=1;
310                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
311                           Leave it there for user program to see... */
312                         CmiPrintCLAs();
313                 }
314         }
315         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
316                 CLAlistLen=CLAlistMax=0;
317                 free(CLAlist); CLAlist=NULL;
318         }
319         usageChecked=1;
320 }
321
322 /** Return 1 if we're currently printing command-line usage information. */
323 int CmiArgGivingUsage(void) {
324         return (CmiMyPe()==0) && printUsage;
325 }
326
327 /** Identifies the module that accepts the following command-line parameters */
328 void CmiArgGroup(const char *parentName,const char *groupName) {
329         if (CmiArgGivingUsage()) {
330                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
331                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
332         }
333 }
334
335 /** Count the number of non-NULL arguments in list*/
336 int CmiGetArgc(char **argv)
337 {
338         int i=0,argc=0;
339         if (argv)
340         while (argv[i++]!=NULL)
341                 argc++;
342         return argc;
343 }
344
345 /** Return a new, heap-allocated copy of the argv array*/
346 char **CmiCopyArgs(char **argv)
347 {
348         int argc=CmiGetArgc(argv);
349         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
350         int i;
351         for (i=0;i<=argc;i++)
352                 ret[i]=argv[i];
353         return ret;
354 }
355
356 /** Delete the first k argument from the given list, shifting
357 all other arguments down by k spaces.
358 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
359 argv={"d",NULL,"c","d",NULL}
360 */
361 void CmiDeleteArgs(char **argv,int k)
362 {
363         int i=0;
364         while ((argv[i]=argv[i+k])!=NULL)
365                 i++;
366 }
367
368 /** Find the given argment and string option in argv.
369 If the argument is present, set the string option and
370 delete both from argv.  If not present, return NULL.
371 e.g., arg=="-name" returns "bob" from
372 argv=={"a.out","foo","-name","bob","bar"},
373 and sets argv={"a.out","foo","bar"};
374 */
375 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
376 {
377         int i;
378         CmiAddCLA(arg,"string",desc);
379         for (i=0;argv[i]!=NULL;i++)
380                 if (0==strcmp(argv[i],arg))
381                 {/*We found the argument*/
382                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
383                         *optDest=argv[i+1];
384                         CmiDeleteArgs(&argv[i],2);
385                         return 1;
386                 }
387         return 0;/*Didn't find the argument*/
388 }
389 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
390         return CmiGetArgStringDesc(argv,arg,optDest,"");
391 }
392
393 /** Find the given argument and floating-point option in argv.
394 Remove it and return 1; or return 0.
395 */
396 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
397         char *number=NULL;
398         CmiAddCLA(arg,"number",desc);
399         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
400         if (1!=sscanf(number,"%lg",optDest)) return 0;
401         return 1;
402 }
403 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
404         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
405 }
406
407 /** Find the given argument and integer option in argv.
408 If the argument is present, parse and set the numeric option,
409 delete both from argv, and return 1. If not present, return 0.
410 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
411 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
412 but not argv=={...,"-packsize",...}.
413 */
414 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
415 {
416         int i;
417         int argLen=strlen(arg);
418         CmiAddCLA(arg,"integer",desc);
419         for (i=0;argv[i]!=NULL;i++)
420                 if (0==strncmp(argv[i],arg,argLen))
421                 {/*We *may* have found the argument*/
422                         const char *opt=NULL;
423                         int nDel=0;
424                         switch(argv[i][argLen]) {
425                         case 0: /* like "-p","27" */
426                                 opt=argv[i+1]; nDel=2; break;
427                         case '=': /* like "-p=27" */
428                                 opt=&argv[i][argLen+1]; nDel=1; break;
429                         case '-':case '+':
430                         case '0':case '1':case '2':case '3':case '4':
431                         case '5':case '6':case '7':case '8':case '9':
432                                 /* like "-p27" */
433                                 opt=&argv[i][argLen]; nDel=1; break;
434                         default:
435                                 continue; /*False alarm-- skip it*/
436                         }
437                         if (opt==NULL) continue; /*False alarm*/
438                         if (sscanf(opt,"%i",optDest)<1) {
439                         /*Bad command line argument-- die*/
440                                 fprintf(stderr,"Cannot parse %s option '%s' "
441                                         "as an integer.\n",arg,opt);
442                                 CmiAbort("Bad command-line argument\n");
443                         }
444                         CmiDeleteArgs(&argv[i],nDel);
445                         return 1;
446                 }
447         return 0;/*Didn't find the argument-- dest is unchanged*/       
448 }
449 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
450         return CmiGetArgIntDesc(argv,arg,optDest,"");
451 }
452
453 int CmiGetArgLongDesc(char **argv,const char *arg,CmiInt8 *optDest,const char *desc)
454 {
455         int i;
456         int argLen=strlen(arg);
457         CmiAddCLA(arg,"integer",desc);
458         for (i=0;argv[i]!=NULL;i++)
459                 if (0==strncmp(argv[i],arg,argLen))
460                 {/*We *may* have found the argument*/
461                         const char *opt=NULL;
462                         int nDel=0;
463                         switch(argv[i][argLen]) {
464                         case 0: /* like "-p","27" */
465                                 opt=argv[i+1]; nDel=2; break;
466                         case '=': /* like "-p=27" */
467                                 opt=&argv[i][argLen+1]; nDel=1; break;
468                         case '-':case '+':
469                         case '0':case '1':case '2':case '3':case '4':
470                         case '5':case '6':case '7':case '8':case '9':
471                                 /* like "-p27" */
472                                 opt=&argv[i][argLen]; nDel=1; break;
473                         default:
474                                 continue; /*False alarm-- skip it*/
475                         }
476                         if (opt==NULL) continue; /*False alarm*/
477                         if (sscanf(opt,"%ld",optDest)<1) {
478                         /*Bad command line argument-- die*/
479                                 fprintf(stderr,"Cannot parse %s option '%s' "
480                                         "as a long integer.\n",arg,opt);
481                                 CmiAbort("Bad command-line argument\n");
482                         }
483                         CmiDeleteArgs(&argv[i],nDel);
484                         return 1;
485                 }
486         return 0;/*Didn't find the argument-- dest is unchanged*/       
487 }
488 int CmiGetArgLong(char **argv,const char *arg,CmiInt8 *optDest) {
489         return CmiGetArgLongDesc(argv,arg,optDest,"");
490 }
491
492 /** Find the given argument in argv.  If present, delete
493 it and return 1; if not present, return 0.
494 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
495 argv={...,"-foobar",...}.
496 */
497 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
498 {
499         int i;
500         CmiAddCLA(arg,"",desc);
501         for (i=0;argv[i]!=NULL;i++)
502                 if (0==strcmp(argv[i],arg))
503                 {/*We found the argument*/
504                         CmiDeleteArgs(&argv[i],1);
505                         return 1;
506                 }
507         return 0;/*Didn't find the argument*/
508 }
509 int CmiGetArgFlag(char **argv,const char *arg) {
510         return CmiGetArgFlagDesc(argv,arg,"");
511 }
512
513
514 /*****************************************************************************
515  *
516  * Stack tracing routines.
517  *
518  *****************************************************************************/
519 #include "cmibacktrace.c"
520
521 /*
522 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
523 the next parenthesis.  Operates in-place on the character data.
524 or Convert X(Y) to "Y" only, when trimname=1
525 */
526 static char *_implTrimParenthesis(char *str, int trimname) {
527   char *lParen=str, *ret=NULL, *rParen=NULL;
528   while (*lParen!='(') {
529     if (*lParen==0) return str; /* No left parenthesis at all. */
530     lParen++;
531   }
532   /* now *lParen=='(', so trim it*/
533   ret=lParen+1;
534   rParen=ret;
535   while (*rParen!=')') {
536     if (*rParen==0) return ret; /* No right parenthesis at all. */
537     rParen++;
538   }
539   /* now *rParen==')', so trim it*/
540   *rParen=trimname?0:' ';
541   return ret;  
542 }
543
544 /*
545 Return the text description of this trimmed routine name, if 
546 it's a system-generated routine where we should stop printing. 
547 This is probably overkill, but improves the appearance of callbacks.
548 */
549 static const char* _implGetBacktraceSys(const char *name) {
550   if (0==strncmp(name,"_call",5)) 
551   { /*it might be something we're interested in*/
552     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
553     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
554   }
555   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
556   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
557   
558   return 0; /*ordinary user routine-- just print normally*/
559 }
560
561 /** Print out the names of these function pointers. */
562 void CmiBacktracePrint(void **retPtrs,int nLevels) {
563   if (nLevels>0) {
564     int i;
565     char **names=CmiBacktraceLookup(retPtrs,nLevels);
566     if (names==NULL) return;
567     CmiPrintf("[%d] Stack Traceback:\n", CmiMyPe());
568     for (i=0;i<nLevels;i++) {
569       if (names[i] == NULL) continue;
570       {
571       const char *trimmed=_implTrimParenthesis(names[i], 0);
572       const char *print=trimmed;
573       const char *sys=_implGetBacktraceSys(print);
574       if (sys) {
575           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
576           break; /*Stop when we hit Charm++ runtime.*/
577       } else {
578           CmiPrintf("  [%d:%d] %s\n",CmiMyPe(),i,print);
579       }
580      }
581     }
582     free(names);
583   }
584 }
585
586 /* Print (to stdout) the names of the functions that have been 
587    called up to this point. nSkip is the number of routines on the
588    top of the stack to *not* print out. */
589 void CmiPrintStackTrace(int nSkip) {
590 #if CMK_USE_BACKTRACE
591         int nLevels=max_stack;
592         void *stackPtrs[max_stack];
593         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
594         CmiBacktracePrint(stackPtrs,nLevels);
595 #endif
596 }
597
598 int CmiIsFortranLibraryCall() {
599 #if CMK_USE_BACKTRACE
600   int ret = 0;
601   int nLevels=9;
602   void *stackPtrs[18];
603   CmiBacktraceRecord(stackPtrs,1,&nLevels);
604   if (nLevels>0) {
605     int i;
606     char **names=CmiBacktraceLookup(stackPtrs,nLevels);
607     if (names==NULL) return 0;
608     for (i=0;i<nLevels;i++) {
609       if (names[i] == NULL) continue;
610       const char *trimmed=_implTrimParenthesis(names[i], 1);
611       if (strncmp(trimmed, "for__", 5) == 0                /* ifort */
612           || strncmp(trimmed, "_xlf", 4) == 0               /* xlf90 */
613           || strncmp(trimmed, "_xlfBeginIO", 11) == 0 
614           || strncmp(trimmed, "_gfortran_", 10) == 0 
615          )
616           {  /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
617              ret = 1; break; }
618     }
619     free(names);
620   }
621   return ret;
622 #else
623   return 0;
624 #endif
625 }
626
627 /*****************************************************************************
628  *
629  * Statistics: currently, the following statistics are not updated by converse.
630  *
631  *****************************************************************************/
632
633 CpvDeclare(int, CstatsMaxChareQueueLength);
634 CpvDeclare(int, CstatsMaxForChareQueueLength);
635 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
636 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
637 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
638
639 void CstatsInit(argv)
640 char **argv;
641 {
642
643 #ifdef MEMMONITOR
644   CpvInitialize(mmulong,MemoryUsage);
645   CpvAccess(MemoryUsage) = 0;
646   CpvInitialize(mmulong,HiWaterMark);
647   CpvAccess(HiWaterMark) = 0;
648   CpvInitialize(mmulong,ReportedHiWaterMark);
649   CpvAccess(ReportedHiWaterMark) = 0;
650   CpvInitialize(int,AllocCount);
651   CpvAccess(AllocCount) = 0;
652   CpvInitialize(int,BlocksAllocated);
653   CpvAccess(BlocksAllocated) = 0;
654 #endif
655
656   CpvInitialize(int, CstatsMaxChareQueueLength);
657   CpvInitialize(int, CstatsMaxForChareQueueLength);
658   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
659   CpvInitialize(int, CstatPrintQueueStatsFlag);
660   CpvInitialize(int, CstatPrintMemStatsFlag);
661
662   CpvAccess(CstatsMaxChareQueueLength) = 0;
663   CpvAccess(CstatsMaxForChareQueueLength) = 0;
664   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
665   CpvAccess(CstatPrintQueueStatsFlag) = 0;
666   CpvAccess(CstatPrintMemStatsFlag) = 0;
667
668 #if 0
669   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
670     CpvAccess(CstatPrintMemStatsFlag)=1;
671   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
672     CpvAccess(CstatPrintQueueStatsFlag)=1;
673 #endif
674 }
675
676 int CstatMemory(i)
677 int i;
678 {
679   return 0;
680 }
681
682 int CstatPrintQueueStats()
683 {
684   return CpvAccess(CstatPrintQueueStatsFlag);
685 }
686
687 int CstatPrintMemStats()
688 {
689   return CpvAccess(CstatPrintMemStatsFlag);
690 }
691
692 /*****************************************************************************
693  *
694  * Cmi handler registration
695  *
696  *****************************************************************************/
697
698 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
699 CpvStaticDeclare(int  , CmiHandlerCount);
700 CpvStaticDeclare(int  , CmiHandlerLocal);
701 CpvStaticDeclare(int  , CmiHandlerGlobal);
702 CpvDeclare(int,         CmiHandlerMax);
703
704 static void CmiExtendHandlerTable(int atLeastLen) {
705     int max = CpvAccess(CmiHandlerMax);
706     int newmax = (atLeastLen+(atLeastLen>>2)+32);
707     int bytes = max*sizeof(CmiHandlerInfo);
708     int newbytes = newmax*sizeof(CmiHandlerInfo);
709     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
710     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
711     _MEMCHECK(nu);
712     memcpy(nu, tab, bytes);
713     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
714     free(tab); tab=nu;
715     CpvAccess(CmiHandlerTable) = tab;
716     CpvAccess(CmiHandlerMax) = newmax;
717 }
718
719 void CmiNumberHandler(int n, CmiHandler h)
720 {
721   CmiHandlerInfo *tab;
722   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
723   tab = CpvAccess(CmiHandlerTable);
724   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
725   tab[n].userPtr = 0;
726 }
727 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
728   CmiHandlerInfo *tab;
729   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
730   tab = CpvAccess(CmiHandlerTable);
731   tab[n].hdlr = h;
732   tab[n].userPtr=userPtr;
733 }
734
735 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
736 #  define DIST_BETWEEN_HANDLERS 3
737 #else /*No local or global handlers; ordinary handlers are back-to-back*/
738 #  define DIST_BETWEEN_HANDLERS 1
739 #endif
740
741 int CmiRegisterHandler(CmiHandler h)
742 {
743   int Count = CpvAccess(CmiHandlerCount);
744   CmiNumberHandler(Count, h);
745   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
746   return Count;
747 }
748 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
749 {
750   int Count = CpvAccess(CmiHandlerCount);
751   CmiNumberHandlerEx(Count, h, userPtr);
752   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
753   return Count;
754 }
755
756 #if CMI_LOCAL_GLOBAL_AVAILABLE
757 int CmiRegisterHandlerLocal(h)
758 CmiHandler h;
759 {
760   int Local = CpvAccess(CmiHandlerLocal);
761   CmiNumberHandler(Local, h);
762   CpvAccess(CmiHandlerLocal) = Local+3;
763   return Local;
764 }
765
766 int CmiRegisterHandlerGlobal(h)
767 CmiHandler h;
768 {
769   int Global = CpvAccess(CmiHandlerGlobal);
770   if (CmiMyPe()!=0) 
771     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
772   CmiNumberHandler(Global, h);
773   CpvAccess(CmiHandlerGlobal) = Global+3;
774   return Global;
775 }
776 #endif
777
778 static void _cmiZeroHandler(void *msg) {
779         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
780 }
781
782 static void CmiHandlerInit()
783 {
784   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
785   CpvInitialize(int         , CmiHandlerCount);
786   CpvInitialize(int         , CmiHandlerLocal);
787   CpvInitialize(int         , CmiHandlerGlobal);
788   CpvInitialize(int         , CmiHandlerMax);
789   CpvAccess(CmiHandlerCount)  = 0;
790   CpvAccess(CmiHandlerLocal)  = 1;
791   CpvAccess(CmiHandlerGlobal) = 2;
792   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
793   CpvAccess(CmiHandlerTable) = NULL;
794   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
795 }
796
797
798 /******************************************************************************
799  *
800  * CmiTimer
801  *
802  * Here are two possible implementations of CmiTimer.  Some machines don't
803  * select either, and define the timer in machine.c instead.
804  *
805  *****************************************************************************/
806
807 #if CMK_HAS_ASCTIME
808
809 char *CmiPrintDate()
810 {
811   struct tm *local;
812   time_t t;
813
814   t = time(NULL);
815   local = localtime(&t);
816   return asctime(local);
817 }
818
819 #else
820
821 char *CmiPrintDate()
822 {
823   return "N/A";
824 }
825
826 #endif
827
828 static int _absoluteTime = 0;
829
830 #if CMK_TIMER_USE_TIMES
831
832 CpvStaticDeclare(double, clocktick);
833 CpvStaticDeclare(int,inittime_wallclock);
834 CpvStaticDeclare(int,inittime_virtual);
835
836 int CmiTimerIsSynchronized()
837 {
838   return 0;
839 }
840
841 int CmiTimerAbsolute()
842 {
843   return 0;
844 }
845
846 double CmiStartTimer()
847 {
848   return 0.0;
849 }
850
851 double CmiInitTime()
852 {
853   return CpvAccess(inittime_wallclock);
854 }
855
856 void CmiTimerInit(char **argv)
857 {
858   struct tms temp;
859   CpvInitialize(double, clocktick);
860   CpvInitialize(int, inittime_wallclock);
861   CpvInitialize(int, inittime_virtual);
862   CpvAccess(inittime_wallclock) = times(&temp);
863   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
864   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
865 }
866
867 double CmiWallTimer()
868 {
869   struct tms temp;
870   double currenttime;
871   int now;
872
873   now = times(&temp);
874   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
875   return (currenttime);
876 }
877
878 double CmiCpuTimer()
879 {
880   struct tms temp;
881   double currenttime;
882   int now;
883
884   times(&temp);
885   now = temp.tms_stime + temp.tms_utime;
886   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
887   return (currenttime);
888 }
889
890 double CmiTimer()
891 {
892   return CmiCpuTimer();
893 }
894
895 #endif
896
897 #if CMK_TIMER_USE_GETRUSAGE
898
899 #if CMK_SMP
900 # if CMK_HAS_RUSAGE_THREAD
901 #define RUSAGE_WHO        1   /* RUSAGE_THREAD, only in latest Linux kernels */
902 #else
903 #undef RUSAGE_WHO
904 #endif
905 #else
906 #define RUSAGE_WHO        0
907 #endif
908
909 static double inittime_wallclock;
910 CpvStaticDeclare(double, inittime_virtual);
911
912 int CmiTimerIsSynchronized()
913 {
914   return 0;
915 }
916
917 int CmiTimerAbsolute()
918 {
919   return _absoluteTime;
920 }
921
922 double CmiStartTimer()
923 {
924   return 0.0;
925 }
926
927 double CmiInitTime()
928 {
929   return inittime_wallclock;
930 }
931
932 void CmiTimerInit(char **argv)
933 {
934   struct timeval tv;
935   struct rusage ru;
936   CpvInitialize(double, inittime_virtual);
937
938   _absoluteTime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
939
940 #if !CMK_MEM_CHECKPOINT && !_FAULT_MLOG_ && !_FAULT_CAUSAL_
941   /* try to synchronize calling barrier */
942   CmiBarrier();
943   CmiBarrier();
944   CmiBarrier();
945 #endif
946
947   gettimeofday(&tv,0);
948   inittime_wallclock = (tv.tv_sec * 1.0) + (tv.tv_usec*0.000001);
949 #ifndef RUSAGE_WHO
950   CpvAccess(inittime_virtual) = inittime_wallclock;
951 #else
952   getrusage(RUSAGE_WHO, &ru); 
953   CpvAccess(inittime_virtual) =
954     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
955     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
956 #endif
957
958 #if ! CMK_MEM_CHECKPOINT && !_FAULT_MLOG_ && !_FAULT_CAUSAL_
959   CmiBarrier();
960 /*  CmiBarrierZero(); */
961 #endif
962 }
963
964 double CmiCpuTimer()
965 {
966 #ifndef RUSAGE_WHO
967   return CmiWallTimer();
968 #else
969   struct rusage ru;
970   double currenttime;
971
972   getrusage(RUSAGE_WHO, &ru);
973   currenttime =
974     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
975     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
976   
977   return currenttime - CpvAccess(inittime_virtual);
978 #endif
979 }
980
981 static double lastT = -1.0;
982
983 double CmiWallTimer()
984 {
985   struct timeval tv;
986   double currenttime;
987
988   gettimeofday(&tv,0);
989   currenttime = (tv.tv_sec * 1.0) + (tv.tv_usec * 0.000001);
990 #if CMK_ERROR_CHECKING
991   if (lastT > 0.0 && currenttime < lastT) {
992     currenttime = lastT;
993   }
994   lastT = currenttime;
995 #endif
996   return _absoluteTime?currenttime:currenttime - inittime_wallclock;
997 }
998
999 double CmiTimer()
1000 {
1001   return CmiCpuTimer();
1002 }
1003
1004 #endif
1005
1006 #if CMK_TIMER_USE_RDTSC
1007
1008 static double readMHz(void)
1009 {
1010   double x;
1011   char str[1000];
1012   char buf[100];
1013   FILE *fp;
1014   CmiLock(_smp_mutex);
1015   fp = fopen("/proc/cpuinfo", "r");
1016   if (fp != NULL)
1017   while(fgets(str, 1000, fp)!=0) {
1018     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1019     {
1020       char *s = strchr(str, ':'); s=s+1;
1021       sscanf(s, "%lf", &x);
1022       fclose(fp);
1023       CmiUnlock(_smp_mutex);
1024       return x;
1025     }
1026   }
1027   CmiUnlock(_smp_mutex);
1028   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
1029   return 0.0;
1030 }
1031
1032 double _cpu_speed_factor;
1033 CpvStaticDeclare(double, inittime_virtual);
1034 CpvStaticDeclare(double, inittime_walltime);
1035
1036 double  CmiStartTimer(void)
1037 {
1038   return CpvAccess(inittime_walltime);
1039 }
1040
1041 double CmiInitTime()
1042 {
1043   return CpvAccess(inittime_walltime);
1044 }
1045
1046 void CmiTimerInit(char **argv)
1047 {
1048   struct rusage ru;
1049
1050   CmiBarrier();
1051   CmiBarrier();
1052
1053   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
1054   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
1055   CpvInitialize(double, inittime_walltime);
1056   CpvAccess(inittime_walltime) = CmiWallTimer();
1057   CpvInitialize(double, inittime_virtual);
1058   getrusage(0, &ru); 
1059   CpvAccess(inittime_virtual) =
1060     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1061     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1062
1063   CmiBarrierZero();
1064 }
1065
1066 double CmiCpuTimer()
1067 {
1068   struct rusage ru;
1069   double currenttime;
1070
1071   getrusage(0, &ru);
1072   currenttime =
1073     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1074     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1075   return currenttime - CpvAccess(inittime_virtual);
1076 }
1077
1078 #endif
1079
1080 #if CMK_BLUEGENEL || CMK_BLUEGENEP
1081 #include "dcopy.h"
1082 #endif
1083
1084 #if CMK_TIMER_USE_BLUEGENEL
1085
1086 #include "rts.h"
1087
1088 #if 0 
1089 #define SPRN_TBRL 0x10C  /* Time Base Read Lower Register (user & sup R/O) */
1090 #define SPRN_TBRU 0x10D  /* Time Base Read Upper Register (user & sup R/O) */
1091 #define SPRN_PIR  0x11E  /* CPU id */
1092
1093 static inline unsigned long long BGLTimebase(void)
1094 {
1095   unsigned volatile u1, u2, lo;
1096   union
1097   {
1098     struct { unsigned hi, lo; } w;
1099     unsigned long long d;
1100   } result;
1101                                                                                 
1102   do {
1103     asm volatile ("mfspr %0,%1" : "=r" (u1) : "i" (SPRN_TBRU));
1104     asm volatile ("mfspr %0,%1" : "=r" (lo) : "i" (SPRN_TBRL));
1105     asm volatile ("mfspr %0,%1" : "=r" (u2) : "i" (SPRN_TBRU));
1106   } while (u1!=u2);
1107                                                                                 
1108   result.w.lo = lo;
1109   result.w.hi = u2;
1110   return result.d;
1111 }
1112 #endif
1113
1114 static unsigned long long inittime_wallclock = 0;
1115 CpvStaticDeclare(double, clocktick);
1116
1117 int CmiTimerIsSynchronized()
1118 {
1119   return 0;
1120 }
1121
1122 int CmiTimerAbsolute()
1123 {
1124   return 1;
1125 }
1126
1127 double CmiStartTimer()
1128 {
1129   return 0.0;
1130 }
1131
1132 double CmiInitTime()
1133 {
1134   return inittime_wallclock;
1135 }
1136
1137 void CmiTimerInit(char **argv)
1138 {
1139   BGLPersonality dst;
1140   CpvInitialize(double, clocktick);
1141   int size = sizeof(BGLPersonality);
1142   rts_get_personality(&dst, size);
1143   CpvAccess(clocktick) = 1.0 / dst.clockHz;
1144
1145   /* try to synchronize calling barrier */
1146   CmiBarrier();
1147   CmiBarrier();
1148   CmiBarrier();
1149
1150   /* inittime_wallclock = rts_get_timebase(); */
1151   inittime_wallclock = 0.0;    /* use bgl absolute time */
1152 }
1153
1154 double CmiWallTimer()
1155 {
1156   unsigned long long currenttime;
1157   currenttime = rts_get_timebase();
1158   return CpvAccess(clocktick)*(currenttime-inittime_wallclock);
1159 }
1160
1161 double CmiCpuTimer()
1162 {
1163   return CmiWallTimer();
1164 }
1165
1166 double CmiTimer()
1167 {
1168   return CmiWallTimer();
1169 }
1170
1171 #endif
1172
1173 #if CMK_TIMER_USE_BLUEGENEP  /* This module just compiles with GCC charm. */
1174
1175 int CmiTimerAbsolute()
1176 {
1177   return 0;
1178 }
1179
1180 double CmiStartTimer()
1181 {
1182   return 0.0;
1183 }
1184
1185 double CmiInitTime()
1186 {
1187   return 0.0;
1188 }
1189
1190 void CmiTimerInit(char **argv) {}
1191
1192 #include "dcmf.h"
1193
1194 double CmiWallTimer () {
1195   return DCMF_Timer();
1196 }
1197
1198 double CmiCpuTimer()
1199 {
1200   return CmiWallTimer();
1201 }
1202
1203 double CmiTimer()
1204 {
1205   return CmiWallTimer();
1206 }
1207 #endif
1208
1209
1210 #if CMK_TIMER_USE_BLUEGENEQ  /* This module just compiles with GCC charm. */
1211
1212 CpvStaticDeclare(unsigned long, inittime);
1213 CpvStaticDeclare(double, clocktick);
1214
1215 int CmiTimerIsSynchronized()
1216 {
1217   return 1;
1218 }
1219
1220 int CmiTimerAbsolute()
1221 {
1222   return 0;
1223 }
1224
1225 #include "hwi/include/bqc/A2_inlines.h"
1226 #include "spi/include/kernel/process.h"
1227
1228 double CmiStartTimer()
1229 {
1230   return 0.0;
1231 }
1232
1233 double CmiInitTime()
1234 {
1235   return CpvAccess(inittime);
1236 }
1237
1238 void CmiTimerInit(char **argv)
1239 {
1240   CpvInitialize(double, clocktick);
1241   CpvInitialize(unsigned long, inittime);
1242
1243   Personality_t  pers;
1244   Kernel_GetPersonality(&pers, sizeof(pers));
1245   uint32_t clockMhz = pers.Kernel_Config.FreqMHz;
1246   CpvAccess(clocktick) = 1.0 / (clockMhz * 1e6); 
1247
1248   /*fprintf(stderr, "Blue Gene/Q running at clock speed of %d Mhz\n", clockMhz);*/
1249
1250   /* try to synchronize calling barrier */
1251   CmiBarrier();
1252   CmiBarrier();
1253   CmiBarrier();
1254
1255   CpvAccess(inittime) = GetTimeBase (); 
1256 }
1257
1258 double CmiWallTimer()
1259 {
1260   unsigned long long currenttime;
1261   currenttime = GetTimeBase();
1262   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1263 }
1264
1265 double CmiCpuTimer()
1266 {
1267   return CmiWallTimer();
1268 }
1269
1270 double CmiTimer()
1271 {
1272   return CmiWallTimer();
1273 }
1274
1275 #endif
1276
1277
1278 #if CMK_TIMER_USE_WIN32API
1279
1280 CpvStaticDeclare(double, inittime_wallclock);
1281 CpvStaticDeclare(double, inittime_virtual);
1282
1283 double CmiStartTimer()
1284 {
1285   return 0.0;
1286 }
1287
1288 int CmiTimerAbsolute()
1289 {
1290   return 0;
1291 }
1292
1293 double CmiInitTime()
1294 {
1295   return CpvAccess(inittime_wallclock);
1296 }
1297
1298 void CmiTimerInit(char **argv)
1299 {
1300 #ifdef __CYGWIN__
1301         struct timeb tv;
1302 #else
1303         struct _timeb tv;
1304 #endif
1305         clock_t       ru;
1306
1307         CpvInitialize(double, inittime_wallclock);
1308         CpvInitialize(double, inittime_virtual);
1309         _ftime(&tv);
1310         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1311         ru = clock();
1312         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1313 }
1314
1315 double CmiCpuTimer()
1316 {
1317         clock_t ru;
1318         double currenttime;
1319
1320         ru = clock();
1321         currenttime = (double) ru/CLOCKS_PER_SEC;
1322
1323         return currenttime - CpvAccess(inittime_virtual);
1324 }
1325
1326 double CmiWallTimer()
1327 {
1328 #ifdef __CYGWIN__
1329         struct timeb tv;
1330 #else
1331         struct _timeb tv;
1332 #endif
1333         double currenttime;
1334
1335         _ftime(&tv);
1336         currenttime = tv.time*1.0 + tv.millitm*0.001;
1337
1338         return currenttime - CpvAccess(inittime_wallclock);
1339 }
1340         
1341
1342 double CmiTimer()
1343 {
1344         return CmiCpuTimer();
1345 }
1346
1347 #endif
1348
1349 #if CMK_TIMER_USE_RTC
1350
1351 #if __crayx1
1352  /* For _rtc() on Cray X1 */
1353 #include <intrinsics.h>
1354 #endif
1355
1356 static double clocktick;
1357 CpvStaticDeclare(long long, inittime_wallclock);
1358
1359 double CmiStartTimer()
1360 {
1361   return 0.0;
1362 }
1363
1364 double CmiInitTime()
1365 {
1366   return CpvAccess(inittime_wallclock);
1367 }
1368
1369 void CmiTimerInit(char **argv)
1370 {
1371   CpvInitialize(long long, inittime_wallclock);
1372   CpvAccess(inittime_wallclock) = _rtc();
1373   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1374 }
1375
1376 int CmiTimerAbsolute()
1377 {
1378   return 0;
1379 }
1380
1381 double CmiWallTimer()
1382 {
1383   long long now;
1384
1385   now = _rtc();
1386   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1387 }
1388
1389 double CmiCpuTimer()
1390 {
1391   return CmiWallTimer();
1392 }
1393
1394 double CmiTimer()
1395 {
1396   return CmiCpuTimer();
1397 }
1398
1399 #endif
1400
1401 #if CMK_TIMER_USE_AIX_READ_TIME
1402
1403 #include <sys/time.h>
1404
1405 static timebasestruct_t inittime_wallclock;
1406 static double clocktick;
1407 CpvStaticDeclare(double, inittime_virtual);
1408
1409 double CmiStartTimer()
1410 {
1411   return 0.0;
1412 }
1413
1414 double CmiInitTime()
1415 {
1416   return inittime_wallclock;
1417 }
1418
1419 void CmiTimerInit(char **argv)
1420 {
1421   struct rusage ru;
1422
1423   if (CmiMyRank() == 0) {
1424     read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1425     time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1426   }
1427
1428   CpvInitialize(double, inittime_virtual);
1429   getrusage(0, &ru);
1430   CpvAccess(inittime_virtual) =
1431     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1432     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1433 }
1434
1435 int CmiTimerAbsolute()
1436 {
1437   return 0;
1438 }
1439
1440 double CmiWallTimer()
1441 {
1442   int secs, n_secs;
1443   double curt;
1444   timebasestruct_t now;
1445   read_wall_time(&now, TIMEBASE_SZ);
1446   time_base_to_time(&now, TIMEBASE_SZ);
1447
1448   secs = now.tb_high - inittime_wallclock.tb_high;
1449   n_secs = now.tb_low - inittime_wallclock.tb_low;
1450   if (n_secs < 0)  {
1451     secs--;
1452     n_secs += 1000000000;
1453   }
1454   curt = secs*1.0 + n_secs*1e-9;
1455   return curt;
1456 }
1457
1458 double CmiCpuTimer()
1459 {
1460   struct rusage ru;
1461   double currenttime;
1462
1463   getrusage(0, &ru);
1464   currenttime =
1465     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1466     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1467   return currenttime - CpvAccess(inittime_virtual);
1468 }
1469
1470 double CmiTimer()
1471 {
1472   return CmiWallTimer();
1473 }
1474
1475 #endif
1476
1477 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1478 /** Return 1 if our outgoing message queue 
1479    for this node is longer than this many bytes. */
1480 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1481   return 0;
1482 }
1483 #endif
1484
1485 #if CMK_SIGNAL_USE_SIGACTION
1486 #include <signal.h>
1487 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)())
1488 {
1489   struct sigaction in, out ;
1490   in.sa_handler = handler;
1491   sigemptyset(&in.sa_mask);
1492   if (sig1) sigaddset(&in.sa_mask, sig1);
1493   if (sig2) sigaddset(&in.sa_mask, sig2);
1494   if (sig3) sigaddset(&in.sa_mask, sig3);
1495   in.sa_flags = 0;
1496   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1497   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1498   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1499 }
1500 #endif
1501
1502 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1503 #include <signal.h>
1504 void CmiSignal(sig1, sig2, sig3, handler)
1505 int sig1, sig2, sig3;
1506 void (*handler)();
1507 {
1508   struct sigaction in, out ;
1509   in.sa_handler = handler;
1510   sigemptyset(&in.sa_mask);
1511   if (sig1) sigaddset(&in.sa_mask, sig1);
1512   if (sig2) sigaddset(&in.sa_mask, sig2);
1513   if (sig3) sigaddset(&in.sa_mask, sig3);
1514   in.sa_flags = SA_RESTART;
1515   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1516   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1517   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1518 }
1519 #endif
1520
1521 /** 
1522  *  @addtogroup ConverseScheduler
1523  *  @{
1524  */
1525
1526 /*****************************************************************************
1527  * 
1528  * The following is the CsdScheduler function.  A common
1529  * implementation is provided below.  The machine layer can provide an
1530  * alternate implementation if it so desires.
1531  *
1532  * void CmiDeliversInit()
1533  *
1534  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1535  *        or any of the other functions in this section.
1536  *
1537  * int CmiDeliverMsgs(int maxmsgs)
1538  *
1539  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1540  *        with the Cmi, and will invoke their handlers.  It does not wait
1541  *        if no message is unavailable.  Instead, it returns the quantity
1542  *        (maxmsgs-delivered), where delivered is the number of messages it
1543  *        delivered.
1544  *
1545  * void CmiDeliverSpecificMsg(int handlerno)
1546  *
1547  *      - Waits for a message with the specified handler to show up, then
1548  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1549  *        This function _does_ wait.
1550  *
1551  * For this common implementation to work, the machine layer must provide the
1552  * following:
1553  *
1554  * void *CmiGetNonLocal()
1555  *
1556  *      - returns a message just retrieved from some other PE, not from
1557  *        local.  If no such message exists, returns 0.
1558  *
1559  * CpvExtern(CdsFifo, CmiLocalQueue);
1560  *
1561  *      - a FIFO queue containing all messages from the local processor.
1562  *
1563  *****************************************************************************/
1564
1565 void CsdBeginIdle(void)
1566 {
1567   CcdCallBacks();
1568 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1569   _LOG_E_PROC_IDLE();   /* projector */
1570 #endif
1571
1572   CpvAccess(cmiMyPeIdle) = 1;
1573
1574   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1575 }
1576
1577 void CsdStillIdle(void)
1578 {
1579   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1580 }
1581
1582 void CsdEndIdle(void)
1583 {
1584 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1585   _LOG_E_PROC_BUSY();   /* projector */
1586 #endif
1587
1588   CpvAccess(cmiMyPeIdle) = 0;
1589
1590   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1591 }
1592
1593 extern int _exitHandlerIdx;
1594
1595 /** Takes a message and calls its corresponding handler. */
1596 void CmiHandleMessage(void *msg)
1597 {
1598 /* this is wrong because it counts the Charm++ messages in sched queue
1599         CpvAccess(cQdState)->mProcessed++;
1600 */
1601         CmiHandlerInfo *h;
1602 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1603         CmiUInt2 handler=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1604         _LOG_E_HANDLER_BEGIN(handler); /* projector */
1605         /* setMemoryStatus(1) */ /* charmdebug */
1606 #endif
1607
1608 /*
1609         FAULT_EVAC
1610 */
1611 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1612                 return;
1613         }*/
1614         
1615         MESSAGE_PHASE_CHECK(msg)
1616
1617         h=&CmiGetHandlerInfo(msg);
1618         (h->hdlr)(msg,h->userPtr);
1619 #if CMK_TRACE_ENABLED
1620         /* setMemoryStatus(0) */ /* charmdebug */
1621         //_LOG_E_HANDLER_END(handler);  /* projector */
1622 #endif
1623 }
1624
1625 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1626
1627 void CmiDeliversInit()
1628 {
1629 }
1630
1631 int CmiDeliverMsgs(int maxmsgs)
1632 {
1633   return CsdScheduler(maxmsgs);
1634 }
1635
1636 #if CMK_OBJECT_QUEUE_AVAILABLE
1637 CpvDeclare(void *, CsdObjQueue);
1638 #endif
1639
1640 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1641 {
1642 #if CMK_OBJECT_QUEUE_AVAILABLE
1643         s->objQ=CpvAccess(CsdObjQueue);
1644 #endif
1645         s->localQ=CpvAccess(CmiLocalQueue);
1646         s->schedQ=CpvAccess(CsdSchedQueue);
1647         s->localCounter=&(CpvAccess(CsdLocalCounter));
1648 #if CMK_NODE_QUEUE_AVAILABLE
1649         s->nodeQ=CsvAccess(CsdNodeQueue);
1650         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1651 #endif
1652 #if CMK_GRID_QUEUE_AVAILABLE
1653         s->gridQ=CpvAccess(CsdGridQueue);
1654 #endif
1655 }
1656
1657
1658 /** Dequeue and return the next message from the unprocessed message queues.
1659  *
1660  * This function encapsulates the multiple queues that exist for holding unprocessed
1661  * messages and the rules for the order in which to check them. There are five (5)
1662  * different Qs that converse uses to store and retrieve unprocessed messages. These
1663  * are:
1664  *     Q Purpose                  Type      internal DeQ logic
1665  * -----------------------------------------------------------
1666  * - PE offnode                   pcQ             FIFO
1667  * - PE onnode                    CkQ             FIFO
1668  * - Node offnode                 pcQ             FIFO
1669  * - Node onnode                  prioQ           prio-based
1670  * - Scheduler                    prioQ           prio-based
1671  *
1672  * The PE queues hold messages that are destined for a specific PE. There is one such
1673  * queue for every PE within a charm node. The node queues hold messages that are
1674  * destined to that node. There is only one of each node queue within a charm node.
1675  * Finally there is also a charm++ message queue for each PE.
1676  *
1677  * The offnode queues are meant for holding messages that arrive from outside the
1678  * node. The onnode queues hold messages that are generated within the same charm
1679  * node.
1680  *
1681  * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1682  * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1683  * and hide the implementation specifics for each layer.
1684  *
1685  * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1686  * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1687  * queues. They are initialized via calls to CqsCreate() which gives each of them
1688  * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1689  * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1690  * is passed into this function.
1691  *
1692  * The order in which these queues are checked is described below. The function
1693  * proceeds to the next queue in the list only if it does not find any messages in
1694  * the current queue. The first message that is found is returned, terminating the
1695  * call.
1696  * (1) offnode queue for this PE
1697  * (2) onnode queue for this PE
1698  * (3) offnode queue for this node
1699  * (4) highest priority msg from onnode queue or scheduler queue
1700  *
1701  * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1702  * access (after observing adequate locking rigor) structs representing the scheduler
1703  * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1704  * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1705  * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1706  *
1707  */
1708 void *CsdNextMessage(CsdSchedulerState_t *s) {
1709         void *msg;
1710         if((*(s->localCounter))-- >0)
1711           {
1712               /* This avoids a race condition with migration detected by megatest*/
1713               msg=CdsFifo_Dequeue(s->localQ);
1714               if (msg!=NULL)
1715                 {
1716                   CpvAccess(cQdState)->mProcessed++;
1717                   return msg;       
1718                 }
1719               CqsDequeue(s->schedQ,(void **)&msg);
1720               if (msg!=NULL) return msg;
1721           }
1722         
1723         *(s->localCounter)=CsdLocalMax;
1724         if ( NULL!=(msg=CmiGetNonLocal()) || 
1725              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1726             CpvAccess(cQdState)->mProcessed++;
1727             return msg;
1728         }
1729 #if CMK_GRID_QUEUE_AVAILABLE
1730         /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1731         CqsDequeue (s->gridQ, (void **) &msg);
1732         if (msg != NULL) {
1733           return (msg);
1734         }
1735 #endif
1736 #if CMK_NODE_QUEUE_AVAILABLE
1737         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1738         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1739         if (!CqsEmpty(s->nodeQ)
1740          && !CqsPrioGT(CqsGetPriority(s->nodeQ),
1741                        CqsGetPriority(s->schedQ))) {
1742           CmiLock(s->nodeLock);
1743           CqsDequeue(s->nodeQ,(void **)&msg);
1744           CmiUnlock(s->nodeLock);
1745           if (msg!=NULL) return msg;
1746         }
1747 #endif
1748 #if CMK_OBJECT_QUEUE_AVAILABLE
1749         /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE"   */
1750         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1751           return msg;
1752         }
1753 #endif
1754         if(!CsdLocalMax) {
1755           CqsDequeue(s->schedQ,(void **)&msg);
1756           if (msg!=NULL) return msg;        
1757         }
1758         return NULL;
1759 }
1760
1761
1762 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1763         void *msg;
1764 #if CMK_NODE_QUEUE_AVAILABLE
1765         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1766         /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1767         if (!CqsEmpty(s->nodeQ))
1768         {
1769           CmiLock(s->nodeLock);
1770           CqsDequeue(s->nodeQ,(void **)&msg);
1771           CmiUnlock(s->nodeLock);
1772           if (msg!=NULL) return msg;
1773         }
1774 #endif
1775         return NULL;
1776
1777 }
1778
1779 int CsdScheduler(int maxmsgs)
1780 {
1781         if (maxmsgs<0) CsdScheduleForever();    
1782         else if (maxmsgs==0)
1783                 CsdSchedulePoll();
1784         else /*(maxmsgs>0)*/ 
1785                 return CsdScheduleCount(maxmsgs);
1786         return 0;
1787 }
1788
1789 /*Declare the standard scheduler housekeeping*/
1790 #define SCHEDULE_TOP \
1791       void *msg;\
1792       int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1793       int cycle = CpvAccess(CsdStopFlag); \
1794       CsdSchedulerState_t state;\
1795       CsdSchedulerState_new(&state);
1796
1797 /*A message is available-- process it*/
1798 #define SCHEDULE_MESSAGE \
1799       CmiHandleMessage(msg);\
1800       if (*CsdStopFlag_ptr != cycle) break;
1801
1802 /*No message available-- go (or remain) idle*/
1803 #define SCHEDULE_IDLE \
1804       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1805       else CsdStillIdle();\
1806       if (*CsdStopFlag_ptr != cycle) {\
1807         CsdEndIdle();\
1808         break;\
1809       }
1810
1811 /*
1812         EVAC
1813 */
1814 extern void CkClearAllArrayElements();
1815
1816
1817 extern void machine_OffloadAPIProgress();
1818
1819 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1820 void CsdScheduleForever(void)
1821 {
1822   #if CMK_CELL
1823     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1824     int progressCount = CMK_CELL_PROGRESS_FREQ;
1825   #endif
1826
1827   #ifdef CMK_CUDA
1828     #define CMK_CUDA_PROGRESS_FREQ 50
1829     int cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1830   #endif
1831
1832   int isIdle=0;
1833   SCHEDULE_TOP
1834   while (1) {
1835     /* The interoperation will cost this little overhead in scheduling */
1836     if(CharmLibInterOperate) {
1837       if(CpvAccess(charmLibExitFlag)) {
1838         CpvAccess(charmLibExitFlag) = 0;
1839         break;
1840       }
1841     }
1842     msg = CsdNextMessage(&state);
1843     if (msg!=NULL) { /*A message is available-- process it*/
1844       if (isIdle) {isIdle=0;CsdEndIdle();}
1845       SCHEDULE_MESSAGE
1846
1847       #if CMK_CELL
1848         if (progressCount <= 0) {
1849           /*OffloadAPIProgress();*/
1850           machine_OffloadAPIProgress();
1851           progressCount = CMK_CELL_PROGRESS_FREQ;
1852         }
1853         progressCount--;
1854       #endif
1855
1856       #ifdef CMK_CUDA
1857         if (cudaProgressCount == 0) {
1858           gpuProgressFn(); 
1859           cudaProgressCount = CMK_CUDA_PROGRESS_FREQ; 
1860         }
1861         cudaProgressCount--; 
1862       #endif
1863
1864     } else { /*No message available-- go (or remain) idle*/
1865       SCHEDULE_IDLE
1866
1867       #if CMK_CELL
1868         /*OffloadAPIProgress();*/
1869         machine_OffloadAPIProgress();
1870         progressCount = CMK_CELL_PROGRESS_FREQ;
1871       #endif
1872
1873       #ifdef CMK_CUDA
1874         gpuProgressFn(); 
1875         cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1876       #endif
1877
1878     }
1879     CsdPeriodic();
1880   }
1881 }
1882 int CsdScheduleCount(int maxmsgs)
1883 {
1884   int isIdle=0;
1885   SCHEDULE_TOP
1886   while (1) {
1887     msg = CsdNextMessage(&state);
1888     if (msg!=NULL) { /*A message is available-- process it*/
1889       if (isIdle) {isIdle=0;CsdEndIdle();}
1890       maxmsgs--; 
1891       SCHEDULE_MESSAGE
1892       if (maxmsgs==0) break;
1893     } else { /*No message available-- go (or remain) idle*/
1894       SCHEDULE_IDLE
1895     }
1896     CsdPeriodic();
1897   }
1898   return maxmsgs;
1899 }
1900
1901 void CsdSchedulePoll(void)
1902 {
1903   SCHEDULE_TOP
1904   while (1)
1905   {
1906         CsdPeriodic();
1907         /*CmiMachineProgressImpl(); ??? */
1908         if (NULL!=(msg = CsdNextMessage(&state)))
1909         {
1910              SCHEDULE_MESSAGE 
1911         }
1912         else break;
1913   }
1914 }
1915
1916 void CsdScheduleNodePoll(void)
1917 {
1918   SCHEDULE_TOP
1919   while (1)
1920   {
1921         /*CsdPeriodic();*/
1922         /*CmiMachineProgressImpl(); ??? */
1923         if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
1924         {
1925              SCHEDULE_MESSAGE 
1926         }
1927         else break;
1928   }
1929 }
1930
1931 void CmiDeliverSpecificMsg(handler)
1932 int handler;
1933 {
1934   int *msg; int side;
1935   void *localqueue = CpvAccess(CmiLocalQueue);
1936  
1937   side = 0;
1938   while (1) {
1939     CsdPeriodic();
1940     side ^= 1;
1941     if (side) msg = CmiGetNonLocal();
1942     else      msg = CdsFifo_Dequeue(localqueue);
1943     if (msg) {
1944       if (CmiGetHandler(msg)==handler) {
1945         CpvAccess(cQdState)->mProcessed++;
1946         CmiHandleMessage(msg);
1947         return;
1948       } else {
1949         CdsFifo_Enqueue(localqueue, msg);
1950       }
1951     }
1952   }
1953 }
1954  
1955 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1956
1957 /***************************************************************************
1958  *
1959  * Standin Schedulers.
1960  *
1961  * We use the following strategy to make sure somebody's always running
1962  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1963  * is responsible for this.  If the main thread blocks, we create a
1964  * "standin scheduler" thread to replace it.  If the standin scheduler
1965  * blocks, we create another standin scheduler to replace that one,
1966  * ad infinitum.  Collectively, the main thread and all the standin
1967  * schedulers are called "scheduling threads".
1968  *
1969  * Suppose the main thread is blocked waiting for data, and a standin
1970  * scheduler is running instead.  Suppose, then, that the data shows
1971  * up and the main thread is CthAwakened.  This causes a token to be
1972  * pushed into the queue.  When the standin pulls the token from the
1973  * queue and handles it, the standin goes to sleep, and control shifts
1974  * back to the main thread.  In this way, unnecessary standins are put
1975  * back to sleep.  These sleeping standins are stored on the
1976  * CthSleepingStandins list.
1977  *
1978  ***************************************************************************/
1979
1980 CpvStaticDeclare(CthThread, CthMainThread);
1981 CpvStaticDeclare(CthThread, CthSchedulingThread);
1982 CpvStaticDeclare(CthThread, CthSleepingStandins);
1983 CpvDeclare(int      , CthResumeNormalThreadIdx);
1984 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1985
1986
1987 void CthStandinCode()
1988 {
1989   while (1) CsdScheduler(0);
1990 }
1991
1992 /* this fix the function pointer for thread migration and pup */
1993 static CthThread CthSuspendNormalThread()
1994 {
1995   return CpvAccess(CthSchedulingThread);
1996 }
1997
1998 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
1999 CthThread CthSuspendSchedulingThread();
2000
2001 CthThread CthSuspendSchedulingThread()
2002 {
2003   CthThread succ = CpvAccess(CthSleepingStandins);
2004
2005   if (succ) {
2006     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2007   } else {
2008     succ = CthCreate(CthStandinCode, 0, 256000);
2009     CthSetStrategy(succ,
2010                    CthEnqueueSchedulingThread,
2011                    CthSuspendSchedulingThread);
2012   }
2013   
2014   CpvAccess(CthSchedulingThread) = succ;
2015   return succ;
2016 }
2017
2018 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2019 void CthResumeNormalThread(CthThreadToken* token)
2020 {
2021   CthThread t = token->thread;
2022
2023   /* BIGSIM_OOC DEBUGGING
2024   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2025   */
2026
2027   if(t == NULL){
2028     free(token);
2029     return;
2030   }
2031 #if CMK_TRACE_ENABLED
2032 #if ! CMK_TRACE_IN_CHARM
2033   if(CpvAccess(traceOn))
2034     CthTraceResume(t);
2035 /*    if(CpvAccess(_traceCoreOn)) 
2036                 resumeTraceCore();*/
2037 #endif
2038 #endif
2039   
2040   /* BIGSIM_OOC DEBUGGING
2041   CmiPrintf("In CthResumeNormalThread:   ");
2042   CthPrintThdMagic(t);
2043   */
2044
2045   CthResume(t);
2046 }
2047
2048 void CthResumeSchedulingThread(CthThreadToken  *token)
2049 {
2050   CthThread t = token->thread;
2051   CthThread me = CthSelf();
2052   if (me == CpvAccess(CthMainThread)) {
2053     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2054   } else {
2055     CthSetNext(me, CpvAccess(CthSleepingStandins));
2056     CpvAccess(CthSleepingStandins) = me;
2057   }
2058   CpvAccess(CthSchedulingThread) = t;
2059 #if CMK_TRACE_ENABLED
2060 #if ! CMK_TRACE_IN_CHARM
2061   if(CpvAccess(traceOn))
2062     CthTraceResume(t);
2063 /*    if(CpvAccess(_traceCoreOn)) 
2064                 resumeTraceCore();*/
2065 #endif
2066 #endif
2067   CthResume(t);
2068 }
2069
2070 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2071                                    int pb,unsigned int *prio)
2072 {
2073   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2074   CsdEnqueueGeneral(token, s, pb, prio);
2075 }
2076
2077 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2078                                        int pb,unsigned int *prio)
2079 {
2080   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2081   CsdEnqueueGeneral(token, s, pb, prio);
2082 }
2083
2084 void CthSetStrategyDefault(CthThread t)
2085 {
2086   CthSetStrategy(t,
2087                  CthEnqueueNormalThread,
2088                  CthSuspendNormalThread);
2089 }
2090
2091 void CthSchedInit()
2092 {
2093   CpvInitialize(CthThread, CthMainThread);
2094   CpvInitialize(CthThread, CthSchedulingThread);
2095   CpvInitialize(CthThread, CthSleepingStandins);
2096   CpvInitialize(int      , CthResumeNormalThreadIdx);
2097   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2098
2099   CpvAccess(CthMainThread) = CthSelf();
2100   CpvAccess(CthSchedulingThread) = CthSelf();
2101   CpvAccess(CthSleepingStandins) = 0;
2102   CpvAccess(CthResumeNormalThreadIdx) =
2103     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2104   CpvAccess(CthResumeSchedulingThreadIdx) =
2105     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2106   CthSetStrategy(CthSelf(),
2107                  CthEnqueueSchedulingThread,
2108                  CthSuspendSchedulingThread);
2109 }
2110
2111 void CsdInit(argv)
2112   char **argv;
2113 {
2114   CpvInitialize(void *, CsdSchedQueue);
2115   CpvInitialize(int,   CsdStopFlag);
2116   CpvInitialize(int,   CsdLocalCounter);
2117   if(!CmiGetArgIntDesc(argv,"+csdLocalMax",&CsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages."))
2118     {
2119       CsdLocalMax= CSD_LOCAL_MAX_DEFAULT;
2120     }
2121   CpvAccess(CsdLocalCounter) = CsdLocalMax;
2122   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
2123
2124 #if CMK_OBJECT_QUEUE_AVAILABLE
2125   CpvInitialize(void *,CsdObjQueue);
2126   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2127 #endif
2128
2129 #if CMK_NODE_QUEUE_AVAILABLE
2130   CsvInitialize(CmiLock, CsdNodeQueueLock);
2131   CsvInitialize(void *, CsdNodeQueue);
2132   if (CmiMyRank() ==0) {
2133         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2134         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
2135   }
2136   CmiNodeAllBarrier();
2137 #endif
2138
2139 #if CMK_GRID_QUEUE_AVAILABLE
2140   CsvInitialize(void *, CsdGridQueue);
2141   CpvAccess(CsdGridQueue) = (void *)CqsCreate();
2142 #endif
2143
2144   CpvAccess(CsdStopFlag)  = 0;
2145 }
2146
2147
2148
2149 /** 
2150  *  @}
2151  */
2152
2153
2154 /*****************************************************************************
2155  *
2156  * Vector Send
2157  *
2158  * The last parameter "system" is by default at zero, in which case the normal
2159  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2160  * CmiAllocced message will also be sent (except for the first one). Useful for
2161  * AllToAll communication, and other system features. If system is 1, also all
2162  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2163  * that.
2164  *
2165  ****************************************************************************/
2166
2167 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2168
2169 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2170   int total;
2171   char *mesg;
2172 #if CMK_USE_IBVERBS
2173   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2174 #else
2175   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2176 #endif  
2177   CmiSyncSendAndFree(destPE, total, mesg);
2178 }
2179
2180 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2181   CmiSyncVectorSend(destPE, n, sizes, msgs);
2182   return NULL;
2183 }
2184
2185 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2186   int i;
2187   CmiSyncVectorSend(destPE, n, sizes, msgs);
2188   for(i=0;i<n;i++) CmiFree(msgs[i]);
2189   CmiFree(sizes);
2190   CmiFree(msgs);
2191 }
2192
2193 #endif
2194
2195 /*****************************************************************************
2196  *
2197  * Reduction management
2198  *
2199  * Only one reduction can be active at a single time in the program.
2200  * Moreover, since every call is supposed to pass in the same arguments,
2201  * having some static variables is not a problem for multithreading.
2202  * 
2203  * Except for "data" and "size", all the other parameters (which are all function
2204  * pointers) MUST be the same in every processor. Having different processors
2205  * pass in different function pointers results in an undefined behaviour.
2206  * 
2207  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2208  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2209  * functions is deleted with the provided function, or it is left intact if no
2210  * function is specified.
2211  * 
2212  * The destination handler for the the first form MUST be embedded into the
2213  * message's header.
2214  * 
2215  * The pup function is used to pup the input data structure into a message to
2216  * be sent to the parent processor. This pup routine is currently used only
2217  * for sizing and packing, NOT unpacking. It MUST be non-null.
2218  * 
2219  * The merge function receives as first parameter the input "data", being it
2220  * a message or a complex data structure (it is up to the user to interpret it
2221  * correctly), and a list of incoming (packed) messages from the children.
2222  * The merge function is responsible to delete "data" if this is no longer needed.
2223  * The system will be in charge of deleting the messages passed in as the second
2224  * argument, and the return value of the function (using the provided deleteFn in
2225  * the second version, or CmiFree in the first). The merge function can return
2226  * data if the merge can be performed in-place. It MUST be non-null.
2227  * 
2228  * At the destination, on processor zero, the final data returned by the last
2229  * merge call will not be deleted by the system, and the CmiHandler function
2230  * will be in charge of its deletion.
2231  * 
2232  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2233  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2234  * particular by the rank zero in each node.
2235  ****************************************************************************/
2236
2237 CpvStaticDeclare(int, CmiReductionMessageHandler);
2238 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2239
2240 CpvStaticDeclare(CmiReduction**, _reduce_info);
2241 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2242 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2243 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2244 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2245
2246 enum {
2247   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2248   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2249   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2250   CmiReductionID_multiplier = 3
2251 };
2252
2253 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2254   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2255   CmiReduction *red = CpvAccess(_reduce_info)[index];
2256   if (red != NULL && red->seqID != id) {
2257     /* The table needs to be expanded */
2258     CmiAbort("Too many simultaneous reductions");
2259   }
2260   if (red == NULL || red->numChildren < numChildren) {
2261     CmiReduction *newred;
2262     if (red != NULL) CmiPrintf("[%d] Reduction structure reallocated\n",CmiMyPe());
2263     CmiAssert(red == NULL || red->localContributed == 0);
2264     if (numChildren == 0) numChildren = 4;
2265     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2266     newred->numRemoteReceived = 0;
2267     newred->localContributed = 0;
2268     newred->seqID = id;
2269     if (red != NULL) {
2270       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2271       free(red);
2272     }
2273     red = newred;
2274     red->numChildren = numChildren;
2275     red->remoteData = (char**)(red+1);
2276     CpvAccess(_reduce_info)[index] = red;
2277   }
2278   return red;
2279 }
2280
2281 CmiReduction* CmiGetReduction(int id) {
2282   return CmiGetReductionCreate(id, 0);
2283 }
2284
2285 void CmiClearReduction(int id) {
2286   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2287   free(CpvAccess(_reduce_info)[index]);
2288   CpvAccess(_reduce_info)[index] = NULL;
2289 }
2290
2291 CmiReduction* CmiGetNextReduction(short int numChildren) {
2292   int id = CpvAccess(_reduce_seqID_global);
2293   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2294   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2295   return CmiGetReductionCreate(id, numChildren);
2296 }
2297
2298 CmiReductionID CmiGetGlobalReduction() {
2299   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2300 }
2301
2302 CmiReductionID CmiGetDynamicReduction() {
2303   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2304   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2305 }
2306
2307 void CmiReductionHandleDynamicRequest(char *msg) {
2308   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2309   int pe = values[0];
2310   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2311   values[0] = CmiGetDynamicReduction();
2312   CmiSetHandler(msg, CmiGetXHandler(msg));
2313   if (pe >= 0) {
2314     CmiSyncSendAndFree(pe, size, msg);
2315   } else {
2316     CmiSyncBroadcastAllAndFree(size, msg);
2317   }
2318 }
2319
2320 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2321   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2322   char *msg = (char*)CmiAlloc(size);
2323   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2324   values[0] = pe;
2325   values[1] = dataSize;
2326   CmiSetXHandler(msg, handlerIdx);
2327   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2328   if (CmiMyPe() == 0) {
2329     CmiReductionHandleDynamicRequest(msg);
2330   } else {
2331     /* send the request to processor 0 */
2332     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2333     CmiSyncSendAndFree(0, size, msg);
2334   }
2335 }
2336
2337 void CmiSendReduce(CmiReduction *red) {
2338   void *mergedData, *msg;
2339   int msg_size;
2340   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2341   mergedData = red->localData;
2342   msg_size = red->localSize;
2343   if (red->numChildren > 0) {
2344     int i, offset=0;
2345     if (red->ops.pupFn != NULL) {
2346       offset = CmiReservedHeaderSize;
2347       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2348     }
2349     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2350     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2351   }
2352   /*CpvAccess(_reduce_num_children) = 0;*/
2353   /*CpvAccess(_reduce_received) = 0;*/
2354   msg = mergedData;
2355   if (red->parent != -1) {
2356     if (red->ops.pupFn != NULL) {
2357       pup_er p = pup_new_sizer();
2358       (red->ops.pupFn)(p, mergedData);
2359       msg_size = pup_size(p) + CmiReservedHeaderSize;
2360       pup_destroy(p);
2361       msg = CmiAlloc(msg_size);
2362       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2363       (red->ops.pupFn)(p, mergedData);
2364       pup_destroy(p);
2365       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2366     }
2367     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2368     CmiSetRedID(msg, red->seqID);
2369     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2370     CmiSyncSendAndFree(red->parent, msg_size, msg);
2371   } else {
2372     (red->ops.destination)(msg);
2373   }
2374   CmiClearReduction(red->seqID);
2375 }
2376
2377 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2378   return data;
2379 }
2380
2381 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2382   CmiAssert(red->localContributed == 0);
2383   red->localContributed = 1;
2384   red->localData = msg;
2385   red->localSize = size;
2386   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2387   red->parent = CmiSpanTreeParent(CmiMyPe());
2388   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2389   red->ops.mergeFn = mergeFn;
2390   red->ops.pupFn = NULL;
2391   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2392   CmiSendReduce(red);
2393 }
2394
2395 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2396                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2397                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2398   CmiAssert(red->localContributed == 0);
2399   red->localContributed = 1;
2400   red->localData = data;
2401   red->localSize = 0;
2402   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2403   red->parent = CmiSpanTreeParent(CmiMyPe());
2404   red->ops.destination = dest;
2405   red->ops.mergeFn = mergeFn;
2406   red->ops.pupFn = pupFn;
2407   red->ops.deleteFn = deleteFn;
2408   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2409   CmiSendReduce(red);
2410 }
2411
2412 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2413   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2414   CmiGlobalReduce(msg, size, mergeFn, red);
2415 }
2416
2417 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2418                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2419                      CmiReduceDeleteFn deleteFn) {
2420   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2421   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2422 }
2423
2424 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2425   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2426   CmiGlobalReduce(msg, size, mergeFn, red);
2427 }
2428
2429 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2430                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2431                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2432   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2433   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2434 }
2435
2436 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2437   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2438   int myPos;
2439   CmiAssert(red->localContributed == 0);
2440   red->localContributed = 1;
2441   red->localData = msg;
2442   red->localSize = size;
2443   for (myPos=0; myPos<npes; ++myPos) {
2444     if (pes[myPos] == CmiMyPe()) break;
2445   }
2446   CmiAssert(myPos < npes);
2447   red->numChildren = npes - (myPos << 2) - 1;
2448   if (red->numChildren > 4) red->numChildren = 4;
2449   if (red->numChildren < 0) red->numChildren = 0;
2450   if (myPos == 0) red->parent = -1;
2451   else red->parent = pes[(myPos - 1) >> 2];
2452   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2453   red->ops.mergeFn = mergeFn;
2454   red->ops.pupFn = NULL;
2455   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2456   CmiSendReduce(red);
2457 }
2458
2459 void CmiListReduceStruct(int npes, int *pes,
2460                      void *data, CmiReducePupFn pupFn,
2461                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2462                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2463   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2464   int myPos;
2465   CmiAssert(red->localContributed == 0);
2466   red->localContributed = 1;
2467   red->localData = data;
2468   red->localSize = 0;
2469   for (myPos=0; myPos<npes; ++myPos) {
2470     if (pes[myPos] == CmiMyPe()) break;
2471   }
2472   CmiAssert(myPos < npes);
2473   red->numChildren = npes - (myPos << 2) - 1;
2474   if (red->numChildren > 4) red->numChildren = 4;
2475   if (red->numChildren < 0) red->numChildren = 0;
2476   red->parent = (myPos - 1) >> 2;
2477   if (myPos == 0) red->parent = -1;
2478   red->ops.destination = dest;
2479   red->ops.mergeFn = mergeFn;
2480   red->ops.pupFn = pupFn;
2481   red->ops.deleteFn = deleteFn;
2482   CmiSendReduce(red);
2483 }
2484
2485 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2486   int npes, *pes;
2487   CmiLookupGroup(grp, &npes, &pes);
2488   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2489 }
2490
2491 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2492                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2493                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2494   int npes, *pes;
2495   CmiLookupGroup(grp, &npes, &pes);
2496   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2497 }
2498
2499 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2500   CmiAbort("Feel free to implement CmiNodeReduce...");
2501   /*
2502   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2503   CpvAccess(_reduce_data) = data;
2504   CpvAccess(_reduce_data_size) = size;
2505   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2506   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2507   _reduce_pupFn = NULL;
2508   _reduce_mergeFn = mergeFn;
2509   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2510   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2511   */
2512 }
2513 #if 0
2514 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2515   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2516       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2517 }
2518 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2519   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2520 }
2521 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2522   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2523       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2524 }
2525 #endif
2526
2527 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2528                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2529                          CmiReduceDeleteFn deleteFn) {
2530   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2531 /*
2532   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2533   CpvAccess(_reduce_data) = data;
2534   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2535   _reduce_destination = dest;
2536   _reduce_pupFn = pupFn;
2537   _reduce_mergeFn = mergeFn;
2538   _reduce_deleteFn = deleteFn;
2539   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2540   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2541   */
2542 }
2543
2544 void CmiHandleReductionMessage(void *msg) {
2545   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2546   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2547   red->remoteData[red->numRemoteReceived++] = msg;
2548   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2549   CmiSendReduce(red);
2550 /*
2551   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2552   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2553   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2554 }
2555
2556 void CmiReductionsInit() {
2557   int i;
2558   CpvInitialize(int, CmiReductionMessageHandler);
2559   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2560   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2561   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2562   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2563   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2564   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2565   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2566   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2567   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2568   CpvInitialize(int, _reduce_info_size);
2569   CpvAccess(_reduce_info_size) = 4;
2570   CpvInitialize(CmiReduction**, _reduce_info);
2571   CpvAccess(_reduce_info) = malloc(16*sizeof(CmiReduction*));
2572   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2573 }
2574
2575 /*****************************************************************************
2576  *
2577  * Multicast groups
2578  *
2579  ****************************************************************************/
2580
2581 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2582
2583 typedef struct GroupDef
2584 {
2585   union {
2586     char core[CmiMsgHeaderSizeBytes];
2587     struct GroupDef *next;
2588   } core;
2589   CmiGroup group;
2590   int npes;
2591   int pes[1];
2592 }
2593 *GroupDef;
2594
2595 #define GROUPTAB_SIZE 101
2596
2597 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2598 CpvStaticDeclare(int, CmiGroupCounter);
2599 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2600
2601 void CmiGroupHandler(GroupDef def)
2602 {
2603   /* receive group definition, insert into group table */
2604   GroupDef *table = CpvAccess(CmiGroupTable);
2605   unsigned int hashval, bucket;
2606   hashval = (def->group.id ^ def->group.pe);
2607   bucket = hashval % GROUPTAB_SIZE;
2608   def->core.next = table[bucket];
2609   table[bucket] = def;
2610 }
2611
2612 CmiGroup CmiEstablishGroup(int npes, int *pes)
2613 {
2614   /* build new group definition, broadcast it */
2615   CmiGroup grp; GroupDef def; int len, i;
2616   grp.id = CpvAccess(CmiGroupCounter)++;
2617   grp.pe = CmiMyPe();
2618   len = sizeof(struct GroupDef)+(npes*sizeof(int));
2619   def = (GroupDef)CmiAlloc(len);
2620   def->group = grp;
2621   def->npes = npes;
2622   for (i=0; i<npes; i++)
2623     def->pes[i] = pes[i];
2624   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2625   CmiSyncBroadcastAllAndFree(len, def);
2626   return grp;
2627 }
2628
2629 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2630 {
2631   unsigned int hashval, bucket;  GroupDef def;
2632   GroupDef *table = CpvAccess(CmiGroupTable);
2633   hashval = (grp.id ^ grp.pe);
2634   bucket = hashval % GROUPTAB_SIZE;
2635   for (def=table[bucket]; def; def=def->core.next) {
2636     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2637       *npes = def->npes;
2638       *pes = def->pes;
2639       return;
2640     }
2641   }
2642   *npes = 0; *pes = 0;
2643 }
2644
2645 void CmiGroupInit()
2646 {
2647   CpvInitialize(int, CmiGroupHandlerIndex);
2648   CpvInitialize(int, CmiGroupCounter);
2649   CpvInitialize(GroupDef *, CmiGroupTable);
2650   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2651   CpvAccess(CmiGroupCounter) = 0;
2652   CpvAccess(CmiGroupTable) =
2653     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2654   if (CpvAccess(CmiGroupTable) == 0)
2655     CmiAbort("Memory Allocation Error");
2656 }
2657
2658 #endif
2659
2660 /*****************************************************************************
2661  *
2662  * Common List-Cast and Multicast Code
2663  *
2664  ****************************************************************************/
2665
2666 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2667
2668 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2669 {
2670   int i;
2671 #if CMK_BROADCAST_USE_CMIREFERENCE
2672   for(i=0;i<npes;i++) {
2673     if (pes[i] == CmiMyPe())
2674       CmiSyncSend(pes[i], len, msg);
2675     else {
2676       CmiReference(msg);
2677       CmiSyncSendAndFree(pes[i], len, msg);
2678     }
2679   }
2680 #else
2681   for(i=0;i<npes;i++) {
2682     CmiSyncSend(pes[i], len, msg);
2683   }
2684 #endif
2685 }
2686
2687 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2688 {
2689   /* A better asynchronous implementation may be wanted, but at least it works */
2690   CmiSyncListSendFn(npes, pes, len, msg);
2691   return (CmiCommHandle) 0;
2692 }
2693
2694 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2695 {
2696 #if CMK_BROADCAST_USE_CMIREFERENCE
2697   if (npes == 1) {
2698     CmiSyncSendAndFree(pes[0], len, msg);
2699     return;
2700   }
2701   CmiSyncListSendFn(npes, pes, len, msg);
2702   CmiFree(msg);
2703 #else
2704   int i;
2705   for(i=0;i<npes-1;i++) {
2706     CmiSyncSend(pes[i], len, msg);
2707   }
2708   if (npes>0)
2709     CmiSyncSendAndFree(pes[npes-1], len, msg);
2710   else 
2711     CmiFree(msg);
2712 #endif
2713 }
2714
2715 #endif
2716
2717 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2718
2719 typedef struct MultiMsg
2720 {
2721   char core[CmiMsgHeaderSizeBytes];
2722   CmiGroup group;
2723   int pos;
2724   int origlen;
2725 }
2726 *MultiMsg;
2727
2728
2729 CpvDeclare(int, CmiMulticastHandlerIndex);
2730
2731 void CmiMulticastDeliver(MultiMsg msg)
2732 {
2733   int npes, *pes; int olen, nlen, pos, child1, child2;
2734   olen = msg->origlen;
2735   nlen = olen + sizeof(struct MultiMsg);
2736   CmiLookupGroup(msg->group, &npes, &pes);
2737   if (pes==0) {
2738     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2739     return;
2740   }
2741   if (npes==0) {
2742     CmiFree(msg);
2743     return;
2744   }
2745   if (msg->pos == -1) {
2746     msg->pos=0;
2747     CmiSyncSendAndFree(pes[0], nlen, msg);
2748     return;
2749   }
2750   pos = msg->pos;
2751   child1 = ((pos+1)<<1);
2752   child2 = child1-1;
2753   if (child1 < npes) {
2754     msg->pos = child1;
2755     CmiSyncSend(pes[child1], nlen, msg);
2756   }
2757   if (child2 < npes) {
2758     msg->pos = child2;
2759     CmiSyncSend(pes[child2], nlen, msg);
2760   }
2761   if(olen < sizeof(struct MultiMsg)) {
2762     memcpy(msg, msg+1, olen);
2763   } else {
2764     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
2765   }
2766   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2767 }
2768
2769 void CmiMulticastHandler(MultiMsg msg)
2770 {
2771   CmiMulticastDeliver(msg);
2772 }
2773
2774 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2775 {
2776   int newlen; MultiMsg newmsg;
2777   newlen = len + sizeof(struct MultiMsg);
2778   newmsg = (MultiMsg)CmiAlloc(newlen);
2779   if(len < sizeof(struct MultiMsg)) {
2780     memcpy(newmsg+1, msg, len);
2781   } else {
2782     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
2783     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
2784   }
2785   newmsg->group = grp;
2786   newmsg->origlen = len;
2787   newmsg->pos = -1;
2788   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2789   CmiMulticastDeliver(newmsg);
2790 }
2791
2792 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2793 {
2794   CmiSyncMulticastFn(grp, len, msg);
2795   CmiFree(msg);
2796 }
2797
2798 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2799 {
2800   CmiError("Async Multicast not implemented.");
2801   return (CmiCommHandle) 0;
2802 }
2803
2804 void CmiMulticastInit()
2805 {
2806   CpvInitialize(int, CmiMulticastHandlerIndex);
2807   CpvAccess(CmiMulticastHandlerIndex) =
2808     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2809 }
2810
2811 #endif
2812
2813 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2814 extern void *arena_malloc(int size);
2815 extern void arena_free(void *blockPtr);
2816 #endif
2817
2818 /***************************************************************************
2819  *
2820  * Memory Allocation routines 
2821  *
2822  * A block of memory can consist of multiple chunks.  Each chunk has
2823  * a sizefield and a refcount.  The first chunk's refcount is a reference
2824  * count.  That's how many CmiFrees it takes to free the message.
2825  * Subsequent chunks have a refcount which is less than zero.  This is
2826  * the offset back to the start of the first chunk.
2827  *
2828  * Each chunk has a CmiChunkHeader before the user data, with the fields:
2829  *
2830  *  size: The user-allocated size of the chunk, in bytes.
2831  *
2832  *  ref: A magic reference count object. Ordinary blocks start with
2833  *     reference count 1.  When the reference count reaches zero,
2834  *     the block is deleted.  To support nested buffers, the 
2835  *     reference count can also be negative, which means it is 
2836  *     a byte offset to the enclosing buffer's reference count.
2837  *
2838  ***************************************************************************/
2839
2840
2841 void *CmiAlloc(int size)
2842 {
2843
2844   char *res;
2845
2846 #if CONVERSE_VERSION_ELAN
2847   res = (char *) elan_CmiAlloc(size+sizeof(CmiChunkHeader));
2848 #elif CONVERSE_VERSION_VMI
2849   res = (char *) CMI_VMI_CmiAlloc(size+sizeof(CmiChunkHeader));
2850 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2851   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
2852 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2853   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
2854 #elif CMK_CONVERSE_GEMINI_UGNI
2855   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
2856 #elif CONVERSE_POOL
2857   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
2858 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
2859   MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
2860 #elif CMK_SMP && CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
2861   res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
2862 #else
2863   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
2864 #endif
2865
2866   _MEMCHECK(res);
2867
2868 #ifdef MEMMONITOR
2869   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
2870   CpvAccess(AllocCount)++;
2871   CpvAccess(BlocksAllocated)++;
2872   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
2873     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
2874   }
2875   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
2876     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2877             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2878             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2879     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
2880   }
2881   if ((CpvAccess(AllocCount) % 1000) == 0) {
2882     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2883             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2884             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2885   }
2886 #endif
2887
2888   res+=sizeof(CmiChunkHeader);
2889   SIZEFIELD(res)=size;
2890   REFFIELD(res)=1;
2891   return (void *)res;
2892 }
2893
2894 /** Follow the header links out to the most enclosing block */
2895 static void *CmiAllocFindEnclosing(void *blk) {
2896   int refCount = REFFIELD(blk);
2897   while (refCount < 0) {
2898     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
2899     refCount = REFFIELD(blk);
2900   }
2901   return blk;
2902 }
2903
2904 int CmiGetReference(void *blk)
2905 {
2906   return REFFIELD(CmiAllocFindEnclosing(blk));
2907 }
2908
2909 /** Increment the reference count for this block's owner.
2910     This call must be matched by an equivalent CmiFree. */
2911 void CmiReference(void *blk)
2912 {
2913   REFFIELD(CmiAllocFindEnclosing(blk))++;
2914 }
2915
2916 /** Return the size of the user portion of this block. */
2917 int CmiSize(void *blk)
2918 {
2919   return SIZEFIELD(blk);
2920 }
2921
2922 /** Decrement the reference count for this block. */
2923 void CmiFree(void *blk)
2924 {
2925   void *parentBlk=CmiAllocFindEnclosing(blk);
2926   int refCount=REFFIELD(parentBlk);
2927 #if CMK_ERROR_CHECKING
2928   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
2929     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
2930 #endif
2931   refCount--;
2932   REFFIELD(parentBlk) = refCount;
2933   if(refCount==0) { /* This was the last reference to the block-- free it */
2934 #ifdef MEMMONITOR
2935     int size=SIZEFIELD(parentBlk);
2936     if (size > 1000000000) /* Absurdly large size field-- warning */
2937       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
2938     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
2939     CpvAccess(BlocksAllocated)--;
2940 #endif
2941
2942 #if CONVERSE_VERSION_ELAN
2943     elan_CmiFree(BLKSTART(parentBlk));
2944 #elif CONVERSE_VERSION_VMI
2945     CMI_VMI_CmiFree(BLKSTART(parentBlk));
2946 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2947     arena_free(BLKSTART(parentBlk));
2948 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2949     /* is this message the head of a MultipleSend that we received?
2950        Then the parts with INFIMULTIPOOL have metadata which must be 
2951        unregistered and freed.  */
2952 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
2953     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
2954       {
2955         infi_freeMultipleSend(parentBlk);
2956       }
2957 #endif
2958     infi_CmiFree(BLKSTART(parentBlk));
2959 #elif CMK_CONVERSE_GEMINI_UGNI
2960     LrtsFree(BLKSTART(parentBlk));
2961 #elif CONVERSE_POOL
2962     CmiPoolFree(BLKSTART(parentBlk));
2963 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
2964     MPI_Free_mem(parentBlk);
2965 #elif CMK_SMP && CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
2966     CmiFree_bgq(BLKSTART(parentBlk));
2967 #else
2968     free_nomigrate(BLKSTART(parentBlk));
2969 #endif
2970   }
2971 }
2972
2973
2974 /***************************************************************************
2975  *
2976  * Temporary-memory Allocation routines 
2977  *
2978  *  This buffer augments the storage available on the regular machine stack
2979  * for fairly large temporary buffers, which allows us to use smaller machine
2980  * stacks.
2981  *
2982  ***************************************************************************/
2983
2984 #define CMI_TMP_BUF_MAX 128*1024 /* Allow this much temporary storage. */
2985
2986 typedef struct {
2987   char *buf; /* Start of temporary buffer */
2988   int cur; /* First unused location in temporary buffer */
2989   int max; /* Length of temporary buffer */
2990 } CmiTmpBuf_t;
2991 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
2992
2993 static void CmiTmpSetup(CmiTmpBuf_t *b) {
2994   b->buf=malloc(CMI_TMP_BUF_MAX);
2995   b->cur=0;
2996   b->max=CMI_TMP_BUF_MAX;
2997 }
2998
2999 void *CmiTmpAlloc(int size) {
3000   if (!CpvInitialized(CmiTmpBuf)) {
3001     return malloc(size);
3002   }
3003   else { /* regular case */
3004     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3005     void *t;
3006     if (b->cur+size>b->max) {
3007       if (b->max==0) /* We're just uninitialized */
3008         CmiTmpSetup(b);
3009       else /* We're really out of space! */
3010         CmiAbort("CmiTmpAlloc: asked for too much temporary buffer space");
3011     }
3012     t=b->buf+b->cur;
3013     b->cur+=size;
3014     return t;
3015   }
3016 }
3017 void CmiTmpFree(void *t) {
3018   if (!CpvInitialized(CmiTmpBuf)) {
3019     free(t);
3020   }
3021   else { /* regular case */
3022     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3023     /* t should point into our temporary buffer: figure out where */
3024     int cur=((const char *)t)-b->buf;
3025 #if CMK_ERROR_CHECKING
3026     if (cur<0 || cur>b->max)
3027       CmiAbort("CmiTmpFree: called with an invalid pointer");
3028 #endif
3029     b->cur=cur;
3030   }
3031 }
3032
3033 void CmiTmpInit(char **argv) {
3034   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3035   /* Set up this processor's temporary buffer */
3036   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3037 }
3038
3039 /******************************************************************************
3040
3041   Cross-platform directory creation
3042
3043   ****************************************************************************/
3044 #ifdef _MSC_VER
3045 /* Windows directory creation: */
3046 #include <windows.h>
3047
3048 void CmiMkdir(const char *dirName) {
3049         CreateDirectory(dirName,NULL);
3050 }
3051
3052 #else /* !_MSC_VER */
3053 /* UNIX directory creation */
3054 #include <unistd.h> 
3055 #include <sys/stat.h> /* from "mkdir" man page */
3056 #include <sys/types.h>
3057
3058 void CmiMkdir(const char *dirName) {
3059 #ifndef __MINGW_H
3060         mkdir(dirName,0777);
3061 #else
3062         mkdir(dirName);
3063 #endif
3064 }
3065
3066 #endif
3067
3068
3069 /******************************************************************************
3070
3071   Multiple Send function                               
3072
3073   ****************************************************************************/
3074
3075
3076
3077
3078
3079 /****************************************************************************
3080 * DESCRIPTION : This function call allows the user to send multiple messages
3081 *               from one processor to another, all intended for differnet 
3082 *               handlers.
3083 *
3084 *               Parameters :
3085 *
3086 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3087 *
3088 ****************************************************************************/
3089 /* Round up message size to the message granularity. 
3090    Does this by adding, then truncating.
3091 */
3092 static int roundUpSize(unsigned int s) {
3093   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3094 }
3095 /* Return the amount of message padding required for a message
3096    with this many user bytes. 
3097  */
3098 static int paddingSize(unsigned int s) {
3099   return roundUpSize(s)-s;
3100 }
3101
3102 /* Message header for a bundle of multiple-sent messages */
3103 typedef struct {
3104   char convHeader[CmiMsgHeaderSizeBytes];
3105   int nMessages; /* Number of distinct messages bundled below. */
3106   double pad; /* To align the first message, which follows this header */
3107 } CmiMultipleSendHeader;
3108
3109 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3110 /* given a pointer to a multisend message clean up the metadata */
3111
3112 void infi_freeMultipleSend(void *msgWhole)
3113 {
3114   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3115   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3116   int offset=sizeof(CmiMultipleSendHeader);
3117   int m;
3118   void *thisMsg=NULL;
3119   if (pad != 1234567.89) return;
3120   for(m=0;m<len;m++)
3121     {
3122       /*unreg meta, free meta, move the ptr */
3123       /* note these weird little things are not pooled */
3124       /* do NOT free the message here, we are only a part of this buffer*/
3125       infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3126       char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3127       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3128       infi_unregAndFreeMeta(ch->metaData);
3129       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3130     }
3131 }
3132 #endif
3133
3134
3135 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3136 {
3137   CmiMultipleSendHeader header;
3138   int m; /* Outgoing message */
3139
3140 #if CMK_USE_IBVERBS
3141   infiCmiChunkHeader *msgHdr;
3142 #else
3143   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3144 #endif
3145         
3146   double pad = 0; /* padding required */
3147   int vecLen; /* Number of pieces in outgoing message vector */
3148   int *vecSizes; /* Sizes of each piece we're sending out. */
3149   char **vecPtrs; /* Pointers to each piece we're sending out. */
3150   int vec; /* Entry we're currently filling out in above array */
3151         
3152 #if CMK_USE_IBVERBS
3153   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3154 #else
3155   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3156 #endif
3157         
3158   /* Allocate memory for the outgoing vector*/
3159   vecLen=1+3*len; /* Header and 3 parts per message */
3160   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3161   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3162   vec=0;
3163   
3164   /* Build the header */
3165   header.nMessages=len;
3166   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3167   header.pad = 1234567.89;
3168 #if CMK_IMMEDIATE_MSG
3169   if (immed) CmiBecomeImmediate(&header);
3170 #endif
3171   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3172   vec++;
3173
3174   /* Build an entry for each message: 
3175          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3176   */
3177   for (m=0;m<len;m++) {
3178 #if CMK_USE_IBVERBS
3179     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3180     msgHdr[m].chunkHeader.ref=0; /* Reference count will be filled out on receive side */
3181     msgHdr[m].metaData=NULL;
3182 #else
3183     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3184     msgHdr[m].ref=0; /* Reference count will be filled out on receive side */
3185 #endif          
3186     
3187     /* First send the message's CmiChunkHeader (for use on receive side) */
3188 #if CMK_USE_IBVERBS
3189     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3190 #else
3191     vecSizes[vec]=sizeof(CmiChunkHeader); 
3192 #endif          
3193                 vecPtrs[vec]=(char *)&msgHdr[m];
3194     vec++;
3195     
3196     /* Now send the actual message data */
3197     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3198     vec++;
3199     
3200     /* Now send padding to align the next message on a double-boundary */
3201     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3202     vec++;
3203   }
3204   CmiAssert(vec==vecLen);
3205   
3206   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3207   
3208   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3209   CmiTmpFree(vecSizes);
3210   CmiTmpFree(msgHdr);
3211 }
3212
3213 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3214 {
3215   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3216 }
3217
3218 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3219 {
3220   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3221 }
3222
3223 /****************************************************************************
3224 * DESCRIPTION : This function initializes the main handler required for the
3225 *               CmiMultipleSend() function to work. 
3226 *               
3227 *               This function should be called once in any Converse program
3228 *               that uses CmiMultipleSend()
3229 *
3230 ****************************************************************************/
3231
3232 static void CmiMultiMsgHandler(char *msgWhole);
3233
3234 void CmiInitMultipleSend(void)
3235 {
3236   CpvInitialize(int,CmiMainHandlerIDP); 
3237   CpvAccess(CmiMainHandlerIDP) =
3238     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3239 }
3240
3241 /****************************************************************************
3242 * DESCRIPTION : This function is the main handler that splits up the messages
3243 *               CmiMultipleSend() pastes together. 
3244 *
3245 ****************************************************************************/
3246
3247 static void CmiMultiMsgHandler(char *msgWhole)
3248 {
3249   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3250   int offset=sizeof(CmiMultipleSendHeader);
3251   int m;
3252   for (m=0;m<len;m++) {
3253 #if CMK_USE_IBVERBS
3254     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3255     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3256     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3257     ch->chunkHeader.ref=msgWhole-msg; 
3258     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3259 #else
3260     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3261     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3262     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3263     ch->ref=msgWhole-msg; 
3264 #endif          
3265     /* Link new message to owner via a negative ref pointer */
3266     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3267     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3268 #if CMK_USE_IBVERBS
3269     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3270 #else
3271     offset+= sizeof(CmiChunkHeader) + msgSize;
3272 #endif          
3273   }
3274   /* Release our reference to the whole message.  The message will
3275      only actually be deleted once all its sub-messages are free'd as well. */
3276   CmiFree(msgWhole);
3277 }
3278
3279 /****************************************************************************
3280 * Hypercube broadcast message passing.
3281 ****************************************************************************/
3282
3283 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3284   int num_pes = 0;
3285   for ( ; k>=0; --k) {
3286     /* add the processor destination at level k if it exist */
3287     dest_pes[num_pes] = mype ^ (1<<k);
3288     if (dest_pes[num_pes] >= total_pes) {
3289       /* find the first proc in the other part of the current dimention */
3290       dest_pes[num_pes] &= (-1)<<k;
3291       /* if the first proc there is over CmiNumPes() then there is no other
3292          dimension, otherwise if it is valid compute my correspondent in such
3293          a way to minimize the load for every processor */
3294       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((-1)<<k))) % (total_pes - dest_pes[num_pes]);
3295       }
3296     if (dest_pes[num_pes] < total_pes) {
3297       /* if the destination is in the acceptable range increment num_pes */
3298       ++num_pes;
3299     }
3300   }
3301   return num_pes;
3302 }
3303
3304
3305 /****************************************************************************
3306 * DESCRIPTION : This function initializes the main handler required for the
3307 *               Immediate message
3308 *               
3309 *               This function should be called once in any Converse program
3310 *
3311 ****************************************************************************/
3312
3313 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3314 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3315
3316 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3317
3318 /* xdl is the real handler */
3319 static void CmiImmediateMsgHandler(char *msg)
3320 {
3321   CmiSetHandler(msg, CmiGetXHandler(msg));
3322   CmiHandleMessage(msg);
3323 }
3324
3325 void CmiInitImmediateMsg(void)
3326 {
3327   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3328   CpvAccess(CmiImmediateMsgHandlerIdx) =
3329     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3330 }
3331
3332 /*#if !CMK_IMMEDIATE_MSG
3333 #if !CMK_MACHINE_PROGRESS_DEFINED
3334 void CmiProbeImmediateMsg()
3335 {
3336 }
3337 #endif
3338 #endif*/
3339
3340 /******** Idle timeout module (+idletimeout=30) *********/
3341
3342 typedef struct {
3343   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3344   int is_idle;/*Boolean currently-idle flag*/
3345   int call_count;/*Number of timeout calls currently in flight*/
3346 } cmi_cpu_idlerec;
3347
3348 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3349 {
3350   rec->call_count--;
3351   if(rec->call_count==0 && rec->is_idle==1) {
3352     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3353     CmiAbort("Exiting.\n");
3354   }
3355 }
3356 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3357 {
3358   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3359   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3360   rec->is_idle = 1;
3361 }
3362 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3363 {
3364   rec->is_idle = 0;
3365 }
3366 static void CIdleTimeoutInit(char **argv)
3367 {
3368   int idle_timeout=0; /*Seconds to wait*/
3369   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3370   if(idle_timeout != 0) {
3371     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3372     _MEMCHECK(rec);
3373     rec->idle_timeout=idle_timeout*1000;
3374     rec->is_idle=0;
3375     rec->call_count=0;
3376     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3377     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3378   }
3379 }
3380
3381 /*****************************************************************************
3382  *
3383  * Converse Initialization
3384  *
3385  *****************************************************************************/
3386
3387 extern void CrnInit(void);
3388 extern void CmiIsomallocInit(char **argv);
3389 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3390 void CmiIOInit(char **argv);
3391 #endif
3392
3393 /* defined in cpuaffinity.c */
3394 extern void CmiInitCPUAffinityUtil();
3395
3396 static void CmiProcessPriority(char **argv)
3397 {
3398   int dummy, nicelevel=-100;      /* process priority */
3399   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3400   /* ignore others */
3401   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3402   /* call setpriority once on each process to set process's priority */
3403   if (CmiMyRank() == 0 && nicelevel != -100)  {
3404 #ifndef _WIN32
3405     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3406       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3407       perror("setpriority");
3408       CmiAbort("setpriority failed.");
3409     }
3410     else
3411       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3412 #else
3413     HANDLE hProcess = GetCurrentProcess();
3414     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3415     char *prio_str = "NORMAL_PRIORITY_CLASS";
3416     BOOL status;
3417     /*
3418        <-20:      real time
3419        -20--10:   high 
3420        -10-0:     above normal
3421        0:         normal
3422        0-10:      below normal
3423        10-:       idle
3424     */
3425     if (0) ;
3426 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3427     else if (nicelevel<10 && nicelevel>0) {
3428       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3429       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3430     }
3431 #endif
3432     else if (nicelevel>0) {
3433       dwPriorityClass = IDLE_PRIORITY_CLASS;
3434       prio_str = "IDLE_PRIORITY_CLASS";
3435     }
3436     else if (nicelevel<=-20) {
3437       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3438       prio_str = "REALTIME_PRIORITY_CLASS";
3439     }
3440 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3441     else if (nicelevel>-10 && nicelevel<0) {
3442       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3443       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3444     }
3445 #endif
3446     else if (nicelevel<0) {
3447       dwPriorityClass = HIGH_PRIORITY_CLASS;
3448       prio_str = "HIGH_PRIORITY_CLASS";
3449     }
3450     status = SetPriorityClass(hProcess, dwPriorityClass);
3451     if (!status)  {
3452         int err=GetLastError();
3453         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3454         CmiAbort("SetPriorityClass failed.");
3455     }
3456     else
3457       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3458 #endif
3459   }
3460 }
3461
3462 void CommunicationServerInit()
3463 {
3464 #if CMK_IMMEDIATE_MSG
3465   CQdCpvInit();
3466   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3467 #endif
3468 }
3469
3470
3471 static int testEndian(void)
3472 {
3473         int test=0x1c;
3474         unsigned char *c=(unsigned char *)&test;
3475         if (c[sizeof(int)-1]==0x1c)
3476                 /* Macintosh and most workstations are big-endian */
3477                 return 1;   /* Big-endian machine */
3478         if (c[0]==0x1c)
3479                 /* Intel x86 PC's, and DEC VAX are little-endian */
3480                 return 0;  /* Little-endian machine */
3481         return -2;  /*Unknown integer type */
3482 }
3483
3484 int CmiEndianness()
3485 {
3486   static int _cmi_endianness = -1;
3487   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3488   CmiAssert(_cmi_endianness != -2);
3489   return  _cmi_endianness;
3490 }
3491
3492 /**
3493   Main Converse initialization routine.  This routine is 
3494   called by the machine file (machine.c) to set up Converse.
3495   It's "Common" because it's shared by all the machine.c files. 
3496   
3497   The main task of this routine is to set up all the Cpv's
3498   (message queues, handler tables, etc.) used during main execution.
3499   
3500   On SMP versions, this initialization routine is called by 
3501   *all* processors of a node simultaniously.  It's *also* called
3502   by the communication thread, which is rather strange but needed
3503   for immediate messages.  Each call to this routine expects a 
3504   different copy of the argv arguments, so use CmiCopyArgs(argv).
3505   
3506   Requires:
3507     - A working network layer.
3508     - Working Cpv's and CmiNodeBarrier.
3509     - CthInit to already have been called.  CthInit is called
3510       from the machine layer directly, because some machine layers
3511       (like uth) use Converse threads internally.
3512
3513   Initialization is somewhat subtle, in that various modules
3514   won't work properly until they're initialized.  For example,
3515   nobody can register handlers before calling CmiHandlerInit.
3516 */
3517 void ConverseCommonInit(char **argv)
3518 {
3519
3520 /**
3521  * The reason to initialize this variable here:
3522  * cmiArgDebugFlag is possibly accessed in CmiPrintf/CmiError etc.,
3523  * therefore, we have to initialize this variable before any calls
3524  * to those functions (such as CmiPrintf). Otherwise, we may encounter
3525  * a memory segmentation fault (bad memory access). Note, even
3526  * testing CpvInitialized(cmiArgDebugFlag) doesn't help to solve
3527  * this problem because the variable indicating whether cmiArgDebugFlag is 
3528  * initialized or not is not initialized, thus possibly causing another
3529  * bad memory access. --Chao Mei
3530  */
3531   CpvInitialize(int, _urgentSend);
3532   CpvAccess(_urgentSend) = 0;
3533 #if CMK_CCS_AVAILABLE
3534   CpvInitialize(int, cmiArgDebugFlag);
3535   CpvAccess(cmiArgDebugFlag) = 0;
3536 #endif
3537   CpvInitialize(int,charmLibExitFlag);
3538   CpvAccess(charmLibExitFlag) = 0;
3539
3540   CpvInitialize(int,_curRestartPhase);
3541   CpvAccess(_curRestartPhase)=1;
3542   CmiArgInit(argv);
3543   CmiMemoryInit(argv);
3544 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3545   CmiIOInit(argv);
3546 #endif
3547   if (CmiMyPe() == 0)
3548       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3549
3550   CpvInitialize(int, cmiMyPeIdle);
3551   CpvAccess(cmiMyPeIdle) = 0;
3552
3553 /* #if CONVERSE_POOL */
3554   CmiPoolAllocInit(30);  
3555 /* #endif */
3556   CmiTmpInit(argv);
3557   CmiTimerInit(argv);
3558   CstatsInit(argv);
3559   CmiInitCPUAffinityUtil();
3560
3561   CcdModuleInit(argv);
3562   CmiHandlerInit();
3563   CmiReductionsInit();
3564   CIdleTimeoutInit(argv);
3565   
3566 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the net-*-smp versions*/
3567   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for net-smp-*) ?")){
3568     if(CmiMyRank() == 0) _Cmi_noprocforcommthread=1;
3569    }
3570 #endif
3571         
3572 #if CMK_TRACE_ENABLED
3573   traceInit(argv);
3574 /*initTraceCore(argv);*/ /* projector */
3575 #endif
3576   CmiProcessPriority(argv);
3577
3578   CmiPersistentInit();
3579   CmiIsomallocInit(argv);
3580   CmiDeliversInit();
3581   CsdInit(argv);
3582 #if CMK_CCS_AVAILABLE
3583   CcsInit(argv);
3584 #endif
3585   CpdInit();
3586   CthSchedInit();
3587   CmiGroupInit();
3588   CmiMulticastInit();
3589   CmiInitMultipleSend();
3590   CQdInit();
3591
3592   CrnInit();
3593   CmiInitImmediateMsg();
3594   CldModuleInit(argv);
3595   
3596 #if CMK_CELL
3597   void CmiInitCell();
3598   CmiInitCell();
3599 #endif
3600
3601 #ifdef CMK_CUDA
3602   initHybridAPI(CmiMyPe()); 
3603 #endif
3604
3605   /* main thread is suspendable */
3606 /*
3607   CthSetSuspendable(CthSelf(), 0);
3608 */
3609
3610 #if CMK_BIGSIM_CHARM
3611    /* have to initialize QD here instead of _initCharm */
3612   extern void initQd(char **argv);
3613   initQd(argv);
3614 #endif
3615 }
3616
3617 void ConverseCommonExit(void)
3618 {
3619   CcsImpl_kill();
3620
3621 #if CMK_TRACE_ENABLED
3622   traceClose();
3623 /*closeTraceCore();*/ /* projector */
3624 #endif
3625
3626 #if CMI_IO_BUFFER_EXPLICIT
3627   CmiFlush(stdout);  /* end of program, always flush */
3628 #endif
3629
3630 #if CMK_CELL
3631   CloseOffloadAPI();
3632 #endif
3633
3634 #if CMK_CUDA
3635   exitHybridAPI(); 
3636 #endif
3637   seedBalancerExit();
3638   EmergencyExit();
3639 }
3640
3641
3642 #if CMK_CELL != 0
3643
3644 extern void register_accel_spe_funcs(void);
3645
3646 void CmiInitCell()
3647 {
3648   // Create a unique string for each PPE to use for the timing
3649   //   data file's name
3650   char fileNameBuf[64];
3651   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3652
3653   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3654   //CcdCallOnConditionKeep(CcdPERIODIC, 
3655   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3656   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3657       (CcdVoidFn) OffloadAPIProgress, NULL);
3658
3659   // Register accelerated entry methods on the PPE
3660   register_accel_spe_funcs();
3661 }
3662
3663 #include "cell-api.c"
3664
3665 #endif
3666
3667 /****
3668  * CW Lee - 9/14/2005
3669  * Added a mechanism to allow some control over machines with extremely
3670  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3671  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3672  * coupled with a default setup using unbuffered stdout introduced
3673  * severe overheads (and hence limiting scaling) for applications like 
3674  * NAMD.
3675  */
3676 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3677 void CmiIOInit(char **argv) {
3678   CpvInitialize(int, expIOFlushFlag);
3679 #if CMI_IO_BUFFER_EXPLICIT
3680   /* 
3681      Support for an explicit buffer only makes sense if the machine
3682      layer does not wish to make its own implementation.
3683
3684      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3685      MUST NOT make use of stdout if an explicit buffer is requested.
3686
3687      The setvbuf function may only be used after opening a stream and
3688      before any other operations have been performed on it
3689   */
3690   CpvInitialize(char*, explicitIOBuffer);
3691   CpvInitialize(int, expIOBufferSize);
3692   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3693                         "Explicit IO Buffer Size")) {
3694     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3695   }
3696   if (CpvAccess(expIOBufferSize) <= 0) {
3697     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3698   }
3699   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3700                                                 sizeof(char));
3701   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
3702               CpvAccess(expIOBufferSize))) {
3703     CmiAbort("Explicit IO Buffering failed\n");
3704   }
3705 #endif
3706 #if CMI_IO_FLUSH_USER
3707   /* system default to have user control flushing of IO */
3708   /* Now look for user override */
3709   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
3710                                                  "System Controls IO Flush");
3711 #else
3712   /* system default to have system handle IO flushing */
3713   /* Now look for user override */
3714   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
3715                                                 "User Controls IO Flush");
3716 #endif
3717 }
3718 #endif
3719
3720 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3721
3722 void CmiPrintf(const char *format, ...)
3723 {
3724   CpdSystemEnter();
3725   {
3726   va_list args;
3727   va_start(args,format);
3728   vfprintf(stdout,format, args);
3729   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
3730     CmiFlush(stdout);
3731   }
3732   va_end(args);
3733 #if CMK_CCS_AVAILABLE
3734   if (CpvAccess(cmiArgDebugFlag)) {
3735     va_start(args,format);
3736     print_node0(format, args);
3737     va_end(args);
3738   }
3739 #endif
3740   }
3741   CpdSystemExit();
3742 }
3743
3744 void CmiError(const char *format, ...)
3745 {
3746   CpdSystemEnter();
3747   {
3748   va_list args;
3749   va_start(args,format);
3750   vfprintf(stderr,format, args);
3751   CmiFlush(stderr);  /* stderr is always flushed */
3752   va_end(args);
3753 #if CMK_CCS_AVAILABLE
3754   if (CpvAccess(cmiArgDebugFlag)) {
3755     va_start(args,format);
3756     print_node0(format, args);
3757     va_end(args);
3758   }
3759 #endif
3760   }
3761   CpdSystemExit();
3762 }
3763
3764 #endif
3765
3766 void __cmi_assert(const char *expr, const char *file, int line)
3767 {
3768   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
3769       CmiMyPe(), expr, file, line);
3770   CmiAbort("");
3771 }
3772
3773 char *CmiCopyMsg(char *msg, int len)
3774 {
3775   char *copy = (char *)CmiAlloc(len);
3776   _MEMCHECK(copy);
3777   memcpy(copy, msg, len);
3778   return copy;
3779 }
3780
3781 unsigned char computeCheckSum(unsigned char *data, int len)