3a23e4d9fa31389e99884cba8612f714e469ef7b
[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 #if !CMK_MEM_CHECKPOINT && !_FAULT_MLOG_ && !_FAULT_CAUSAL_
1252   CmiBarrier();
1253   CmiBarrier();
1254   CmiBarrier();
1255 #endif
1256   CpvAccess(inittime) = GetTimeBase (); 
1257 }
1258
1259 double CmiWallTimer()
1260 {
1261   unsigned long long currenttime;
1262   currenttime = GetTimeBase();
1263   //return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1264   return CpvAccess(clocktick)*(currenttime);
1265 }
1266
1267 double CmiCpuTimer()
1268 {
1269   return CmiWallTimer();
1270 }
1271
1272 double CmiTimer()
1273 {
1274   return CmiWallTimer();
1275 }
1276
1277 #endif
1278
1279
1280 #if CMK_TIMER_USE_WIN32API
1281
1282 CpvStaticDeclare(double, inittime_wallclock);
1283 CpvStaticDeclare(double, inittime_virtual);
1284
1285 double CmiStartTimer()
1286 {
1287   return 0.0;
1288 }
1289
1290 int CmiTimerAbsolute()
1291 {
1292   return 0;
1293 }
1294
1295 double CmiInitTime()
1296 {
1297   return CpvAccess(inittime_wallclock);
1298 }
1299
1300 void CmiTimerInit(char **argv)
1301 {
1302 #ifdef __CYGWIN__
1303         struct timeb tv;
1304 #else
1305         struct _timeb tv;
1306 #endif
1307         clock_t       ru;
1308
1309         CpvInitialize(double, inittime_wallclock);
1310         CpvInitialize(double, inittime_virtual);
1311         _ftime(&tv);
1312         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1313         ru = clock();
1314         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1315 }
1316
1317 double CmiCpuTimer()
1318 {
1319         clock_t ru;
1320         double currenttime;
1321
1322         ru = clock();
1323         currenttime = (double) ru/CLOCKS_PER_SEC;
1324
1325         return currenttime - CpvAccess(inittime_virtual);
1326 }
1327
1328 double CmiWallTimer()
1329 {
1330 #ifdef __CYGWIN__
1331         struct timeb tv;
1332 #else
1333         struct _timeb tv;
1334 #endif
1335         double currenttime;
1336
1337         _ftime(&tv);
1338         currenttime = tv.time*1.0 + tv.millitm*0.001;
1339
1340         return currenttime - CpvAccess(inittime_wallclock);
1341 }
1342         
1343
1344 double CmiTimer()
1345 {
1346         return CmiCpuTimer();
1347 }
1348
1349 #endif
1350
1351 #if CMK_TIMER_USE_RTC
1352
1353 #if __crayx1
1354  /* For _rtc() on Cray X1 */
1355 #include <intrinsics.h>
1356 #endif
1357
1358 static double clocktick;
1359 CpvStaticDeclare(long long, inittime_wallclock);
1360
1361 double CmiStartTimer()
1362 {
1363   return 0.0;
1364 }
1365
1366 double CmiInitTime()
1367 {
1368   return CpvAccess(inittime_wallclock);
1369 }
1370
1371 void CmiTimerInit(char **argv)
1372 {
1373   CpvInitialize(long long, inittime_wallclock);
1374   CpvAccess(inittime_wallclock) = _rtc();
1375   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1376 }
1377
1378 int CmiTimerAbsolute()
1379 {
1380   return 0;
1381 }
1382
1383 double CmiWallTimer()
1384 {
1385   long long now;
1386
1387   now = _rtc();
1388   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1389 }
1390
1391 double CmiCpuTimer()
1392 {
1393   return CmiWallTimer();
1394 }
1395
1396 double CmiTimer()
1397 {
1398   return CmiCpuTimer();
1399 }
1400
1401 #endif
1402
1403 #if CMK_TIMER_USE_AIX_READ_TIME
1404
1405 #include <sys/time.h>
1406
1407 static timebasestruct_t inittime_wallclock;
1408 static double clocktick;
1409 CpvStaticDeclare(double, inittime_virtual);
1410
1411 double CmiStartTimer()
1412 {
1413   return 0.0;
1414 }
1415
1416 double CmiInitTime()
1417 {
1418   return inittime_wallclock;
1419 }
1420
1421 void CmiTimerInit(char **argv)
1422 {
1423   struct rusage ru;
1424
1425   if (CmiMyRank() == 0) {
1426     read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1427     time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1428   }
1429
1430   CpvInitialize(double, inittime_virtual);
1431   getrusage(0, &ru);
1432   CpvAccess(inittime_virtual) =
1433     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1434     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1435 }
1436
1437 int CmiTimerAbsolute()
1438 {
1439   return 0;
1440 }
1441
1442 double CmiWallTimer()
1443 {
1444   int secs, n_secs;
1445   double curt;
1446   timebasestruct_t now;
1447   read_wall_time(&now, TIMEBASE_SZ);
1448   time_base_to_time(&now, TIMEBASE_SZ);
1449
1450   secs = now.tb_high - inittime_wallclock.tb_high;
1451   n_secs = now.tb_low - inittime_wallclock.tb_low;
1452   if (n_secs < 0)  {
1453     secs--;
1454     n_secs += 1000000000;
1455   }
1456   curt = secs*1.0 + n_secs*1e-9;
1457   return curt;
1458 }
1459
1460 double CmiCpuTimer()
1461 {
1462   struct rusage ru;
1463   double currenttime;
1464
1465   getrusage(0, &ru);
1466   currenttime =
1467     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1468     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1469   return currenttime - CpvAccess(inittime_virtual);
1470 }
1471
1472 double CmiTimer()
1473 {
1474   return CmiWallTimer();
1475 }
1476
1477 #endif
1478
1479 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1480 /** Return 1 if our outgoing message queue 
1481    for this node is longer than this many bytes. */
1482 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1483   return 0;
1484 }
1485 #endif
1486
1487 #if CMK_SIGNAL_USE_SIGACTION
1488 #include <signal.h>
1489 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)())
1490 {
1491   struct sigaction in, out ;
1492   in.sa_handler = handler;
1493   sigemptyset(&in.sa_mask);
1494   if (sig1) sigaddset(&in.sa_mask, sig1);
1495   if (sig2) sigaddset(&in.sa_mask, sig2);
1496   if (sig3) sigaddset(&in.sa_mask, sig3);
1497   in.sa_flags = 0;
1498   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1499   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1500   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1501 }
1502 #endif
1503
1504 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1505 #include <signal.h>
1506 void CmiSignal(sig1, sig2, sig3, handler)
1507 int sig1, sig2, sig3;
1508 void (*handler)();
1509 {
1510   struct sigaction in, out ;
1511   in.sa_handler = handler;
1512   sigemptyset(&in.sa_mask);
1513   if (sig1) sigaddset(&in.sa_mask, sig1);
1514   if (sig2) sigaddset(&in.sa_mask, sig2);
1515   if (sig3) sigaddset(&in.sa_mask, sig3);
1516   in.sa_flags = SA_RESTART;
1517   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1518   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1519   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1520 }
1521 #endif
1522
1523 /** 
1524  *  @addtogroup ConverseScheduler
1525  *  @{
1526  */
1527
1528 /*****************************************************************************
1529  * 
1530  * The following is the CsdScheduler function.  A common
1531  * implementation is provided below.  The machine layer can provide an
1532  * alternate implementation if it so desires.
1533  *
1534  * void CmiDeliversInit()
1535  *
1536  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1537  *        or any of the other functions in this section.
1538  *
1539  * int CmiDeliverMsgs(int maxmsgs)
1540  *
1541  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1542  *        with the Cmi, and will invoke their handlers.  It does not wait
1543  *        if no message is unavailable.  Instead, it returns the quantity
1544  *        (maxmsgs-delivered), where delivered is the number of messages it
1545  *        delivered.
1546  *
1547  * void CmiDeliverSpecificMsg(int handlerno)
1548  *
1549  *      - Waits for a message with the specified handler to show up, then
1550  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1551  *        This function _does_ wait.
1552  *
1553  * For this common implementation to work, the machine layer must provide the
1554  * following:
1555  *
1556  * void *CmiGetNonLocal()
1557  *
1558  *      - returns a message just retrieved from some other PE, not from
1559  *        local.  If no such message exists, returns 0.
1560  *
1561  * CpvExtern(CdsFifo, CmiLocalQueue);
1562  *
1563  *      - a FIFO queue containing all messages from the local processor.
1564  *
1565  *****************************************************************************/
1566
1567 void CsdBeginIdle(void)
1568 {
1569   CcdCallBacks();
1570 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1571   _LOG_E_PROC_IDLE();   /* projector */
1572 #endif
1573
1574   CpvAccess(cmiMyPeIdle) = 1;
1575
1576   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1577 }
1578
1579 void CsdStillIdle(void)
1580 {
1581   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1582 }
1583
1584 void CsdEndIdle(void)
1585 {
1586 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1587   _LOG_E_PROC_BUSY();   /* projector */
1588 #endif
1589
1590   CpvAccess(cmiMyPeIdle) = 0;
1591
1592   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1593 }
1594
1595 extern int _exitHandlerIdx;
1596
1597 /** Takes a message and calls its corresponding handler. */
1598 void CmiHandleMessage(void *msg)
1599 {
1600 /* this is wrong because it counts the Charm++ messages in sched queue
1601         CpvAccess(cQdState)->mProcessed++;
1602 */
1603         CmiHandlerInfo *h;
1604 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1605         CmiUInt2 handler=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1606         _LOG_E_HANDLER_BEGIN(handler); /* projector */
1607         /* setMemoryStatus(1) */ /* charmdebug */
1608 #endif
1609
1610 /*
1611         FAULT_EVAC
1612 */
1613 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1614                 return;
1615         }*/
1616         
1617         MESSAGE_PHASE_CHECK(msg)
1618
1619         h=&CmiGetHandlerInfo(msg);
1620         (h->hdlr)(msg,h->userPtr);
1621 #if CMK_TRACE_ENABLED
1622         /* setMemoryStatus(0) */ /* charmdebug */
1623         //_LOG_E_HANDLER_END(handler);  /* projector */
1624 #endif
1625 }
1626
1627 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1628
1629 void CmiDeliversInit()
1630 {
1631 }
1632
1633 int CmiDeliverMsgs(int maxmsgs)
1634 {
1635   return CsdScheduler(maxmsgs);
1636 }
1637
1638 #if CMK_OBJECT_QUEUE_AVAILABLE
1639 CpvDeclare(void *, CsdObjQueue);
1640 #endif
1641
1642 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1643 {
1644 #if CMK_OBJECT_QUEUE_AVAILABLE
1645         s->objQ=CpvAccess(CsdObjQueue);
1646 #endif
1647         s->localQ=CpvAccess(CmiLocalQueue);
1648         s->schedQ=CpvAccess(CsdSchedQueue);
1649         s->localCounter=&(CpvAccess(CsdLocalCounter));
1650 #if CMK_NODE_QUEUE_AVAILABLE
1651         s->nodeQ=CsvAccess(CsdNodeQueue);
1652         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1653 #endif
1654 #if CMK_GRID_QUEUE_AVAILABLE
1655         s->gridQ=CpvAccess(CsdGridQueue);
1656 #endif
1657 }
1658
1659
1660 /** Dequeue and return the next message from the unprocessed message queues.
1661  *
1662  * This function encapsulates the multiple queues that exist for holding unprocessed
1663  * messages and the rules for the order in which to check them. There are five (5)
1664  * different Qs that converse uses to store and retrieve unprocessed messages. These
1665  * are:
1666  *     Q Purpose                  Type      internal DeQ logic
1667  * -----------------------------------------------------------
1668  * - PE offnode                   pcQ             FIFO
1669  * - PE onnode                    CkQ             FIFO
1670  * - Node offnode                 pcQ             FIFO
1671  * - Node onnode                  prioQ           prio-based
1672  * - Scheduler                    prioQ           prio-based
1673  *
1674  * The PE queues hold messages that are destined for a specific PE. There is one such
1675  * queue for every PE within a charm node. The node queues hold messages that are
1676  * destined to that node. There is only one of each node queue within a charm node.
1677  * Finally there is also a charm++ message queue for each PE.
1678  *
1679  * The offnode queues are meant for holding messages that arrive from outside the
1680  * node. The onnode queues hold messages that are generated within the same charm
1681  * node.
1682  *
1683  * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1684  * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1685  * and hide the implementation specifics for each layer.
1686  *
1687  * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1688  * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1689  * queues. They are initialized via calls to CqsCreate() which gives each of them
1690  * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1691  * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1692  * is passed into this function.
1693  *
1694  * The order in which these queues are checked is described below. The function
1695  * proceeds to the next queue in the list only if it does not find any messages in
1696  * the current queue. The first message that is found is returned, terminating the
1697  * call.
1698  * (1) offnode queue for this PE
1699  * (2) onnode queue for this PE
1700  * (3) offnode queue for this node
1701  * (4) highest priority msg from onnode queue or scheduler queue
1702  *
1703  * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1704  * access (after observing adequate locking rigor) structs representing the scheduler
1705  * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1706  * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1707  * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1708  *
1709  */
1710 void *CsdNextMessage(CsdSchedulerState_t *s) {
1711         void *msg;
1712         if((*(s->localCounter))-- >0)
1713           {
1714               /* This avoids a race condition with migration detected by megatest*/
1715               msg=CdsFifo_Dequeue(s->localQ);
1716               if (msg!=NULL)
1717                 {
1718                   CpvAccess(cQdState)->mProcessed++;
1719                   return msg;       
1720                 }
1721               CqsDequeue(s->schedQ,(void **)&msg);
1722               if (msg!=NULL) return msg;
1723           }
1724         
1725         *(s->localCounter)=CsdLocalMax;
1726         if ( NULL!=(msg=CmiGetNonLocal()) || 
1727              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1728             CpvAccess(cQdState)->mProcessed++;
1729             return msg;
1730         }
1731 #if CMK_GRID_QUEUE_AVAILABLE
1732         /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1733         CqsDequeue (s->gridQ, (void **) &msg);
1734         if (msg != NULL) {
1735           return (msg);
1736         }
1737 #endif
1738 #if CMK_NODE_QUEUE_AVAILABLE
1739         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1740         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1741         if (!CqsEmpty(s->nodeQ)
1742          && !CqsPrioGT(CqsGetPriority(s->nodeQ),
1743                        CqsGetPriority(s->schedQ))) {
1744           CmiLock(s->nodeLock);
1745           CqsDequeue(s->nodeQ,(void **)&msg);
1746           CmiUnlock(s->nodeLock);
1747           if (msg!=NULL) return msg;
1748         }
1749 #endif
1750 #if CMK_OBJECT_QUEUE_AVAILABLE
1751         /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE"   */
1752         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1753           return msg;
1754         }
1755 #endif
1756         if(!CsdLocalMax) {
1757           CqsDequeue(s->schedQ,(void **)&msg);
1758           if (msg!=NULL) return msg;        
1759         }
1760         return NULL;
1761 }
1762
1763
1764 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1765         void *msg;
1766 #if CMK_NODE_QUEUE_AVAILABLE
1767         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1768         /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1769         if (!CqsEmpty(s->nodeQ))
1770         {
1771           CmiLock(s->nodeLock);
1772           CqsDequeue(s->nodeQ,(void **)&msg);
1773           CmiUnlock(s->nodeLock);
1774           if (msg!=NULL) return msg;
1775         }
1776 #endif
1777         return NULL;
1778
1779 }
1780
1781 int CsdScheduler(int maxmsgs)
1782 {
1783         if (maxmsgs<0) CsdScheduleForever();    
1784         else if (maxmsgs==0)
1785                 CsdSchedulePoll();
1786         else /*(maxmsgs>0)*/ 
1787                 return CsdScheduleCount(maxmsgs);
1788         return 0;
1789 }
1790
1791 /*Declare the standard scheduler housekeeping*/
1792 #define SCHEDULE_TOP \
1793       void *msg;\
1794       int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1795       int cycle = CpvAccess(CsdStopFlag); \
1796       CsdSchedulerState_t state;\
1797       CsdSchedulerState_new(&state);
1798
1799 /*A message is available-- process it*/
1800 #define SCHEDULE_MESSAGE \
1801       CmiHandleMessage(msg);\
1802       if (*CsdStopFlag_ptr != cycle) break;
1803
1804 /*No message available-- go (or remain) idle*/
1805 #define SCHEDULE_IDLE \
1806       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1807       else CsdStillIdle();\
1808       if (*CsdStopFlag_ptr != cycle) {\
1809         CsdEndIdle();\
1810         break;\
1811       }
1812
1813 /*
1814         EVAC
1815 */
1816 extern void CkClearAllArrayElements();
1817
1818
1819 extern void machine_OffloadAPIProgress();
1820
1821 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1822 void CsdScheduleForever(void)
1823 {
1824   #if CMK_CELL
1825     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1826     int progressCount = CMK_CELL_PROGRESS_FREQ;
1827   #endif
1828
1829   #ifdef CMK_CUDA
1830     #define CMK_CUDA_PROGRESS_FREQ 50
1831     int cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1832   #endif
1833
1834   int isIdle=0;
1835   SCHEDULE_TOP
1836   while (1) {
1837     /* The interoperation will cost this little overhead in scheduling */
1838     if(CharmLibInterOperate) {
1839       if(CpvAccess(charmLibExitFlag)) {
1840         CpvAccess(charmLibExitFlag) = 0;
1841         break;
1842       }
1843     }
1844     msg = CsdNextMessage(&state);
1845     if (msg!=NULL) { /*A message is available-- process it*/
1846       if (isIdle) {isIdle=0;CsdEndIdle();}
1847       SCHEDULE_MESSAGE
1848
1849       #if CMK_CELL
1850         if (progressCount <= 0) {
1851           /*OffloadAPIProgress();*/
1852           machine_OffloadAPIProgress();
1853           progressCount = CMK_CELL_PROGRESS_FREQ;
1854         }
1855         progressCount--;
1856       #endif
1857
1858       #ifdef CMK_CUDA
1859         if (cudaProgressCount == 0) {
1860           gpuProgressFn(); 
1861           cudaProgressCount = CMK_CUDA_PROGRESS_FREQ; 
1862         }
1863         cudaProgressCount--; 
1864       #endif
1865
1866     } else { /*No message available-- go (or remain) idle*/
1867       SCHEDULE_IDLE
1868
1869       #if CMK_CELL
1870         /*OffloadAPIProgress();*/
1871         machine_OffloadAPIProgress();
1872         progressCount = CMK_CELL_PROGRESS_FREQ;
1873       #endif
1874
1875       #ifdef CMK_CUDA
1876         gpuProgressFn(); 
1877         cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1878       #endif
1879
1880     }
1881     CsdPeriodic();
1882   }
1883 }
1884 int CsdScheduleCount(int maxmsgs)
1885 {
1886   int isIdle=0;
1887   SCHEDULE_TOP
1888   while (1) {
1889     msg = CsdNextMessage(&state);
1890     if (msg!=NULL) { /*A message is available-- process it*/
1891       if (isIdle) {isIdle=0;CsdEndIdle();}
1892       maxmsgs--; 
1893       SCHEDULE_MESSAGE
1894       if (maxmsgs==0) break;
1895     } else { /*No message available-- go (or remain) idle*/
1896       SCHEDULE_IDLE
1897     }
1898     CsdPeriodic();
1899   }
1900   return maxmsgs;
1901 }
1902
1903 void CsdSchedulePoll(void)
1904 {
1905   SCHEDULE_TOP
1906   while (1)
1907   {
1908         CsdPeriodic();
1909         /*CmiMachineProgressImpl(); ??? */
1910         if (NULL!=(msg = CsdNextMessage(&state)))
1911         {
1912              SCHEDULE_MESSAGE 
1913         }
1914         else break;
1915   }
1916 }
1917
1918 void CsdScheduleNodePoll(void)
1919 {
1920   SCHEDULE_TOP
1921   while (1)
1922   {
1923         /*CsdPeriodic();*/
1924         /*CmiMachineProgressImpl(); ??? */
1925         if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
1926         {
1927              SCHEDULE_MESSAGE 
1928         }
1929         else break;
1930   }
1931 }
1932
1933 void CmiDeliverSpecificMsg(handler)
1934 int handler;
1935 {
1936   int *msg; int side;
1937   void *localqueue = CpvAccess(CmiLocalQueue);
1938  
1939   side = 0;
1940   while (1) {
1941     CsdPeriodic();
1942     side ^= 1;
1943     if (side) msg = CmiGetNonLocal();
1944     else      msg = CdsFifo_Dequeue(localqueue);
1945     if (msg) {
1946       if (CmiGetHandler(msg)==handler) {
1947         CpvAccess(cQdState)->mProcessed++;
1948         CmiHandleMessage(msg);
1949         return;
1950       } else {
1951         CdsFifo_Enqueue(localqueue, msg);
1952       }
1953     }
1954   }
1955 }
1956  
1957 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1958
1959 /***************************************************************************
1960  *
1961  * Standin Schedulers.
1962  *
1963  * We use the following strategy to make sure somebody's always running
1964  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1965  * is responsible for this.  If the main thread blocks, we create a
1966  * "standin scheduler" thread to replace it.  If the standin scheduler
1967  * blocks, we create another standin scheduler to replace that one,
1968  * ad infinitum.  Collectively, the main thread and all the standin
1969  * schedulers are called "scheduling threads".
1970  *
1971  * Suppose the main thread is blocked waiting for data, and a standin
1972  * scheduler is running instead.  Suppose, then, that the data shows
1973  * up and the main thread is CthAwakened.  This causes a token to be
1974  * pushed into the queue.  When the standin pulls the token from the
1975  * queue and handles it, the standin goes to sleep, and control shifts
1976  * back to the main thread.  In this way, unnecessary standins are put
1977  * back to sleep.  These sleeping standins are stored on the
1978  * CthSleepingStandins list.
1979  *
1980  ***************************************************************************/
1981
1982 CpvStaticDeclare(CthThread, CthMainThread);
1983 CpvStaticDeclare(CthThread, CthSchedulingThread);
1984 CpvStaticDeclare(CthThread, CthSleepingStandins);
1985 CpvDeclare(int      , CthResumeNormalThreadIdx);
1986 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1987
1988
1989 void CthStandinCode()
1990 {
1991   while (1) CsdScheduler(0);
1992 }
1993
1994 /* this fix the function pointer for thread migration and pup */
1995 static CthThread CthSuspendNormalThread()
1996 {
1997   return CpvAccess(CthSchedulingThread);
1998 }
1999
2000 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2001 CthThread CthSuspendSchedulingThread();
2002
2003 CthThread CthSuspendSchedulingThread()
2004 {
2005   CthThread succ = CpvAccess(CthSleepingStandins);
2006
2007   if (succ) {
2008     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2009   } else {
2010     succ = CthCreate(CthStandinCode, 0, 256000);
2011     CthSetStrategy(succ,
2012                    CthEnqueueSchedulingThread,
2013                    CthSuspendSchedulingThread);
2014   }
2015   
2016   CpvAccess(CthSchedulingThread) = succ;
2017   return succ;
2018 }
2019
2020 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2021 void CthResumeNormalThread(CthThreadToken* token)
2022 {
2023   CthThread t = token->thread;
2024
2025   /* BIGSIM_OOC DEBUGGING
2026   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2027   */
2028
2029   if(t == NULL){
2030     free(token);
2031     return;
2032   }
2033 #if CMK_TRACE_ENABLED
2034 #if ! CMK_TRACE_IN_CHARM
2035   if(CpvAccess(traceOn))
2036     CthTraceResume(t);
2037 /*    if(CpvAccess(_traceCoreOn)) 
2038                 resumeTraceCore();*/
2039 #endif
2040 #endif
2041   
2042   /* BIGSIM_OOC DEBUGGING
2043   CmiPrintf("In CthResumeNormalThread:   ");
2044   CthPrintThdMagic(t);
2045   */
2046
2047   CthResume(t);
2048 }
2049
2050 void CthResumeSchedulingThread(CthThreadToken  *token)
2051 {
2052   CthThread t = token->thread;
2053   CthThread me = CthSelf();
2054   if (me == CpvAccess(CthMainThread)) {
2055     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2056   } else {
2057     CthSetNext(me, CpvAccess(CthSleepingStandins));
2058     CpvAccess(CthSleepingStandins) = me;
2059   }
2060   CpvAccess(CthSchedulingThread) = t;
2061 #if CMK_TRACE_ENABLED
2062 #if ! CMK_TRACE_IN_CHARM
2063   if(CpvAccess(traceOn))
2064     CthTraceResume(t);
2065 /*    if(CpvAccess(_traceCoreOn)) 
2066                 resumeTraceCore();*/
2067 #endif
2068 #endif
2069   CthResume(t);
2070 }
2071
2072 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2073                                    int pb,unsigned int *prio)
2074 {
2075   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2076   CsdEnqueueGeneral(token, s, pb, prio);
2077 }
2078
2079 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2080                                        int pb,unsigned int *prio)
2081 {
2082   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2083   CsdEnqueueGeneral(token, s, pb, prio);
2084 }
2085
2086 void CthSetStrategyDefault(CthThread t)
2087 {
2088   CthSetStrategy(t,
2089                  CthEnqueueNormalThread,
2090                  CthSuspendNormalThread);
2091 }
2092
2093 void CthSchedInit()
2094 {
2095   CpvInitialize(CthThread, CthMainThread);
2096   CpvInitialize(CthThread, CthSchedulingThread);
2097   CpvInitialize(CthThread, CthSleepingStandins);
2098   CpvInitialize(int      , CthResumeNormalThreadIdx);
2099   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2100
2101   CpvAccess(CthMainThread) = CthSelf();
2102   CpvAccess(CthSchedulingThread) = CthSelf();
2103   CpvAccess(CthSleepingStandins) = 0;
2104   CpvAccess(CthResumeNormalThreadIdx) =
2105     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2106   CpvAccess(CthResumeSchedulingThreadIdx) =
2107     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2108   CthSetStrategy(CthSelf(),
2109                  CthEnqueueSchedulingThread,
2110                  CthSuspendSchedulingThread);
2111 }
2112
2113 void CsdInit(argv)
2114   char **argv;
2115 {
2116   CpvInitialize(void *, CsdSchedQueue);
2117   CpvInitialize(int,   CsdStopFlag);
2118   CpvInitialize(int,   CsdLocalCounter);
2119   if(!CmiGetArgIntDesc(argv,"+csdLocalMax",&CsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages."))
2120     {
2121       CsdLocalMax= CSD_LOCAL_MAX_DEFAULT;
2122     }
2123   CpvAccess(CsdLocalCounter) = CsdLocalMax;
2124   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
2125
2126 #if CMK_OBJECT_QUEUE_AVAILABLE
2127   CpvInitialize(void *,CsdObjQueue);
2128   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2129 #endif
2130
2131 #if CMK_NODE_QUEUE_AVAILABLE
2132   CsvInitialize(CmiLock, CsdNodeQueueLock);
2133   CsvInitialize(void *, CsdNodeQueue);
2134   if (CmiMyRank() ==0) {
2135         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2136         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
2137   }
2138   CmiNodeAllBarrier();
2139 #endif
2140
2141 #if CMK_GRID_QUEUE_AVAILABLE
2142   CsvInitialize(void *, CsdGridQueue);
2143   CpvAccess(CsdGridQueue) = (void *)CqsCreate();
2144 #endif
2145
2146   CpvAccess(CsdStopFlag)  = 0;
2147 }
2148
2149
2150
2151 /** 
2152  *  @}
2153  */
2154
2155
2156 /*****************************************************************************
2157  *
2158  * Vector Send
2159  *
2160  * The last parameter "system" is by default at zero, in which case the normal
2161  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2162  * CmiAllocced message will also be sent (except for the first one). Useful for
2163  * AllToAll communication, and other system features. If system is 1, also all
2164  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2165  * that.
2166  *
2167  ****************************************************************************/
2168
2169 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2170
2171 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2172   int total;
2173   char *mesg;
2174 #if CMK_USE_IBVERBS
2175   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2176 #else
2177   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2178 #endif  
2179   CmiSyncSendAndFree(destPE, total, mesg);
2180 }
2181
2182 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2183   CmiSyncVectorSend(destPE, n, sizes, msgs);
2184   return NULL;
2185 }
2186
2187 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2188   int i;
2189   CmiSyncVectorSend(destPE, n, sizes, msgs);
2190   for(i=0;i<n;i++) CmiFree(msgs[i]);
2191   CmiFree(sizes);
2192   CmiFree(msgs);
2193 }
2194
2195 #endif
2196
2197 /*****************************************************************************
2198  *
2199  * Reduction management
2200  *
2201  * Only one reduction can be active at a single time in the program.
2202  * Moreover, since every call is supposed to pass in the same arguments,
2203  * having some static variables is not a problem for multithreading.
2204  * 
2205  * Except for "data" and "size", all the other parameters (which are all function
2206  * pointers) MUST be the same in every processor. Having different processors
2207  * pass in different function pointers results in an undefined behaviour.
2208  * 
2209  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2210  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2211  * functions is deleted with the provided function, or it is left intact if no
2212  * function is specified.
2213  * 
2214  * The destination handler for the the first form MUST be embedded into the
2215  * message's header.
2216  * 
2217  * The pup function is used to pup the input data structure into a message to
2218  * be sent to the parent processor. This pup routine is currently used only
2219  * for sizing and packing, NOT unpacking. It MUST be non-null.
2220  * 
2221  * The merge function receives as first parameter the input "data", being it
2222  * a message or a complex data structure (it is up to the user to interpret it
2223  * correctly), and a list of incoming (packed) messages from the children.
2224  * The merge function is responsible to delete "data" if this is no longer needed.
2225  * The system will be in charge of deleting the messages passed in as the second
2226  * argument, and the return value of the function (using the provided deleteFn in
2227  * the second version, or CmiFree in the first). The merge function can return
2228  * data if the merge can be performed in-place. It MUST be non-null.
2229  * 
2230  * At the destination, on processor zero, the final data returned by the last
2231  * merge call will not be deleted by the system, and the CmiHandler function
2232  * will be in charge of its deletion.
2233  * 
2234  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2235  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2236  * particular by the rank zero in each node.
2237  ****************************************************************************/
2238
2239 CpvStaticDeclare(int, CmiReductionMessageHandler);
2240 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2241
2242 CpvStaticDeclare(CmiReduction**, _reduce_info);
2243 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2244 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2245 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2246 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2247
2248 enum {
2249   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2250   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2251   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2252   CmiReductionID_multiplier = 3
2253 };
2254
2255 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2256   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2257   CmiReduction *red = CpvAccess(_reduce_info)[index];
2258   if (red != NULL && red->seqID != id) {
2259     /* The table needs to be expanded */
2260     CmiAbort("Too many simultaneous reductions");
2261   }
2262   if (red == NULL || red->numChildren < numChildren) {
2263     CmiReduction *newred;
2264     if (red != NULL) CmiPrintf("[%d] Reduction structure reallocated\n",CmiMyPe());
2265     CmiAssert(red == NULL || red->localContributed == 0);
2266     if (numChildren == 0) numChildren = 4;
2267     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2268     newred->numRemoteReceived = 0;
2269     newred->localContributed = 0;
2270     newred->seqID = id;
2271     if (red != NULL) {
2272       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2273       free(red);
2274     }
2275     red = newred;
2276     red->numChildren = numChildren;
2277     red->remoteData = (char**)(red+1);
2278     CpvAccess(_reduce_info)[index] = red;
2279   }
2280   return red;
2281 }
2282
2283 CmiReduction* CmiGetReduction(int id) {
2284   return CmiGetReductionCreate(id, 0);
2285 }
2286
2287 void CmiClearReduction(int id) {
2288   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2289   free(CpvAccess(_reduce_info)[index]);
2290   CpvAccess(_reduce_info)[index] = NULL;
2291 }
2292
2293 CmiReduction* CmiGetNextReduction(short int numChildren) {
2294   int id = CpvAccess(_reduce_seqID_global);
2295   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2296   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2297   return CmiGetReductionCreate(id, numChildren);
2298 }
2299
2300 CmiReductionID CmiGetGlobalReduction() {
2301   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2302 }
2303
2304 CmiReductionID CmiGetDynamicReduction() {
2305   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2306   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2307 }
2308
2309 void CmiReductionHandleDynamicRequest(char *msg) {
2310   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2311   int pe = values[0];
2312   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2313   values[0] = CmiGetDynamicReduction();
2314   CmiSetHandler(msg, CmiGetXHandler(msg));
2315   if (pe >= 0) {
2316     CmiSyncSendAndFree(pe, size, msg);
2317   } else {
2318     CmiSyncBroadcastAllAndFree(size, msg);
2319   }
2320 }
2321
2322 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2323   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2324   char *msg = (char*)CmiAlloc(size);
2325   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2326   values[0] = pe;
2327   values[1] = dataSize;
2328   CmiSetXHandler(msg, handlerIdx);
2329   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2330   if (CmiMyPe() == 0) {
2331     CmiReductionHandleDynamicRequest(msg);
2332   } else {
2333     /* send the request to processor 0 */
2334     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2335     CmiSyncSendAndFree(0, size, msg);
2336   }
2337 }
2338
2339 void CmiSendReduce(CmiReduction *red) {
2340   void *mergedData, *msg;
2341   int msg_size;
2342   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2343   mergedData = red->localData;
2344   msg_size = red->localSize;
2345   if (red->numChildren > 0) {
2346     int i, offset=0;
2347     if (red->ops.pupFn != NULL) {
2348       offset = CmiReservedHeaderSize;
2349       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2350     }
2351     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2352     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2353   }
2354   /*CpvAccess(_reduce_num_children) = 0;*/
2355   /*CpvAccess(_reduce_received) = 0;*/
2356   msg = mergedData;
2357   if (red->parent != -1) {
2358     if (red->ops.pupFn != NULL) {
2359       pup_er p = pup_new_sizer();
2360       (red->ops.pupFn)(p, mergedData);
2361       msg_size = pup_size(p) + CmiReservedHeaderSize;
2362       pup_destroy(p);
2363       msg = CmiAlloc(msg_size);
2364       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2365       (red->ops.pupFn)(p, mergedData);
2366       pup_destroy(p);
2367       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2368     }
2369     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2370     CmiSetRedID(msg, red->seqID);
2371     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2372     CmiSyncSendAndFree(red->parent, msg_size, msg);
2373   } else {
2374     (red->ops.destination)(msg);
2375   }
2376   CmiClearReduction(red->seqID);
2377 }
2378
2379 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2380   return data;
2381 }
2382
2383 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2384   CmiAssert(red->localContributed == 0);
2385   red->localContributed = 1;
2386   red->localData = msg;
2387   red->localSize = size;
2388   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2389   red->parent = CmiSpanTreeParent(CmiMyPe());
2390   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2391   red->ops.mergeFn = mergeFn;
2392   red->ops.pupFn = NULL;
2393   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2394   CmiSendReduce(red);
2395 }
2396
2397 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2398                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2399                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2400   CmiAssert(red->localContributed == 0);
2401   red->localContributed = 1;
2402   red->localData = data;
2403   red->localSize = 0;
2404   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2405   red->parent = CmiSpanTreeParent(CmiMyPe());
2406   red->ops.destination = dest;
2407   red->ops.mergeFn = mergeFn;
2408   red->ops.pupFn = pupFn;
2409   red->ops.deleteFn = deleteFn;
2410   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2411   CmiSendReduce(red);
2412 }
2413
2414 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2415   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2416   CmiGlobalReduce(msg, size, mergeFn, red);
2417 }
2418
2419 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2420                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2421                      CmiReduceDeleteFn deleteFn) {
2422   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2423   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2424 }
2425
2426 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2427   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2428   CmiGlobalReduce(msg, size, mergeFn, red);
2429 }
2430
2431 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2432                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2433                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2434   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2435   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2436 }
2437
2438 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2439   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2440   int myPos;
2441   CmiAssert(red->localContributed == 0);
2442   red->localContributed = 1;
2443   red->localData = msg;
2444   red->localSize = size;
2445   for (myPos=0; myPos<npes; ++myPos) {
2446     if (pes[myPos] == CmiMyPe()) break;
2447   }
2448   CmiAssert(myPos < npes);
2449   red->numChildren = npes - (myPos << 2) - 1;
2450   if (red->numChildren > 4) red->numChildren = 4;
2451   if (red->numChildren < 0) red->numChildren = 0;
2452   if (myPos == 0) red->parent = -1;
2453   else red->parent = pes[(myPos - 1) >> 2];
2454   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2455   red->ops.mergeFn = mergeFn;
2456   red->ops.pupFn = NULL;
2457   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2458   CmiSendReduce(red);
2459 }
2460
2461 void CmiListReduceStruct(int npes, int *pes,
2462                      void *data, CmiReducePupFn pupFn,
2463                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2464                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2465   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2466   int myPos;
2467   CmiAssert(red->localContributed == 0);
2468   red->localContributed = 1;
2469   red->localData = data;
2470   red->localSize = 0;
2471   for (myPos=0; myPos<npes; ++myPos) {
2472     if (pes[myPos] == CmiMyPe()) break;
2473   }
2474   CmiAssert(myPos < npes);
2475   red->numChildren = npes - (myPos << 2) - 1;
2476   if (red->numChildren > 4) red->numChildren = 4;
2477   if (red->numChildren < 0) red->numChildren = 0;
2478   red->parent = (myPos - 1) >> 2;
2479   if (myPos == 0) red->parent = -1;
2480   red->ops.destination = dest;
2481   red->ops.mergeFn = mergeFn;
2482   red->ops.pupFn = pupFn;
2483   red->ops.deleteFn = deleteFn;
2484   CmiSendReduce(red);
2485 }
2486
2487 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2488   int npes, *pes;
2489   CmiLookupGroup(grp, &npes, &pes);
2490   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2491 }
2492
2493 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2494                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2495                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2496   int npes, *pes;
2497   CmiLookupGroup(grp, &npes, &pes);
2498   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2499 }
2500
2501 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2502   CmiAbort("Feel free to implement CmiNodeReduce...");
2503   /*
2504   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2505   CpvAccess(_reduce_data) = data;
2506   CpvAccess(_reduce_data_size) = size;
2507   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2508   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2509   _reduce_pupFn = NULL;
2510   _reduce_mergeFn = mergeFn;
2511   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2512   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2513   */
2514 }
2515 #if 0
2516 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2517   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2518       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2519 }
2520 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2521   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2522 }
2523 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2524   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2525       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2526 }
2527 #endif
2528
2529 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2530                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2531                          CmiReduceDeleteFn deleteFn) {
2532   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2533 /*
2534   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2535   CpvAccess(_reduce_data) = data;
2536   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2537   _reduce_destination = dest;
2538   _reduce_pupFn = pupFn;
2539   _reduce_mergeFn = mergeFn;
2540   _reduce_deleteFn = deleteFn;
2541   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2542   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2543   */
2544 }
2545
2546 void CmiHandleReductionMessage(void *msg) {
2547   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2548   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2549   red->remoteData[red->numRemoteReceived++] = msg;
2550   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2551   CmiSendReduce(red);
2552 /*
2553   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2554   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2555   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2556 }
2557
2558 void CmiReductionsInit() {
2559   int i;
2560   CpvInitialize(int, CmiReductionMessageHandler);
2561   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2562   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2563   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2564   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2565   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2566   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2567   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2568   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2569   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2570   CpvInitialize(int, _reduce_info_size);
2571   CpvAccess(_reduce_info_size) = 4;
2572   CpvInitialize(CmiReduction**, _reduce_info);
2573   CpvAccess(_reduce_info) = malloc(16*sizeof(CmiReduction*));
2574   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2575 }
2576
2577 /*****************************************************************************
2578  *
2579  * Multicast groups
2580  *
2581  ****************************************************************************/
2582
2583 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2584
2585 typedef struct GroupDef
2586 {
2587   union {
2588     char core[CmiMsgHeaderSizeBytes];
2589     struct GroupDef *next;
2590   } core;
2591   CmiGroup group;
2592   int npes;
2593   int pes[1];
2594 }
2595 *GroupDef;
2596
2597 #define GROUPTAB_SIZE 101
2598
2599 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2600 CpvStaticDeclare(int, CmiGroupCounter);
2601 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2602
2603 void CmiGroupHandler(GroupDef def)
2604 {
2605   /* receive group definition, insert into group table */
2606   GroupDef *table = CpvAccess(CmiGroupTable);
2607   unsigned int hashval, bucket;
2608   hashval = (def->group.id ^ def->group.pe);
2609   bucket = hashval % GROUPTAB_SIZE;
2610   def->core.next = table[bucket];
2611   table[bucket] = def;
2612 }
2613
2614 CmiGroup CmiEstablishGroup(int npes, int *pes)
2615 {
2616   /* build new group definition, broadcast it */
2617   CmiGroup grp; GroupDef def; int len, i;
2618   grp.id = CpvAccess(CmiGroupCounter)++;
2619   grp.pe = CmiMyPe();
2620   len = sizeof(struct GroupDef)+(npes*sizeof(int));
2621   def = (GroupDef)CmiAlloc(len);
2622   def->group = grp;
2623   def->npes = npes;
2624   for (i=0; i<npes; i++)
2625     def->pes[i] = pes[i];
2626   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2627   CmiSyncBroadcastAllAndFree(len, def);
2628   return grp;
2629 }
2630
2631 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2632 {
2633   unsigned int hashval, bucket;  GroupDef def;
2634   GroupDef *table = CpvAccess(CmiGroupTable);
2635   hashval = (grp.id ^ grp.pe);
2636   bucket = hashval % GROUPTAB_SIZE;
2637   for (def=table[bucket]; def; def=def->core.next) {
2638     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2639       *npes = def->npes;
2640       *pes = def->pes;
2641       return;
2642     }
2643   }
2644   *npes = 0; *pes = 0;
2645 }
2646
2647 void CmiGroupInit()
2648 {
2649   CpvInitialize(int, CmiGroupHandlerIndex);
2650   CpvInitialize(int, CmiGroupCounter);
2651   CpvInitialize(GroupDef *, CmiGroupTable);
2652   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2653   CpvAccess(CmiGroupCounter) = 0;
2654   CpvAccess(CmiGroupTable) =
2655     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2656   if (CpvAccess(CmiGroupTable) == 0)
2657     CmiAbort("Memory Allocation Error");
2658 }
2659
2660 #endif
2661
2662 /*****************************************************************************
2663  *
2664  * Common List-Cast and Multicast Code
2665  *
2666  ****************************************************************************/
2667
2668 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2669
2670 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2671 {
2672   int i;
2673 #if CMK_BROADCAST_USE_CMIREFERENCE
2674   for(i=0;i<npes;i++) {
2675     if (pes[i] == CmiMyPe())
2676       CmiSyncSend(pes[i], len, msg);
2677     else {
2678       CmiReference(msg);
2679       CmiSyncSendAndFree(pes[i], len, msg);
2680     }
2681   }
2682 #else
2683   for(i=0;i<npes;i++) {
2684     CmiSyncSend(pes[i], len, msg);
2685   }
2686 #endif
2687 }
2688
2689 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2690 {
2691   /* A better asynchronous implementation may be wanted, but at least it works */
2692   CmiSyncListSendFn(npes, pes, len, msg);
2693   return (CmiCommHandle) 0;
2694 }
2695
2696 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2697 {
2698 #if CMK_BROADCAST_USE_CMIREFERENCE
2699   if (npes == 1) {
2700     CmiSyncSendAndFree(pes[0], len, msg);
2701     return;
2702   }
2703   CmiSyncListSendFn(npes, pes, len, msg);
2704   CmiFree(msg);
2705 #else
2706   int i;
2707   for(i=0;i<npes-1;i++) {
2708     CmiSyncSend(pes[i], len, msg);
2709   }
2710   if (npes>0)
2711     CmiSyncSendAndFree(pes[npes-1], len, msg);
2712   else 
2713     CmiFree(msg);
2714 #endif
2715 }
2716
2717 #endif
2718
2719 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2720
2721 typedef struct MultiMsg
2722 {
2723   char core[CmiMsgHeaderSizeBytes];
2724   CmiGroup group;
2725   int pos;
2726   int origlen;
2727 }
2728 *MultiMsg;
2729
2730
2731 CpvDeclare(int, CmiMulticastHandlerIndex);
2732
2733 void CmiMulticastDeliver(MultiMsg msg)
2734 {
2735   int npes, *pes; int olen, nlen, pos, child1, child2;
2736   olen = msg->origlen;
2737   nlen = olen + sizeof(struct MultiMsg);
2738   CmiLookupGroup(msg->group, &npes, &pes);
2739   if (pes==0) {
2740     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2741     return;
2742   }
2743   if (npes==0) {
2744     CmiFree(msg);
2745     return;
2746   }
2747   if (msg->pos == -1) {
2748     msg->pos=0;
2749     CmiSyncSendAndFree(pes[0], nlen, msg);
2750     return;
2751   }
2752   pos = msg->pos;
2753   child1 = ((pos+1)<<1);
2754   child2 = child1-1;
2755   if (child1 < npes) {
2756     msg->pos = child1;
2757     CmiSyncSend(pes[child1], nlen, msg);
2758   }
2759   if (child2 < npes) {
2760     msg->pos = child2;
2761     CmiSyncSend(pes[child2], nlen, msg);
2762   }
2763   if(olen < sizeof(struct MultiMsg)) {
2764     memcpy(msg, msg+1, olen);
2765   } else {
2766     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
2767   }
2768   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2769 }
2770
2771 void CmiMulticastHandler(MultiMsg msg)
2772 {
2773   CmiMulticastDeliver(msg);
2774 }
2775
2776 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2777 {
2778   int newlen; MultiMsg newmsg;
2779   newlen = len + sizeof(struct MultiMsg);
2780   newmsg = (MultiMsg)CmiAlloc(newlen);
2781   if(len < sizeof(struct MultiMsg)) {
2782     memcpy(newmsg+1, msg, len);
2783   } else {
2784     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
2785     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
2786   }
2787   newmsg->group = grp;
2788   newmsg->origlen = len;
2789   newmsg->pos = -1;
2790   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2791   CmiMulticastDeliver(newmsg);
2792 }
2793
2794 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2795 {
2796   CmiSyncMulticastFn(grp, len, msg);
2797   CmiFree(msg);
2798 }
2799
2800 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2801 {
2802   CmiError("Async Multicast not implemented.");
2803   return (CmiCommHandle) 0;
2804 }
2805
2806 void CmiMulticastInit()
2807 {
2808   CpvInitialize(int, CmiMulticastHandlerIndex);
2809   CpvAccess(CmiMulticastHandlerIndex) =
2810     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2811 }
2812
2813 #endif
2814
2815 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2816 extern void *arena_malloc(int size);
2817 extern void arena_free(void *blockPtr);
2818 #endif
2819
2820 /***************************************************************************
2821  *
2822  * Memory Allocation routines 
2823  *
2824  * A block of memory can consist of multiple chunks.  Each chunk has
2825  * a sizefield and a refcount.  The first chunk's refcount is a reference
2826  * count.  That's how many CmiFrees it takes to free the message.
2827  * Subsequent chunks have a refcount which is less than zero.  This is
2828  * the offset back to the start of the first chunk.
2829  *
2830  * Each chunk has a CmiChunkHeader before the user data, with the fields:
2831  *
2832  *  size: The user-allocated size of the chunk, in bytes.
2833  *
2834  *  ref: A magic reference count object. Ordinary blocks start with
2835  *     reference count 1.  When the reference count reaches zero,
2836  *     the block is deleted.  To support nested buffers, the 
2837  *     reference count can also be negative, which means it is 
2838  *     a byte offset to the enclosing buffer's reference count.
2839  *
2840  ***************************************************************************/
2841
2842
2843 void *CmiAlloc(int size)
2844 {
2845
2846   char *res;
2847
2848 #if CONVERSE_VERSION_ELAN
2849   res = (char *) elan_CmiAlloc(size+sizeof(CmiChunkHeader));
2850 #elif CONVERSE_VERSION_VMI
2851   res = (char *) CMI_VMI_CmiAlloc(size+sizeof(CmiChunkHeader));
2852 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2853   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
2854 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2855   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
2856 #elif CMK_CONVERSE_GEMINI_UGNI
2857   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
2858 #elif CONVERSE_POOL
2859   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
2860 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
2861   MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
2862 #elif CMK_SMP && CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
2863   res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
2864 #else
2865   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
2866 #endif
2867
2868   _MEMCHECK(res);
2869
2870 #ifdef MEMMONITOR
2871   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
2872   CpvAccess(AllocCount)++;
2873   CpvAccess(BlocksAllocated)++;
2874   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
2875     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
2876   }
2877   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
2878     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2879             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2880             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2881     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
2882   }
2883   if ((CpvAccess(AllocCount) % 1000) == 0) {
2884     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2885             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2886             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2887   }
2888 #endif
2889
2890   res+=sizeof(CmiChunkHeader);
2891   SIZEFIELD(res)=size;
2892   REFFIELD(res)=1;
2893   return (void *)res;
2894 }
2895
2896 /** Follow the header links out to the most enclosing block */
2897 static void *CmiAllocFindEnclosing(void *blk) {
2898   int refCount = REFFIELD(blk);
2899   while (refCount < 0) {
2900     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
2901     refCount = REFFIELD(blk);
2902   }
2903   return blk;
2904 }
2905
2906 int CmiGetReference(void *blk)
2907 {
2908   return REFFIELD(CmiAllocFindEnclosing(blk));
2909 }
2910
2911 /** Increment the reference count for this block's owner.
2912     This call must be matched by an equivalent CmiFree. */
2913 void CmiReference(void *blk)
2914 {
2915   REFFIELD(CmiAllocFindEnclosing(blk))++;
2916 }
2917
2918 /** Return the size of the user portion of this block. */
2919 int CmiSize(void *blk)
2920 {
2921   return SIZEFIELD(blk);
2922 }
2923
2924 /** Decrement the reference count for this block. */
2925 void CmiFree(void *blk)
2926 {
2927   void *parentBlk=CmiAllocFindEnclosing(blk);
2928   int refCount=REFFIELD(parentBlk);
2929 #if CMK_ERROR_CHECKING
2930   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
2931     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
2932 #endif
2933   refCount--;
2934   REFFIELD(parentBlk) = refCount;
2935   if(refCount==0) { /* This was the last reference to the block-- free it */
2936 #ifdef MEMMONITOR
2937     int size=SIZEFIELD(parentBlk);
2938     if (size > 1000000000) /* Absurdly large size field-- warning */
2939       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
2940     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
2941     CpvAccess(BlocksAllocated)--;
2942 #endif
2943
2944 #if CONVERSE_VERSION_ELAN
2945     elan_CmiFree(BLKSTART(parentBlk));
2946 #elif CONVERSE_VERSION_VMI
2947     CMI_VMI_CmiFree(BLKSTART(parentBlk));
2948 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2949     arena_free(BLKSTART(parentBlk));
2950 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2951     /* is this message the head of a MultipleSend that we received?
2952        Then the parts with INFIMULTIPOOL have metadata which must be 
2953        unregistered and freed.  */
2954 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
2955     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
2956       {
2957         infi_freeMultipleSend(parentBlk);
2958       }
2959 #endif
2960     infi_CmiFree(BLKSTART(parentBlk));
2961 #elif CMK_CONVERSE_GEMINI_UGNI
2962     LrtsFree(BLKSTART(parentBlk));
2963 #elif CONVERSE_POOL
2964     CmiPoolFree(BLKSTART(parentBlk));
2965 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
2966     MPI_Free_mem(parentBlk);
2967 #elif CMK_SMP && CMK_BLUEGENEQ && CMK_USE_L2ATOMICS
2968     CmiFree_bgq(BLKSTART(parentBlk));
2969 #else
2970     free_nomigrate(BLKSTART(parentBlk));
2971 #endif
2972   }
2973 }
2974
2975
2976 /***************************************************************************
2977  *
2978  * Temporary-memory Allocation routines 
2979  *
2980  *  This buffer augments the storage available on the regular machine stack
2981  * for fairly large temporary buffers, which allows us to use smaller machine
2982  * stacks.
2983  *
2984  ***************************************************************************/
2985
2986 #define CMI_TMP_BUF_MAX 128*1024 /* Allow this much temporary storage. */
2987
2988 typedef struct {
2989   char *buf; /* Start of temporary buffer */
2990   int cur; /* First unused location in temporary buffer */
2991   int max; /* Length of temporary buffer */
2992 } CmiTmpBuf_t;
2993 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
2994
2995 static void CmiTmpSetup(CmiTmpBuf_t *b) {
2996   b->buf=malloc(CMI_TMP_BUF_MAX);
2997   b->cur=0;
2998   b->max=CMI_TMP_BUF_MAX;
2999 }
3000
3001 void *CmiTmpAlloc(int size) {
3002   if (!CpvInitialized(CmiTmpBuf)) {
3003     return malloc(size);
3004   }
3005   else { /* regular case */
3006     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3007     void *t;
3008     if (b->cur+size>b->max) {
3009       if (b->max==0) /* We're just uninitialized */
3010         CmiTmpSetup(b);
3011       else /* We're really out of space! */
3012         CmiAbort("CmiTmpAlloc: asked for too much temporary buffer space");
3013     }
3014     t=b->buf+b->cur;
3015     b->cur+=size;
3016     return t;
3017   }
3018 }
3019 void CmiTmpFree(void *t) {
3020   if (!CpvInitialized(CmiTmpBuf)) {
3021     free(t);
3022   }
3023   else { /* regular case */
3024     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3025     /* t should point into our temporary buffer: figure out where */
3026     int cur=((const char *)t)-b->buf;
3027 #if CMK_ERROR_CHECKING
3028     if (cur<0 || cur>b->max)
3029       CmiAbort("CmiTmpFree: called with an invalid pointer");
3030 #endif
3031     b->cur=cur;
3032   }
3033 }
3034
3035 void CmiTmpInit(char **argv) {
3036   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3037   /* Set up this processor's temporary buffer */
3038   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3039 }
3040
3041 /******************************************************************************
3042
3043   Cross-platform directory creation
3044
3045   ****************************************************************************/
3046 #ifdef _MSC_VER
3047 /* Windows directory creation: */
3048 #include <windows.h>
3049
3050 void CmiMkdir(const char *dirName) {
3051         CreateDirectory(dirName,NULL);
3052 }
3053
3054 #else /* !_MSC_VER */
3055 /* UNIX directory creation */
3056 #include <unistd.h> 
3057 #include <sys/stat.h> /* from "mkdir" man page */
3058 #include <sys/types.h>
3059
3060 void CmiMkdir(const char *dirName) {
3061 #ifndef __MINGW_H
3062         mkdir(dirName,0777);
3063 #else
3064         mkdir(dirName);
3065 #endif
3066 }
3067
3068 #endif
3069
3070
3071 /******************************************************************************
3072
3073   Multiple Send function                               
3074
3075   ****************************************************************************/
3076
3077
3078
3079
3080
3081 /****************************************************************************
3082 * DESCRIPTION : This function call allows the user to send multiple messages
3083 *               from one processor to another, all intended for differnet 
3084 *               handlers.
3085 *
3086 *               Parameters :
3087 *
3088 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3089 *
3090 ****************************************************************************/
3091 /* Round up message size to the message granularity. 
3092    Does this by adding, then truncating.
3093 */
3094 static int roundUpSize(unsigned int s) {
3095   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3096 }
3097 /* Return the amount of message padding required for a message
3098    with this many user bytes. 
3099  */
3100 static int paddingSize(unsigned int s) {
3101   return roundUpSize(s)-s;
3102 }
3103
3104 /* Message header for a bundle of multiple-sent messages */
3105 typedef struct {
3106   char convHeader[CmiMsgHeaderSizeBytes];
3107   int nMessages; /* Number of distinct messages bundled below. */
3108   double pad; /* To align the first message, which follows this header */
3109 } CmiMultipleSendHeader;
3110
3111 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3112 /* given a pointer to a multisend message clean up the metadata */
3113
3114 void infi_freeMultipleSend(void *msgWhole)
3115 {
3116   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3117   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3118   int offset=sizeof(CmiMultipleSendHeader);
3119   int m;
3120   void *thisMsg=NULL;
3121   if (pad != 1234567.89) return;
3122   for(m=0;m<len;m++)
3123     {
3124       /*unreg meta, free meta, move the ptr */
3125       /* note these weird little things are not pooled */
3126       /* do NOT free the message here, we are only a part of this buffer*/
3127       infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3128       char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3129       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3130       infi_unregAndFreeMeta(ch->metaData);
3131       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3132     }
3133 }
3134 #endif
3135
3136
3137 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3138 {
3139   CmiMultipleSendHeader header;
3140   int m; /* Outgoing message */
3141
3142 #if CMK_USE_IBVERBS
3143   infiCmiChunkHeader *msgHdr;
3144 #else
3145   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3146 #endif
3147         
3148   double pad = 0; /* padding required */
3149   int vecLen; /* Number of pieces in outgoing message vector */
3150   int *vecSizes; /* Sizes of each piece we're sending out. */
3151   char **vecPtrs; /* Pointers to each piece we're sending out. */
3152   int vec; /* Entry we're currently filling out in above array */
3153         
3154 #if CMK_USE_IBVERBS
3155   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3156 #else
3157   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3158 #endif
3159         
3160   /* Allocate memory for the outgoing vector*/
3161   vecLen=1+3*len; /* Header and 3 parts per message */
3162   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3163   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3164   vec=0;
3165   
3166   /* Build the header */
3167   header.nMessages=len;
3168   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3169   header.pad = 1234567.89;
3170 #if CMK_IMMEDIATE_MSG
3171   if (immed) CmiBecomeImmediate(&header);
3172 #endif
3173   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3174   vec++;
3175
3176   /* Build an entry for each message: 
3177          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3178   */
3179   for (m=0;m<len;m++) {
3180 #if CMK_USE_IBVERBS
3181     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3182     msgHdr[m].chunkHeader.ref=0; /* Reference count will be filled out on receive side */
3183     msgHdr[m].metaData=NULL;
3184 #else
3185     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3186     msgHdr[m].ref=0; /* Reference count will be filled out on receive side */
3187 #endif          
3188     
3189     /* First send the message's CmiChunkHeader (for use on receive side) */
3190 #if CMK_USE_IBVERBS
3191     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3192 #else
3193     vecSizes[vec]=sizeof(CmiChunkHeader); 
3194 #endif          
3195                 vecPtrs[vec]=(char *)&msgHdr[m];
3196     vec++;
3197     
3198     /* Now send the actual message data */
3199     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3200     vec++;
3201     
3202     /* Now send padding to align the next message on a double-boundary */
3203     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3204     vec++;
3205   }
3206   CmiAssert(vec==vecLen);
3207   
3208   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3209   
3210   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3211   CmiTmpFree(vecSizes);
3212   CmiTmpFree(msgHdr);
3213 }
3214
3215 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3216 {
3217   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3218 }
3219
3220 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3221 {
3222   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3223 }
3224
3225 /****************************************************************************
3226 * DESCRIPTION : This function initializes the main handler required for the
3227 *               CmiMultipleSend() function to work. 
3228 *               
3229 *               This function should be called once in any Converse program
3230 *               that uses CmiMultipleSend()
3231 *
3232 ****************************************************************************/
3233
3234 static void CmiMultiMsgHandler(char *msgWhole);
3235
3236 void CmiInitMultipleSend(void)
3237 {
3238   CpvInitialize(int,CmiMainHandlerIDP); 
3239   CpvAccess(CmiMainHandlerIDP) =
3240     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3241 }
3242
3243 /****************************************************************************
3244 * DESCRIPTION : This function is the main handler that splits up the messages
3245 *               CmiMultipleSend() pastes together. 
3246 *
3247 ****************************************************************************/
3248
3249 static void CmiMultiMsgHandler(char *msgWhole)
3250 {
3251   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3252   int offset=sizeof(CmiMultipleSendHeader);
3253   int m;
3254   for (m=0;m<len;m++) {
3255 #if CMK_USE_IBVERBS
3256     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3257     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3258     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3259     ch->chunkHeader.ref=msgWhole-msg; 
3260     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3261 #else
3262     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3263     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3264     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3265     ch->ref=msgWhole-msg; 
3266 #endif          
3267     /* Link new message to owner via a negative ref pointer */
3268     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3269     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3270 #if CMK_USE_IBVERBS
3271     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3272 #else
3273     offset+= sizeof(CmiChunkHeader) + msgSize;
3274 #endif          
3275   }
3276   /* Release our reference to the whole message.  The message will
3277      only actually be deleted once all its sub-messages are free'd as well. */
3278   CmiFree(msgWhole);
3279 }
3280
3281 /****************************************************************************
3282 * Hypercube broadcast message passing.
3283 ****************************************************************************/
3284
3285 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3286   int num_pes = 0;
3287   for ( ; k>=0; --k) {
3288     /* add the processor destination at level k if it exist */
3289     dest_pes[num_pes] = mype ^ (1<<k);
3290     if (dest_pes[num_pes] >= total_pes) {
3291       /* find the first proc in the other part of the current dimention */
3292       dest_pes[num_pes] &= (-1)<<k;
3293       /* if the first proc there is over CmiNumPes() then there is no other
3294          dimension, otherwise if it is valid compute my correspondent in such
3295          a way to minimize the load for every processor */
3296       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((-1)<<k))) % (total_pes - dest_pes[num_pes]);
3297       }
3298     if (dest_pes[num_pes] < total_pes) {
3299       /* if the destination is in the acceptable range increment num_pes */
3300       ++num_pes;
3301     }
3302   }
3303   return num_pes;
3304 }
3305
3306
3307 /****************************************************************************
3308 * DESCRIPTION : This function initializes the main handler required for the
3309 *               Immediate message
3310 *               
3311 *               This function should be called once in any Converse program
3312 *
3313 ****************************************************************************/
3314
3315 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3316 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3317
3318 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3319
3320 /* xdl is the real handler */
3321 static void CmiImmediateMsgHandler(char *msg)
3322 {
3323   CmiSetHandler(msg, CmiGetXHandler(msg));
3324   CmiHandleMessage(msg);
3325 }
3326
3327 void CmiInitImmediateMsg(void)
3328 {
3329   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3330   CpvAccess(CmiImmediateMsgHandlerIdx) =
3331     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3332 }
3333
3334 /*#if !CMK_IMMEDIATE_MSG
3335 #if !CMK_MACHINE_PROGRESS_DEFINED
3336 void CmiProbeImmediateMsg()
3337 {
3338 }
3339 #endif
3340 #endif*/
3341
3342 /******** Idle timeout module (+idletimeout=30) *********/
3343
3344 typedef struct {
3345   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3346   int is_idle;/*Boolean currently-idle flag*/
3347   int call_count;/*Number of timeout calls currently in flight*/
3348 } cmi_cpu_idlerec;
3349
3350 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3351 {
3352   rec->call_count--;
3353   if(rec->call_count==0 && rec->is_idle==1) {
3354     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3355     CmiAbort("Exiting.\n");
3356   }
3357 }
3358 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3359 {
3360   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3361   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3362   rec->is_idle = 1;
3363 }
3364 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3365 {
3366   rec->is_idle = 0;
3367 }
3368 static void CIdleTimeoutInit(char **argv)
3369 {
3370   int idle_timeout=0; /*Seconds to wait*/
3371   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3372   if(idle_timeout != 0) {
3373     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3374     _MEMCHECK(rec);
3375     rec->idle_timeout=idle_timeout*1000;
3376     rec->is_idle=0;
3377     rec->call_count=0;
3378     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3379     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3380   }
3381 }
3382
3383 /*****************************************************************************
3384  *
3385  * Converse Initialization
3386  *
3387  *****************************************************************************/
3388
3389 extern void CrnInit(void);
3390 extern void CmiIsomallocInit(char **argv);
3391 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3392 void CmiIOInit(char **argv);
3393 #endif
3394
3395 /* defined in cpuaffinity.c */
3396 extern void CmiInitCPUAffinityUtil();
3397
3398 static void CmiProcessPriority(char **argv)
3399 {
3400   int dummy, nicelevel=-100;      /* process priority */
3401   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3402   /* ignore others */
3403   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3404   /* call setpriority once on each process to set process's priority */
3405   if (CmiMyRank() == 0 && nicelevel != -100)  {
3406 #ifndef _WIN32
3407     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3408       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3409       perror("setpriority");
3410       CmiAbort("setpriority failed.");
3411     }
3412     else
3413       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3414 #else
3415     HANDLE hProcess = GetCurrentProcess();
3416     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3417     char *prio_str = "NORMAL_PRIORITY_CLASS";
3418     BOOL status;
3419     /*
3420        <-20:      real time
3421        -20--10:   high 
3422        -10-0:     above normal
3423        0:         normal
3424        0-10:      below normal
3425        10-:       idle
3426     */
3427     if (0) ;
3428 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3429     else if (nicelevel<10 && nicelevel>0) {
3430       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3431       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3432     }
3433 #endif
3434     else if (nicelevel>0) {
3435       dwPriorityClass = IDLE_PRIORITY_CLASS;
3436       prio_str = "IDLE_PRIORITY_CLASS";
3437     }
3438     else if (nicelevel<=-20) {
3439       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3440       prio_str = "REALTIME_PRIORITY_CLASS";
3441     }
3442 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3443     else if (nicelevel>-10 && nicelevel<0) {
3444       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3445       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3446     }
3447 #endif
3448     else if (nicelevel<0) {
3449       dwPriorityClass = HIGH_PRIORITY_CLASS;
3450       prio_str = "HIGH_PRIORITY_CLASS";
3451     }
3452     status = SetPriorityClass(hProcess, dwPriorityClass);
3453     if (!status)  {
3454         int err=GetLastError();
3455         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3456         CmiAbort("SetPriorityClass failed.");
3457     }
3458     else
3459       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3460 #endif
3461   }
3462 }
3463
3464 void CommunicationServerInit()
3465 {
3466 #if CMK_IMMEDIATE_MSG
3467   CQdCpvInit();
3468   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3469 #endif
3470 }
3471
3472
3473 static int testEndian(void)
3474 {
3475         int test=0x1c;
3476         unsigned char *c=(unsigned char *)&test;
3477         if (c[sizeof(int)-1]==0x1c)
3478                 /* Macintosh and most workstations are big-endian */
3479                 return 1;   /* Big-endian machine */
3480         if (c[0]==0x1c)
3481                 /* Intel x86 PC's, and DEC VAX are little-endian */
3482                 return 0;  /* Little-endian machine */
3483         return -2;  /*Unknown integer type */
3484 }
3485
3486 int CmiEndianness()
3487 {
3488   static int _cmi_endianness = -1;
3489   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3490   CmiAssert(_cmi_endianness != -2);
3491   return  _cmi_endianness;
3492 }
3493
3494 /**
3495   Main Converse initialization routine.  This routine is 
3496   called by the machine file (machine.c) to set up Converse.
3497   It's "Common" because it's shared by all the machine.c files. 
3498   
3499   The main task of this routine is to set up all the Cpv's
3500   (message queues, handler tables, etc.) used during main execution.
3501   
3502   On SMP versions, this initialization routine is called by 
3503   *all* processors of a node simultaniously.  It's *also* called
3504   by the communication thread, which is rather strange but needed
3505   for immediate messages.  Each call to this routine expects a 
3506   different copy of the argv arguments, so use CmiCopyArgs(argv).
3507   
3508   Requires:
3509     - A working network layer.
3510     - Working Cpv's and CmiNodeBarrier.
3511     - CthInit to already have been called.  CthInit is called
3512       from the machine layer directly, because some machine layers
3513       (like uth) use Converse threads internally.
3514
3515   Initialization is somewhat subtle, in that various modules
3516   won't work properly until they're initialized.  For example,
3517   nobody can register handlers before calling CmiHandlerInit.
3518 */
3519 void ConverseCommonInit(char **argv)
3520 {
3521
3522 /**
3523  * The reason to initialize this variable here:
3524  * cmiArgDebugFlag is possibly accessed in CmiPrintf/CmiError etc.,
3525  * therefore, we have to initialize this variable before any calls
3526  * to those functions (such as CmiPrintf). Otherwise, we may encounter
3527  * a memory segmentation fault (bad memory access). Note, even
3528  * testing CpvInitialized(cmiArgDebugFlag) doesn't help to solve
3529  * this problem because the variable indicating whether cmiArgDebugFlag is 
3530  * initialized or not is not initialized, thus possibly causing another
3531  * bad memory access. --Chao Mei
3532  */
3533   CpvInitialize(int, _urgentSend);
3534   CpvAccess(_urgentSend) = 0;
3535 #if CMK_CCS_AVAILABLE
3536   CpvInitialize(int, cmiArgDebugFlag);
3537   CpvAccess(cmiArgDebugFlag) = 0;
3538 #endif
3539   CpvInitialize(int,charmLibExitFlag);
3540   CpvAccess(charmLibExitFlag) = 0;
3541
3542   CpvInitialize(int,_curRestartPhase);
3543   CpvAccess(_curRestartPhase)=1;
3544   CmiArgInit(argv);
3545   CmiMemoryInit(argv);
3546 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3547   CmiIOInit(argv);
3548 #endif
3549   if (CmiMyPe() == 0)
3550       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3551
3552   CpvInitialize(int, cmiMyPeIdle);
3553   CpvAccess(cmiMyPeIdle) = 0;
3554
3555 /* #if CONVERSE_POOL */
3556   CmiPoolAllocInit(30);  
3557 /* #endif */
3558   CmiTmpInit(argv);
3559   CmiTimerInit(argv);
3560   CstatsInit(argv);
3561   CmiInitCPUAffinityUtil();
3562
3563   CcdModuleInit(argv);
3564   CmiHandlerInit();
3565   CmiReductionsInit();
3566   CIdleTimeoutInit(argv);
3567   
3568 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the net-*-smp versions*/
3569   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for net-smp-*) ?")){
3570     if(CmiMyRank() == 0) _Cmi_noprocforcommthread=1;
3571    }
3572 #endif
3573         
3574 #if CMK_TRACE_ENABLED
3575   traceInit(argv);
3576 /*initTraceCore(argv);*/ /* projector */
3577 #endif
3578   CmiProcessPriority(argv);
3579
3580   CmiPersistentInit();
3581   CmiIsomallocInit(argv);
3582   CmiDeliversInit();
3583   CsdInit(argv);
3584 #if CMK_CCS_AVAILABLE
3585   CcsInit(argv);
3586 #endif
3587   CpdInit();
3588   CthSchedInit();
3589   CmiGroupInit();
3590   CmiMulticastInit();
3591   CmiInitMultipleSend();
3592   CQdInit();
3593
3594   CrnInit();
3595   CmiInitImmediateMsg();
3596   CldModuleInit(argv);
3597   
3598 #if CMK_CELL
3599   void CmiInitCell();
3600   CmiInitCell();
3601 #endif
3602
3603 #ifdef CMK_CUDA
3604   initHybridAPI(CmiMyPe()); 
3605 #endif
3606
3607   /* main thread is suspendable */
3608 /*
3609   CthSetSuspendable(CthSelf(), 0);
3610 */
3611
3612 #if CMK_BIGSIM_CHARM
3613    /* have to initialize QD here instead of _initCharm */
3614   extern void initQd(char **argv);
3615   initQd(argv);
3616 #endif
3617 }
3618
3619 void ConverseCommonExit(void)
3620 {
3621   CcsImpl_kill();
3622
3623 #if CMK_TRACE_ENABLED
3624   traceClose();
3625 /*closeTraceCore();*/ /* projector */
3626 #endif
3627
3628 #if CMI_IO_BUFFER_EXPLICIT
3629   CmiFlush(stdout);  /* end of program, always flush */
3630 #endif
3631
3632 #if CMK_CELL
3633   CloseOffloadAPI();
3634 #endif
3635
3636 #if CMK_CUDA
3637   exitHybridAPI(); 
3638 #endif
3639   seedBalancerExit();
3640   EmergencyExit();
3641 }
3642
3643
3644 #if CMK_CELL != 0
3645
3646 extern void register_accel_spe_funcs(void);
3647
3648 void CmiInitCell()
3649 {
3650   // Create a unique string for each PPE to use for the timing
3651   //   data file's name
3652   char fileNameBuf[64];
3653   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3654
3655   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3656   //CcdCallOnConditionKeep(CcdPERIODIC, 
3657   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3658   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3659       (CcdVoidFn) OffloadAPIProgress, NULL);
3660
3661   // Register accelerated entry methods on the PPE
3662   register_accel_spe_funcs();
3663 }
3664
3665 #include "cell-api.c"
3666
3667 #endif
3668
3669 /****
3670  * CW Lee - 9/14/2005
3671  * Added a mechanism to allow some control over machines with extremely
3672  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3673  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3674  * coupled with a default setup using unbuffered stdout introduced
3675  * severe overheads (and hence limiting scaling) for applications like 
3676  * NAMD.
3677  */
3678 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3679 void CmiIOInit(char **argv) {
3680   CpvInitialize(int, expIOFlushFlag);
3681 #if CMI_IO_BUFFER_EXPLICIT
3682   /* 
3683      Support for an explicit buffer only makes sense if the machine
3684      layer does not wish to make its own implementation.
3685
3686      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3687      MUST NOT make use of stdout if an explicit buffer is requested.
3688
3689      The setvbuf function may only be used after opening a stream and
3690      before any other operations have been performed on it
3691   */
3692   CpvInitialize(char*, explicitIOBuffer);
3693   CpvInitialize(int, expIOBufferSize);
3694   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3695                         "Explicit IO Buffer Size")) {
3696     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3697   }
3698   if (CpvAccess(expIOBufferSize) <= 0) {
3699     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3700   }
3701   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3702                                                 sizeof(char));
3703   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
3704               CpvAccess(expIOBufferSize))) {
3705     CmiAbort("Explicit IO Buffering failed\n");
3706   }
3707 #endif
3708 #if CMI_IO_FLUSH_USER
3709   /* system default to have user control flushing of IO */
3710   /* Now look for user override */
3711   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
3712                                                  "System Controls IO Flush");
3713 #else
3714   /* system default to have system handle IO flushing */
3715   /* Now look for user override */
3716   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
3717                                                 "User Controls IO Flush");
3718 #endif
3719 }
3720 #endif
3721
3722 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3723
3724 void CmiPrintf(const char *format, ...)
3725 {
3726   CpdSystemEnter();
3727   {
3728   va_list args;
3729   va_start(args,format);
3730   vfprintf(stdout,format, args);
3731   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
3732     CmiFlush(stdout);
3733   }
3734   va_end(args);
3735 #if CMK_CCS_AVAILABLE
3736   if (CpvAccess(cmiArgDebugFlag)) {
3737     va_start(args,format);
3738     print_node0(format, args);
3739     va_end(args);
3740   }
3741 #endif
3742   }
3743   CpdSystemExit();
3744 }
3745
3746 void CmiError(const char *format, ...)
3747 {
3748   CpdSystemEnter();
3749   {
3750   va_list args;
3751   va_start(args,format);
3752   vfprintf(stderr,format, args);
3753   CmiFlush(stderr);  /* stderr is always flushed */
3754   va_end(args);
3755 #if CMK_CCS_AVAILABLE
3756   if (CpvAccess(cmiArgDebugFlag)) {
3757     va_start(args,format);
3758     print_node0(format, args);
3759     va_end(args);
3760   }
3761 #endif
3762   }
3763   CpdSystemExit();
3764 }
3765
3766 #endif
3767
3768 void __cmi_assert(const char *expr, const char *file, int line)
3769 {
3770   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
3771       CmiMyPe(), expr, file, line);
3772   CmiAbort("");
3773 }
3774
3775 char *CmiCopyMsg(char *msg, int len)
3776 {
3777   char *copy = (char *)CmiAlloc(len);
3778   _MEMCHECK(copy);
3779   memcpy(copy, msg, len);
3780   return copy;
3781 }
3782
3783 unsigned char computeCheckSum(unsigned char *data, int len)
3784 {
3785   int i;
3786   unsigned char ret = 0;
3787   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
3788   return ret;
3789 }
3790
3791 /* Flag for bigsim's out-of-core emulation */
3792 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
3793 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
3794
3795 #if !CMK_HAS_LOG2
3796 unsigned int CmiILog2(unsigned int val) {
3797   unsigned int log = 0u;
3798   if ( val != 0u ) {
3799       while ( val > (1u<<log) ) { log++; }
3800   }
3801   return log;
3802 }
3803 double CmiLog2(double x) {
3804   return log(x)/log(2);
3805 }
3806 #endif
3807
3808 /* for bigsim */
3809 int CmiMyRank_()
3810 {
3811   return CmiMyRank();
3812 }
3813
3814 double CmiReadSize(const char *str)
3815 {
3816     double val;
3817     if (strpbrk(str,"Gg")) {
3818         //sscanf(str, "%llf", &val);
3819         //val = strtod(str, &p);
3820         val = atof(str);
3821         val *= 1024ll*1024*1024;
3822     }
3823     else if (strpbrk(str,"Mm")) {
3824         val = atof(str);
3825         val *= 1024*1024;
3826     }
3827     else if (strpbrk(str,"Kk")) {
3828         val = atof(str);
3829         val *= 1024;
3830     }
3831     else {
3832         val = atof(str);
3833     }
3834     return val;
3835 }
3836
3837 int CmiIsMyNodeIdle(){
3838     int i;
3839     for(i=0; i<CmiMyNodeSize(); i++){
3840         if(CpvAccessOther(cmiMyPeIdle, i)) return 1;
3841     }
3842     return 0;
3843 }
3844
3845 /*@}*/