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