Rename the majority of remaining C files in the RTS to C++
[charm.git] / src / conv-core / convcore.C
blob564dd7f08cea44baf28528dd405c74813086ee7d
1 /** 
2   @defgroup Converse
3   \brief Converse--a parallel portability layer.
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.
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.
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.
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).
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).
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.
39   Incoming messages that are destined for Charm++ will be passed to the 
40   \ref CharmScheduler "charm scheduling routines".
42   @file
43   converse main core
44   @ingroup Converse
45   @ingroup ConverseScheduler
47   @addtogroup Converse
48   @{
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include "hrctimer.h"
56 #ifndef __STDC_FORMAT_MACROS
57 # define __STDC_FORMAT_MACROS
58 #endif
59 #ifndef __STDC_LIMIT_MACROS
60 # define __STDC_LIMIT_MACROS
61 #endif
62 #include <inttypes.h>
63 #include <errno.h>
64 #ifndef _WIN32
65 #include <sys/time.h>
66 #include <sys/resource.h>
67 #else
68 #define snprintf _snprintf
69 #endif
71 #include "converse.h"
72 #include "conv-trace.h"
73 #include "sockRoutines.h"
74 #include "queueing.h"
75 #if CMK_SMP && CMK_TASKQUEUE
76 #include "taskqueue.h"
77 #include "conv-taskQ.h"
78 #endif
79 #include "conv-ccs.h"
80 #include "ccs-server.h"
81 #include "memory-isomalloc.h"
82 #if CMK_PROJECTOR
83 #include "converseEvents.h"             /* projector */
84 #include "traceCoreCommon.h"    /* projector */
85 #include "machineEvents.h"     /* projector */
86 #endif
88 CMI_EXTERNC_VARIABLE const char * const CmiCommitID;
90 #if CMI_QD
91 CMI_EXTERNC void initQd(char **argv);
92 #endif
94 #if CMK_OUT_OF_CORE
95 #include "conv-ooc.h"
96 #endif
98 #if CONVERSE_POOL
99 #include "cmipool.h"
100 #else
101 void CmiPoolAllocInit(int numBins);
102 #endif
104 #if CMK_CONDS_USE_SPECIAL_CODE
105 CmiSwitchToPEFnPtr CmiSwitchToPE;
106 #endif
108 CpvExtern(int, _traceCoreOn);   /* projector */
109 CMI_EXTERNC void CcdModuleInit(char **);
110 CMI_EXTERNC
111 void CmiMemoryInit(char **);
112 CMI_EXTERNC void CldModuleInit(char **);
114 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
115 #include <sys/types.h>
116 #include <sys/time.h>
117 #endif
119 #if CMK_TIMER_USE_TIMES
120 #include <sys/times.h>
121 #include <limits.h>
122 #include <unistd.h>
123 #endif
125 #if CMK_TIMER_USE_GETRUSAGE
126 #include <sys/time.h>
127 #include <sys/resource.h>
128 #endif
130 #if CMK_TIMER_USE_RDTSC
131 #include <string.h>
132 #include <unistd.h>
133 #include <time.h>
134 #include <stdio.h>
135 #include <sys/time.h>
136 #include <sys/resource.h>
137 #endif
139 #ifdef CMK_TIMER_USE_WIN32API
140 #include <stdlib.h>
141 #include <time.h>
142 #include <sys/types.h>
143 #include <sys/timeb.h>
144 #endif
146 #ifdef CMK_HAS_ASCTIME
147 #include <time.h>
148 #endif
150 #include "quiescence.h"
152 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
153 #include <mpi.h>
154 #endif
156 #if CMK_TRACE_ENABLED
157 struct envelope;
158 void traceAddThreadListeners(CthThread tid, struct envelope *env);
159 #endif
161 CMI_EXTERNC void seedBalancerExit(void);
162 CMI_EXTERNC
163 void EmergencyExit(void);
165 //int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
166 CpvDeclare(int,_curRestartPhase);
167 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
169 int CharmLibInterOperate = 0;
170 CpvCExtern(int,interopExitFlag);
171 CpvDeclare(int,interopExitFlag);
173 CpvStaticDeclare(int, CmiMainHandlerIDP); /* Main handler for _CmiMultipleSend that is run on every node */
175 #if CMK_MEM_CHECKPOINT
176 void (*notify_crash_fn)(int) = NULL;
177 #endif
179 CpvDeclare(char *, _validProcessors);
181 #if CMK_CUDA
182 CpvExtern(int, n_hapi_events);
183 CMI_EXTERNC
184 void hapiPollEvents();
185 CMI_EXTERNC
186 void exitHybridAPI();
187 #endif
189 /*****************************************************************************
191  * Unix Stub Functions
193  ****************************************************************************/
195 #ifdef MEMMONITOR
196 typedef unsigned long mmulong;
197 CpvDeclare(mmulong,MemoryUsage);
198 CpvDeclare(mmulong,HiWaterMark);
199 CpvDeclare(mmulong,ReportedHiWaterMark);
200 CpvDeclare(int,AllocCount);
201 CpvDeclare(int,BlocksAllocated);
202 #endif
204 #define MAX_HANDLERS 512
206 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
207 CpvDeclare(int,expIOFlushFlag);
208 #if CMI_IO_BUFFER_EXPLICIT
209 /* 250k not too large depending on how slow terminal IO is */
210 #define DEFAULT_IO_BUFFER_SIZE 250000
211 CpvDeclare(char*,explicitIOBuffer);
212 CpvDeclare(int,expIOBufferSize);
213 #endif
214 #endif
216 #if CMK_NODE_QUEUE_AVAILABLE
217 CMI_EXTERNC
218 void  *CmiGetNonLocalNodeQ();
219 #endif
221 CpvDeclare(Queue, CsdSchedQueue);
223 #if CMK_OUT_OF_CORE
224 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
225 CpvDeclare(Queue, CsdPrefetchQueue);
226 pthread_mutex_t prefetchLock;
227 #endif
229 #if CMK_NODE_QUEUE_AVAILABLE
230 CsvDeclare(Queue, CsdNodeQueue);
231 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
232 #endif
233 CpvDeclare(int,   CsdStopFlag);
234 CpvDeclare(int,   CsdLocalCounter);
236 CpvDeclare(int,   _urgentSend);
238 CmiNodeLock _smp_mutex;               /* for smp */
240 #if CMK_USE_IBVERBS | CMK_USE_IBUD
241 CMI_EXTERNC
242 void *infi_CmiAlloc(int size);
243 CMI_EXTERNC
244 void infi_CmiFree(void *ptr);
245 void infi_freeMultipleSend(void *ptr);
246 CMI_EXTERNC
247 void infi_unregAndFreeMeta(void *ch);
248 #endif
250 #if CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
251 CMI_EXTERNC void * CmiAlloc_bgq (int     size);
252 CMI_EXTERNC void   CmiFree_bgq  (void  * buf);
253 #endif
255 #if CMK_SMP && CMK_PPC_ATOMIC_QUEUE
256 CMI_EXTERNC void * CmiAlloc_ppcq (int     size);
257 CMI_EXTERNC void   CmiFree_ppcq  (void  * buf);
258 #endif
260 #if CMK_GRID_QUEUE_AVAILABLE
261 CpvDeclare(void *, CkGridObject);
262 CpvDeclare(Queue, CsdGridQueue);
263 #endif
265 #if CMK_CRAYXE || CMK_CRAYXC || CMK_OFI
266 CMI_EXTERNC void* LrtsAlloc(int, int);
267 CMI_EXTERNC void* LrtsRdmaAlloc(int, int);
268 CMI_EXTERNC void  LrtsFree(void*);
269 CMI_EXTERNC void  LrtsRdmaFree(void*);
270 #endif
272 CpvStaticDeclare(int, cmiMyPeIdle);
273 #if CMK_SMP && CMK_TASKQUEUE
274 CsvDeclare(unsigned int, idleThreadsCnt);
275 CpvDeclare(Queue, CsdTaskQueue);
276 CpvDeclare(void *, CmiSuspendedTaskQueue);
277 #endif
279 CpvDeclare(int, isHelperOn);
281 CMI_EXTERNC_VARIABLE int CmiMyLocalRank;
283 int    CmiMyLocalRank;        /* local rank only for scalable startup */
285 #if CMK_LOCKLESS_QUEUE
286 /*****************************************************************************
288  * MPSCQueue and MPMCQueue variables
290  *****************************************************************************/
291 int DataNodeSize;
292 int MaxDataNodes;
293 int QueueUpperBound;
294 int DataNodeWrap;
295 int QueueWrap;
296 int messageQueueOverflow;
297 #endif
299 /*****************************************************************************
301  * Command-Line Argument (CLA) parsing routines.
303  *****************************************************************************/
305 static int usageChecked=0; /* set when argv has been searched for a usage request */
306 static int printUsage=0; /* if set, print command-line usage information */
307 static const char *CLAformatString="%20s %10s %s\n";
309 /** This little list of CLA's holds the argument descriptions until it's
310    safe to print them--it's needed because the netlrts- versions don't have 
311    printf until they're pretty well started.
312  */
313 typedef struct {
314         const char *arg; /* Flag name, like "-foo"*/
315         const char *param; /* Argument's parameter type, like "integer" or "none"*/
316         const char *desc; /* Human-readable description of what it does */
317 } CLA;
318 static int CLAlistLen=0;
319 static int CLAlistMax=0;
320 static CLA *CLAlist=NULL;
322 /** Add this CLA */
323 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
324         int i;
325         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
326         if (desc==NULL) return; /*It's an internal argument*/
327         if (usageChecked) { /* Printf should work now */
328                 if (printUsage)
329                         CmiPrintf(CLAformatString,arg,param,desc);
330         }
331         else { /* Printf doesn't work yet-- just add to the list.
332                 This assumes the const char *'s are static references,
333                 which is probably reasonable. */
334                 CLA *temp;
335                 i=CLAlistLen++;
336                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
337                         CLAlistMax=16+2*CLAlistLen;
338                         temp = (CLA *)realloc(CLAlist,sizeof(CLA)*CLAlistMax);
339                         if(temp != NULL) {
340                           CLAlist=temp;
341                         } else {
342                           free(CLAlist);
343                           CmiAbort("Reallocation failed for CLAlist\n");
344                         }
345                 }
346                 CLAlist[i].arg=arg;
347                 CLAlist[i].param=param;
348                 CLAlist[i].desc=desc;
349         }
352 /** Print out the stored list of CLA's */
353 static void CmiPrintCLAs(void) {
354         int i;
355         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
356         CmiPrintf("Converse Machine Command-line Parameters:\n ");
357         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
358         for (i=0;i<CLAlistLen;i++) {
359                 CLA *c=&CLAlist[i];
360                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
361         }
365  * Determines if command-line usage information should be printed--
366  * that is, if a "-?", "-h", or "--help" flag is present.
367  * Must be called after printf is setup.
368  */
369 void CmiArgInit(char **argv) {
370         int i;
371         CmiLock(_smp_mutex);
372         for (i=0;argv[i]!=NULL;i++)
373         {
374                 if (0==strcmp(argv[i],"-?") ||
375                     0==strcmp(argv[i],"-h") ||
376                     0==strcmp(argv[i],"--help")) 
377                 {
378                         printUsage=1;
379                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
380                           Leave it there for user program to see... */
381                         CmiPrintCLAs();
382                 }
383         }
384         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
385                 CLAlistLen=CLAlistMax=0;
386                 free(CLAlist); CLAlist=NULL;
387         }
388         usageChecked=1;
389         CmiUnlock(_smp_mutex);
392 /** Return 1 if we're currently printing command-line usage information. */
393 int CmiArgGivingUsage(void) {
394         return (CmiMyPe()==0) && printUsage;
397 /** Identifies the module that accepts the following command-line parameters */
398 void CmiArgGroup(const char *parentName,const char *groupName) {
399         if (CmiArgGivingUsage()) {
400                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
401                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
402         }
405 /** Count the number of non-NULL arguments in list*/
406 int CmiGetArgc(char **argv)
408         int i=0,argc=0;
409         if (argv)
410         while (argv[i++]!=NULL)
411                 argc++;
412         return argc;
415 /** Return a new, heap-allocated copy of the argv array*/
416 char **CmiCopyArgs(char **argv)
418         int argc=CmiGetArgc(argv);
419         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
420         int i;
421         for (i=0;i<=argc;i++)
422                 ret[i]=argv[i];
423         return ret;
426 /** Delete the first k argument from the given list, shifting
427 all other arguments down by k spaces.
428 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
429 argv={"d",NULL,"c","d",NULL}
431 void CmiDeleteArgs(char **argv,int k)
433         int i=0;
434         while ((argv[i]=argv[i+k])!=NULL)
435                 i++;
438 /** Find the given argment and string option in argv.
439 If the argument is present, set the string option and
440 delete both from argv.  If not present, return NULL.
441 e.g., arg=="-name" returns "bob" from
442 argv=={"a.out","foo","-name","bob","bar"},
443 and sets argv={"a.out","foo","bar"};
445 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
447         int i;
448         CmiAddCLA(arg,"string",desc);
449         for (i=0;argv[i]!=NULL;i++)
450                 if (0==strcmp(argv[i],arg))
451                 {/*We found the argument*/
452                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
453                         *optDest=argv[i+1];
454                         CmiDeleteArgs(&argv[i],2);
455                         return 1;
456                 }
457         return 0;/*Didn't find the argument*/
459 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
460         return CmiGetArgStringDesc(argv,arg,optDest,"");
463 /** Find the given argument and floating-point option in argv.
464 Remove it and return 1; or return 0.
466 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
467         char *number=NULL;
468         CmiAddCLA(arg,"number",desc);
469         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
470         if (1!=sscanf(number,"%lg",optDest)) return 0;
471         return 1;
473 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
474         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
477 /** Find the given argument and integer option in argv.
478 If the argument is present, parse and set the numeric option,
479 delete both from argv, and return 1. If not present, return 0.
480 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
481 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
482 but not argv=={...,"-packsize",...}.
484 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
486         int i;
487         int argLen=strlen(arg);
488         CmiAddCLA(arg,"integer",desc);
489         for (i=0;argv[i]!=NULL;i++)
490                 if (0==strncmp(argv[i],arg,argLen))
491                 {/*We *may* have found the argument*/
492                         const char *opt=NULL;
493                         int nDel=0;
494                         switch(argv[i][argLen]) {
495                         case 0: /* like "-p","27" */
496                                 opt=argv[i+1]; nDel=2; break;
497                         case '=': /* like "-p=27" */
498                                 opt=&argv[i][argLen+1]; nDel=1; break;
499                         case '-':case '+':
500                         case '0':case '1':case '2':case '3':case '4':
501                         case '5':case '6':case '7':case '8':case '9':
502                                 /* like "-p27" */
503                                 opt=&argv[i][argLen]; nDel=1; break;
504                         default:
505                                 continue; /*False alarm-- skip it*/
506                         }
507                         if (opt==NULL) {
508                                 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
509                                                 "but none was provided\n", arg);
510                                 CmiAbort("Bad command-line argument\n");
511                         }
512                         if (sscanf(opt,"%i",optDest)<1) {
513                         /*Bad command line argument-- die*/
514                                 fprintf(stderr,"Cannot parse %s option '%s' "
515                                         "as an integer.\n",arg,opt);
516                                 CmiAbort("Bad command-line argument\n");
517                         }
518                         CmiDeleteArgs(&argv[i],nDel);
519                         return 1;
520                 }
521         return 0;/*Didn't find the argument-- dest is unchanged*/
523 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
524         return CmiGetArgIntDesc(argv,arg,optDest,"");
527 int CmiGetArgLongDesc(char **argv,const char *arg,CmiInt8 *optDest,const char *desc)
529         int i;
530         int argLen=strlen(arg);
531         CmiAddCLA(arg,"integer",desc);
532         for (i=0;argv[i]!=NULL;i++)
533                 if (0==strncmp(argv[i],arg,argLen))
534                 {/*We *may* have found the argument*/
535                         const char *opt=NULL;
536                         int nDel=0;
537                         switch(argv[i][argLen]) {
538                         case 0: /* like "-p","27" */
539                                 opt=argv[i+1]; nDel=2; break;
540                         case '=': /* like "-p=27" */
541                                 opt=&argv[i][argLen+1]; nDel=1; break;
542                         case '-':case '+':
543                         case '0':case '1':case '2':case '3':case '4':
544                         case '5':case '6':case '7':case '8':case '9':
545                                 /* like "-p27" */
546                                 opt=&argv[i][argLen]; nDel=1; break;
547                         default:
548                                 continue; /*False alarm-- skip it*/
549                         }
550                         if (opt==NULL) {
551                                 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
552                                                 "but none was provided\n", arg);
553                                 CmiAbort("Bad command-line argument\n");
554                         }
555                         if (sscanf(opt,"%" SCNd64,optDest)<1) {
556                         /*Bad command line argument-- die*/
557                                 fprintf(stderr,"Cannot parse %s option '%s' "
558                                         "as a long integer.\n",arg,opt);
559                                 CmiAbort("Bad command-line argument\n");
560                         }
561                         CmiDeleteArgs(&argv[i],nDel);
562                         return 1;
563                 }
564         return 0;/*Didn't find the argument-- dest is unchanged*/
566 int CmiGetArgLong(char **argv,const char *arg,CmiInt8 *optDest) {
567         return CmiGetArgLongDesc(argv,arg,optDest,"");
570 /** Find the given argument in argv.  If present, delete
571 it and return 1; if not present, return 0.
572 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
573 argv={...,"-foobar",...}.
575 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
577         int i;
578         CmiAddCLA(arg,"",desc);
579         for (i=0;argv[i]!=NULL;i++)
580                 if (0==strcmp(argv[i],arg))
581                 {/*We found the argument*/
582                         CmiDeleteArgs(&argv[i],1);
583                         return 1;
584                 }
585         return 0;/*Didn't find the argument*/
587 int CmiGetArgFlag(char **argv,const char *arg) {
588         return CmiGetArgFlagDesc(argv,arg,"");
591 void CmiDeprecateArgInt(char **argv,const char *arg,const char *desc,const char *warning)
593   int dummy = 0, found = CmiGetArgIntDesc(argv, arg, &dummy, desc);
595   if (found)
596     CmiPrintf(warning);
599 /*****************************************************************************
601  * Stack tracing routines.
603  *****************************************************************************/
604 #include "cmibacktrace.C"
607 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
608 the next parenthesis.  Operates in-place on the character data.
609 or Convert X(Y) to "Y" only, when trimname=1
611 static char *_implTrimParenthesis(char *str, int trimname) {
612   char *lParen=str, *ret=NULL, *rParen=NULL;
613   while (*lParen!='(') {
614     if (*lParen==0) return str; /* No left parenthesis at all. */
615     lParen++;
616   }
617   /* now *lParen=='(', so trim it*/
618   ret=lParen+1;
619   rParen=ret;
620   while (*rParen!=')') {
621     if (*rParen==0) return ret; /* No right parenthesis at all. */
622     rParen++;
623   }
624   /* now *rParen==')', so trim it*/
625   *rParen=trimname?0:' ';
626   return ret;  
630 Return the text description of this trimmed routine name, if 
631 it's a system-generated routine where we should stop printing. 
632 This is probably overkill, but improves the appearance of callbacks.
634 static const char* _implGetBacktraceSys(const char *name) {
635   if (0==strncmp(name,"_call",5)) 
636   { /*it might be something we're interested in*/
637     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
638     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
639   }
640   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
641   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
642   
643   return 0; /*ordinary user routine-- just print normally*/
646 /** Print out the names of these function pointers. */
647 void CmiBacktracePrint(void **retPtrs,int nLevels) {
648   if (nLevels>0) {
649     int i;
650     char **names=CmiBacktraceLookup(retPtrs,nLevels);
651     if (names==NULL) return;
652     CmiPrintf("[%d] Stack Traceback:\n", CmiMyPe());
653     for (i=0;i<nLevels;i++) {
654       if (names[i] == NULL) continue;
655       {
656       const char *trimmed=_implTrimParenthesis(names[i], 0);
657       const char *print=trimmed;
658       const char *sys=_implGetBacktraceSys(print);
659       if (sys) {
660           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
661           break; /*Stop when we hit Charm++ runtime.*/
662       } else {
663           CmiPrintf("  [%d:%d] %s\n",CmiMyPe(),i,print);
664       }
665      }
666     }
667     free(names);
668   }
671 /* Print (to stdout) the names of the functions that have been 
672    called up to this point. nSkip is the number of routines on the
673    top of the stack to *not* print out. */
674 void CmiPrintStackTrace(int nSkip) {
675 #if CMK_USE_BACKTRACE
676         int nLevels=max_stack;
677         void *stackPtrs[max_stack];
678         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
679         CmiBacktracePrint(stackPtrs,nLevels);
680 #endif
683 int CmiIsFortranLibraryCall(void) {
684 #if CMK_USE_BACKTRACE
685   int ret = 0;
686   int nLevels=9;
687   void *stackPtrs[18];
688   CmiBacktraceRecord(stackPtrs,1,&nLevels);
689   if (nLevels>0) {
690     int i;
691     char **names=CmiBacktraceLookup(stackPtrs,nLevels);
692     const char *trimmed;
693     if (names==NULL) return 0;
694     for (i=0;i<nLevels;i++) {
695       if (names[i] == NULL) continue;
696       trimmed=_implTrimParenthesis(names[i], 1);
697       if (strncmp(trimmed, "for__", 5) == 0                /* ifort */
698           || strncmp(trimmed, "_xlf", 4) == 0               /* xlf90 */
699           || strncmp(trimmed, "_xlfBeginIO", 11) == 0 
700           || strncmp(trimmed, "_gfortran_", 10) == 0 
701          )
702           {  /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
703              ret = 1; break; }
704     }
705     free(names);
706   }
707   return ret;
708 #else
709   return 0;
710 #endif
713 /*****************************************************************************
715  * Statistics: currently, the following statistics are not updated by converse.
717  *****************************************************************************/
719 CpvDeclare(int, CstatsMaxChareQueueLength);
720 CpvDeclare(int, CstatsMaxForChareQueueLength);
721 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
722 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
723 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
725 void CstatsInit(char ** argv)
728 #ifdef MEMMONITOR
729   CpvInitialize(mmulong,MemoryUsage);
730   CpvAccess(MemoryUsage) = 0;
731   CpvInitialize(mmulong,HiWaterMark);
732   CpvAccess(HiWaterMark) = 0;
733   CpvInitialize(mmulong,ReportedHiWaterMark);
734   CpvAccess(ReportedHiWaterMark) = 0;
735   CpvInitialize(int,AllocCount);
736   CpvAccess(AllocCount) = 0;
737   CpvInitialize(int,BlocksAllocated);
738   CpvAccess(BlocksAllocated) = 0;
739 #endif
741   CpvInitialize(int, CstatsMaxChareQueueLength);
742   CpvInitialize(int, CstatsMaxForChareQueueLength);
743   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
744   CpvInitialize(int, CstatPrintQueueStatsFlag);
745   CpvInitialize(int, CstatPrintMemStatsFlag);
747   CpvAccess(CstatsMaxChareQueueLength) = 0;
748   CpvAccess(CstatsMaxForChareQueueLength) = 0;
749   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
750   CpvAccess(CstatPrintQueueStatsFlag) = 0;
751   CpvAccess(CstatPrintMemStatsFlag) = 0;
753 #if 0
754   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
755     CpvAccess(CstatPrintMemStatsFlag)=1;
756   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
757     CpvAccess(CstatPrintQueueStatsFlag)=1;
758 #endif
761 int CstatMemory(int i)
763   return 0;
766 int CstatPrintQueueStats(void)
768   return CpvAccess(CstatPrintQueueStatsFlag);
771 int CstatPrintMemStats(void)
773   return CpvAccess(CstatPrintMemStatsFlag);
776 /*****************************************************************************
778  * Cmi handler registration
780  *****************************************************************************/
782 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
783 CpvStaticDeclare(int  , CmiHandlerCount);
784 CpvStaticDeclare(int  , CmiHandlerLocal);
785 CpvStaticDeclare(int  , CmiHandlerGlobal);
786 CpvDeclare(int,         CmiHandlerMax);
788 static void CmiExtendHandlerTable(int atLeastLen) {
789     int max = CpvAccess(CmiHandlerMax);
790     int newmax = (atLeastLen+(atLeastLen>>2)+32);
791     int bytes = max*sizeof(CmiHandlerInfo);
792     int newbytes = newmax*sizeof(CmiHandlerInfo);
793     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
794     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
795     _MEMCHECK(nu);
796     if (tab) {
797       memcpy(nu, tab, bytes);
798     }
799     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
800     free(tab); tab=nu;
801     CpvAccess(CmiHandlerTable) = tab;
802     CpvAccess(CmiHandlerMax) = newmax;
805 void CmiAssignOnce(int* variable, int value) {
806   if (CmiMyRank() == 0) { *variable = value; }
807   CmiNodeAllBarrier();
810 void CmiNumberHandler(int n, CmiHandler h)
812   CmiHandlerInfo *tab;
813   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
814   tab = CpvAccess(CmiHandlerTable);
815   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
816   tab[n].userPtr = 0;
818 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
819   CmiHandlerInfo *tab;
820   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
821   tab = CpvAccess(CmiHandlerTable);
822   tab[n].hdlr = h;
823   tab[n].userPtr=userPtr;
826 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
827 #  define DIST_BETWEEN_HANDLERS 3
828 #else /*No local or global handlers; ordinary handlers are back-to-back*/
829 #  define DIST_BETWEEN_HANDLERS 1
830 #endif
832 int CmiRegisterHandler(CmiHandler h)
834   int Count = CpvAccess(CmiHandlerCount);
835   CmiNumberHandler(Count, h);
836   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
837   return Count;
840 void CmiRegisterHandlerAssignOnce(CmiHandler h, int *index)
842   if (CmiMyRank() == 0) { *index = CmiRegisterHandler(h); }
843   else { CmiRegisterHandler(h); }
844   CmiBarrier();
847 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
849   int Count = CpvAccess(CmiHandlerCount);
850   CmiNumberHandlerEx(Count, h, userPtr);
851   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
852   return Count;
855 void CmiRegisterHandlerExAssignOnce(CmiHandlerEx h, void *userPtr, int *index)
857   if (CmiMyRank() == 0) { *index = CmiRegisterHandlerEx(h, userPtr); }
858   else { CmiRegisterHandlerEx(h, userPtr); }
859   CmiBarrier();
862 #if CMI_LOCAL_GLOBAL_AVAILABLE
863 int CmiRegisterHandlerLocal(CmiHandler h)
865   int Local = CpvAccess(CmiHandlerLocal);
866   CmiNumberHandler(Local, h);
867   CpvAccess(CmiHandlerLocal) = Local+3;
868   return Local;
871 int CmiRegisterHandlerGlobal(CmiHandler h)
873   int Global = CpvAccess(CmiHandlerGlobal);
874   if (CmiMyPe()!=0) 
875     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
876   CmiNumberHandler(Global, h);
877   CpvAccess(CmiHandlerGlobal) = Global+3;
878   return Global;
880 #endif
882 static void _cmiZeroHandler(void *msg) {
883         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
886 static void CmiHandlerInit(void)
888   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
889   CpvInitialize(int         , CmiHandlerCount);
890   CpvInitialize(int         , CmiHandlerLocal);
891   CpvInitialize(int         , CmiHandlerGlobal);
892   CpvInitialize(int         , CmiHandlerMax);
893   CpvAccess(CmiHandlerCount)  = 0;
894   CpvAccess(CmiHandlerLocal)  = 1;
895   CpvAccess(CmiHandlerGlobal) = 2;
896   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
897   CpvAccess(CmiHandlerTable) = NULL;
898   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
902 /******************************************************************************
904  * CmiTimer
906  * Here are two possible implementations of CmiTimer.  Some machines don't
907  * select either, and define the timer in machine.C instead.
909  *****************************************************************************/
911 #if CMK_HAS_ASCTIME
913 char *CmiPrintDate(void)
915   struct tm *local;
916   time_t t;
918   t = time(NULL);
919   local = localtime(&t);
920   return asctime(local);
923 #else
925 char *CmiPrintDate(void)
927   return "N/A";
930 #endif
932 static int _absoluteTime = 0;
934 #if CMK_TIMER_USE_TIMES
936 CpvStaticDeclare(double, clocktick);
937 CpvStaticDeclare(int,inittime_wallclock);
938 CpvStaticDeclare(int,inittime_virtual);
940 int CmiTimerIsSynchronized(void)
942   return 0;
945 int CmiTimerAbsolute(void)
947   return 0;
950 double CmiStartTimer(void)
952   return 0.0;
955 double CmiInitTime(void)
957   return CpvAccess(inittime_wallclock);
960 void CmiTimerInit(char **argv)
962   struct tms temp;
963   CpvInitialize(double, clocktick);
964   CpvInitialize(int, inittime_wallclock);
965   CpvInitialize(int, inittime_virtual);
966   CpvAccess(inittime_wallclock) = times(&temp);
967   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
968   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
971 double CmiWallTimer(void)
973   struct tms temp;
974   double currenttime;
975   int now;
977   now = times(&temp);
978   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
979   return (currenttime);
982 double CmiCpuTimer(void)
984   struct tms temp;
985   double currenttime;
986   int now;
988   times(&temp);
989   now = temp.tms_stime + temp.tms_utime;
990   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
991   return (currenttime);
994 double CmiTimer(void)
996   return CmiCpuTimer();
999 #endif
1001 #if CMK_TIMER_USE_GETRUSAGE
1003 #if CMK_SMP
1004 # if CMK_HAS_RUSAGE_THREAD
1005 #define RUSAGE_WHO        1   /* RUSAGE_THREAD, only in latest Linux kernels */
1006 #else
1007 #undef RUSAGE_WHO
1008 #endif
1009 #else
1010 #define RUSAGE_WHO        0
1011 #endif
1013 static double inittime_wallclock;
1014 CpvStaticDeclare(double, inittime_virtual);
1016 int CmiTimerIsSynchronized(void)
1018   return 0;
1021 int CmiTimerAbsolute(void)
1023   return _absoluteTime;
1026 double CmiStartTimer(void)
1028   return 0.0;
1031 double CmiInitTime(void)
1033   return inittime_wallclock;
1036 void CmiTimerInit(char **argv)
1038   struct rusage ru;
1039   CpvInitialize(double, inittime_virtual);
1041   int tmptime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1042   if(CmiMyRank() == 0) _absoluteTime = tmptime;   /* initialize only  once */
1043 #if !(__FAULT__)
1044   /* try to synchronize calling barrier */
1045   CmiBarrier();
1046   CmiBarrier();
1047   CmiBarrier();
1048 #endif
1049 if(CmiMyRank() == 0) /* initialize only  once */
1050   {
1051     inittime_wallclock = inithrc();
1052 #ifndef RUSAGE_WHO
1053     CpvAccess(inittime_virtual) = inittime_wallclock;
1054 #else
1055     getrusage(RUSAGE_WHO, &ru); 
1056     CpvAccess(inittime_virtual) =
1057       (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1058       (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1059 #endif
1060   }
1062 #if !(__FAULT__)
1063   CmiBarrier();
1064 /*  CmiBarrierZero(); */
1065 #endif
1068 double CmiCpuTimer(void)
1070 #ifndef RUSAGE_WHO
1071   return CmiWallTimer();
1072 #else
1073   struct rusage ru;
1074   double currenttime;
1076   getrusage(RUSAGE_WHO, &ru);
1077   currenttime =
1078     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1079     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1080   
1081   return currenttime - CpvAccess(inittime_virtual);
1082 #endif
1085 static double lastT = -1.0;
1087 double CmiWallTimer(void)
1089   double currenttime;
1090   currenttime = gethrctime();
1091   return _absoluteTime?currenttime+inittime_wallclock:currenttime;
1094 double CmiTimer(void)
1096   return CmiCpuTimer();
1099 #endif
1101 #if CMK_TIMER_USE_RDTSC
1103 static double readMHz(void)
1105   double x;
1106   char str[1000];
1107   char buf[100];
1108   FILE *fp;
1109   CmiLock(_smp_mutex);
1110   fp = fopen("/proc/cpuinfo", "r");
1111   if (fp != NULL)
1112   while(fgets(str, 1000, fp)!=0) {
1113     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1114     {
1115       char *s = strchr(str, ':'); s=s+1;
1116       sscanf(s, "%lf", &x);
1117       fclose(fp);
1118       CmiUnlock(_smp_mutex);
1119       return x;
1120     }
1121   }
1122   CmiUnlock(_smp_mutex);
1123   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
1124   return 0.0;
1127 double _cpu_speed_factor;
1128 CpvStaticDeclare(double, inittime_virtual);
1129 CpvStaticDeclare(double, inittime_walltime);
1131 double  CmiStartTimer(void)
1133   return CpvAccess(inittime_walltime);
1136 double CmiInitTime(void)
1138   return CpvAccess(inittime_walltime);
1141 void CmiTimerInit(char **argv)
1143   struct rusage ru;
1145   CmiBarrier();
1146   CmiBarrier();
1148   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
1149   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
1150   CpvInitialize(double, inittime_walltime);
1151   CpvAccess(inittime_walltime) = CmiWallTimer();
1152   CpvInitialize(double, inittime_virtual);
1153   getrusage(0, &ru); 
1154   CpvAccess(inittime_virtual) =
1155     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1156     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1158   CmiBarrierZero();
1161 double CmiCpuTimer(void)
1163   struct rusage ru;
1164   double currenttime;
1166   getrusage(0, &ru);
1167   currenttime =
1168     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1169     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1170   return currenttime - CpvAccess(inittime_virtual);
1173 #endif
1175 #if CMK_TIMER_USE_BLUEGENEQ  /* This module just compiles with GCC charm. */
1177 CpvStaticDeclare(unsigned long, inittime);
1178 CpvStaticDeclare(double, clocktick);
1180 int CmiTimerIsSynchronized(void)
1182   return 1;
1185 int CmiTimerAbsolute(void)
1187   return 0;
1190 #include "hwi/include/bqc/A2_inlines.h"
1191 #include "spi/include/kernel/process.h"
1193 double CmiStartTimer(void)
1195   return 0.0;
1198 double CmiInitTime(void)
1200   return CpvAccess(inittime);
1203 void CmiTimerInit(char **argv)
1205   CpvInitialize(double, clocktick);
1206   CpvInitialize(unsigned long, inittime);
1208   Personality_t  pers;
1209   Kernel_GetPersonality(&pers, sizeof(pers));
1210   uint32_t clockMhz = pers.Kernel_Config.FreqMHz;
1211   CpvAccess(clocktick) = 1.0 / (clockMhz * 1e6); 
1213   /*fprintf(stderr, "Blue Gene/Q running at clock speed of %d Mhz\n", clockMhz);*/
1215   /* try to synchronize calling barrier */
1216 #if !(__FAULT__)
1217   CmiBarrier();
1218   CmiBarrier();
1219   CmiBarrier();
1220 #endif
1221   CpvAccess(inittime) = GetTimeBase (); 
1224 double CmiWallTimer(void)
1226   unsigned long long currenttime;
1227   currenttime = GetTimeBase();
1228   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1231 double CmiCpuTimer(void)
1233   return CmiWallTimer();
1236 double CmiTimer(void)
1238   return CmiWallTimer();
1241 #endif
1244 #if CMK_TIMER_USE_PPC64
1246 #include <sys/time.h>
1247 #include <sys/platform/ppc.h>
1249 CpvStaticDeclare(uint64_t, inittime);
1250 CpvStaticDeclare(double, clocktick);
1252 int CmiTimerIsSynchronized(void)
1254   return 1;
1257 int CmiTimerAbsolute(void)
1259   return 0;
1262 double CmiStartTimer(void)
1264   return 0.0;
1267 double CmiInitTime(void)
1269   return CpvAccess(inittime);
1272 static inline uint64_t PPC64_TimeBase(void)
1274   register volatile uint64_t result;
1276   /* For 64-bit only */
1277   asm volatile (
1278             "   isync    \n\t"
1279             "   mftb  %0 \n\t"
1280             "   isync    \n\t"
1281             : "=r"(result));
1283   return result;
1286 void CmiTimerInit(char **argv)
1288   CpvInitialize(double, clocktick);
1289   CpvInitialize(unsigned long, inittime);
1290   CpvAccess(clocktick) =  1.0 / ((double) __ppc_get_timebase_freq());
1292   /* try to synchronize calling barrier */
1293 #if !(__FAULT__)
1294   CmiBarrier();
1295   CmiBarrier();
1296   CmiBarrier();
1297 #endif
1298   CpvAccess(inittime) = PPC64_TimeBase ();
1301 double CmiWallTimer(void)
1303   uint64_t currenttime;
1304   currenttime = PPC64_TimeBase();
1305   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1308 double CmiCpuTimer(void)
1310   return CmiWallTimer();
1313 double CmiTimer(void)
1315   return CmiWallTimer();
1318 #endif
1321 #if CMK_TIMER_USE_WIN32API
1323 CpvStaticDeclare(double, inittime_wallclock);
1324 CpvStaticDeclare(double, inittime_virtual);
1326 double CmiStartTimer(void)
1328   return 0.0;
1331 int CmiTimerAbsolute(void)
1333   return 0;
1336 double CmiInitTime(void)
1338   return CpvAccess(inittime_wallclock);
1341 void CmiTimerInit(char **argv)
1343         struct timeb tv;
1344         clock_t       ru;
1346         CpvInitialize(double, inittime_wallclock);
1347         CpvInitialize(double, inittime_virtual);
1348         ftime(&tv);
1349         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1350         ru = clock();
1351         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1354 double CmiCpuTimer(void)
1356         clock_t ru;
1357         double currenttime;
1359         ru = clock();
1360         currenttime = (double) ru/CLOCKS_PER_SEC;
1362         return currenttime - CpvAccess(inittime_virtual);
1365 double CmiWallTimer(void)
1367         struct timeb tv;
1368         double currenttime;
1370         ftime(&tv);
1371         currenttime = tv.time*1.0 + tv.millitm*0.001;
1373         return currenttime - CpvAccess(inittime_wallclock);
1375         
1377 double CmiTimer(void)
1379         return CmiCpuTimer();
1382 #endif
1384 #if CMK_TIMER_USE_RTC
1386 static double clocktick;
1387 CpvStaticDeclare(long long, inittime_wallclock);
1389 double CmiStartTimer(void)
1391   return 0.0;
1394 double CmiInitTime(void)
1396   return CpvAccess(inittime_wallclock);
1399 void CmiTimerInit(char **argv)
1401   CpvInitialize(long long, inittime_wallclock);
1402   CpvAccess(inittime_wallclock) = _rtc();
1403   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1406 int CmiTimerAbsolute(void)
1408   return 0;
1411 double CmiWallTimer(void)
1413   long long now;
1415   now = _rtc();
1416   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1419 double CmiCpuTimer(void)
1421   return CmiWallTimer();
1424 double CmiTimer(void)
1426   return CmiCpuTimer();
1429 #endif
1431 #if CMK_TIMER_USE_AIX_READ_TIME
1433 #include <sys/time.h>
1435 static timebasestruct_t inittime_wallclock;
1436 static double clocktick;
1437 CpvStaticDeclare(double, inittime_virtual);
1439 double CmiStartTimer(void)
1441   return 0.0;
1444 double CmiInitTime(void)
1446   return inittime_wallclock;
1449 void CmiTimerInit(char **argv)
1451   struct rusage ru;
1453   if (CmiMyRank() == 0) {
1454     read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1455     time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1456   }
1458   CpvInitialize(double, inittime_virtual);
1459   getrusage(0, &ru);
1460   CpvAccess(inittime_virtual) =
1461     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1462     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1465 int CmiTimerAbsolute(void)
1467   return 0;
1470 double CmiWallTimer(void)
1472   int secs, n_secs;
1473   double curt;
1474   timebasestruct_t now;
1475   read_wall_time(&now, TIMEBASE_SZ);
1476   time_base_to_time(&now, TIMEBASE_SZ);
1478   secs = now.tb_high - inittime_wallclock.tb_high;
1479   n_secs = now.tb_low - inittime_wallclock.tb_low;
1480   if (n_secs < 0)  {
1481     secs--;
1482     n_secs += 1000000000;
1483   }
1484   curt = secs*1.0 + n_secs*1e-9;
1485   return curt;
1488 double CmiCpuTimer(void)
1490   struct rusage ru;
1491   double currenttime;
1493   getrusage(0, &ru);
1494   currenttime =
1495     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1496     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1497   return currenttime - CpvAccess(inittime_virtual);
1500 double CmiTimer(void)
1502   return CmiWallTimer();
1505 #endif
1507 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1508 /** Return 1 if our outgoing message queue 
1509    for this node is longer than this many bytes. */
1510 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1511   return 0;
1513 #endif
1515 #if CMK_SIGNAL_USE_SIGACTION
1516 #include <signal.h>
1517 CMI_EXTERNC
1518 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1520   struct sigaction in, out ;
1521   in.sa_handler = handler;
1522   sigemptyset(&in.sa_mask);
1523   if (sig1) sigaddset(&in.sa_mask, sig1);
1524   if (sig2) sigaddset(&in.sa_mask, sig2);
1525   if (sig3) sigaddset(&in.sa_mask, sig3);
1526   in.sa_flags = 0;
1527   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1528   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1529   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1531 #endif
1533 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1534 #include <signal.h>
1535 CMI_EXTERNC
1536 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1538   struct sigaction in, out ;
1539   in.sa_handler = handler;
1540   sigemptyset(&in.sa_mask);
1541   if (sig1) sigaddset(&in.sa_mask, sig1);
1542   if (sig2) sigaddset(&in.sa_mask, sig2);
1543   if (sig3) sigaddset(&in.sa_mask, sig3);
1544   in.sa_flags = SA_RESTART;
1545   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1546   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1547   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1549 #endif
1551 /** 
1552  *  @addtogroup ConverseScheduler
1553  *  @{
1554  */
1556 /*****************************************************************************
1557  * 
1558  * The following is the CsdScheduler function.  A common
1559  * implementation is provided below.  The machine layer can provide an
1560  * alternate implementation if it so desires.
1562  * void CmiDeliversInit()
1564  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1565  *        or any of the other functions in this section.
1567  * int CmiDeliverMsgs(int maxmsgs)
1569  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1570  *        with the Cmi, and will invoke their handlers.  It does not wait
1571  *        if no message is unavailable.  Instead, it returns the quantity
1572  *        (maxmsgs-delivered), where delivered is the number of messages it
1573  *        delivered.
1575  * void CmiDeliverSpecificMsg(int handlerno)
1577  *      - Waits for a message with the specified handler to show up, then
1578  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1579  *        This function _does_ wait.
1581  * For this common implementation to work, the machine layer must provide the
1582  * following:
1584  * void *CmiGetNonLocal()
1586  *      - returns a message just retrieved from some other PE, not from
1587  *        local.  If no such message exists, returns 0.
1589  * CpvExtern(CdsFifo, CmiLocalQueue);
1591  *      - a FIFO queue containing all messages from the local processor.
1593  *****************************************************************************/
1595 void CsdBeginIdle(void)
1597   CcdCallBacks();
1598 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1599   _LOG_E_PROC_IDLE();   /* projector */
1600 #endif
1601 #if CMK_SMP && CMK_TASKQUEUE
1602   if (CpvAccess(cmiMyPeIdle) !=1) {
1603     CpvAccess(cmiMyPeIdle) = 1;
1604     CmiMemoryAtomicIncrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1605   }
1606 #else
1607   CpvAccess(cmiMyPeIdle) = 1;
1608 #endif // CMK_SMP
1609   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1612 void CsdStillIdle(void)
1614   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1617 void CsdEndIdle(void)
1619 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1620   _LOG_E_PROC_BUSY();   /* projector */
1621 #endif
1622 #if CMK_SMP && CMK_TASKQUEUE
1623   if (CpvAccess(cmiMyPeIdle) != 0){
1624     CpvAccess(cmiMyPeIdle) = 0;
1625     CmiMemoryAtomicDecrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1626   }
1627 #else
1628   CpvAccess(cmiMyPeIdle) = 0;
1629 #endif // CMK_SMP
1630   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1633 extern int _exitHandlerIdx;
1635 /** Takes a message and calls its corresponding handler. */
1636 void CmiHandleMessage(void *msg)
1638 /* this is wrong because it counts the Charm++ messages in sched queue
1639         CpvAccess(cQdState)->mProcessed++;
1641         CmiHandlerInfo *h;
1642         CmiUInt2 handlerIdx=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1643 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1644         _LOG_E_HANDLER_BEGIN(handlerIdx); /* projector */
1645         /* setMemoryStatus(1) */ /* charmdebug */
1646 #endif
1649         CMK_FAULT_EVAC
1651 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1652                 return;
1653         }*/
1654         
1655         MESSAGE_PHASE_CHECK(msg)
1656 #if CMK_ERROR_CHECKING
1657         if (handlerIdx >= CpvAccess(CmiHandlerCount)) {
1658           CmiAbort("Msg handler does not exist, possible race condition during init\n");
1659         }
1660 #endif
1661         h=&CmiHandlerToInfo(handlerIdx);
1662 #if CMK_ERROR_CHECKING
1663         if (h->hdlr == NULL) {
1664           CmiAbort("Msg handler does not exist, possible race condition during init\n");
1665         }
1666 #endif
1667         (h->hdlr)(msg,h->userPtr);
1668 #if CMK_TRACE_ENABLED
1669         /* setMemoryStatus(0) */ /* charmdebug */
1670         //_LOG_E_HANDLER_END(handlerIdx);       /* projector */
1671 #endif
1674 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1676 void CmiDeliversInit(void)
1680 int CmiDeliverMsgs(int maxmsgs)
1682   return CsdScheduler(maxmsgs);
1685 #if CMK_OBJECT_QUEUE_AVAILABLE
1686 CpvDeclare(void *, CsdObjQueue);
1687 #endif
1689 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1691 #if CMK_OBJECT_QUEUE_AVAILABLE
1692         s->objQ=CpvAccess(CsdObjQueue);
1693 #endif
1694         s->localQ=CpvAccess(CmiLocalQueue);
1695         s->schedQ=CpvAccess(CsdSchedQueue);
1696         s->localCounter=&(CpvAccess(CsdLocalCounter));
1697 #if CMK_NODE_QUEUE_AVAILABLE
1698         s->nodeQ=CsvAccess(CsdNodeQueue);
1699         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1700 #endif
1701 #if CMK_GRID_QUEUE_AVAILABLE
1702         s->gridQ=CpvAccess(CsdGridQueue);
1703 #endif
1704 #if CMK_SMP && CMK_TASKQUEUE
1705         s->taskQ = CpvAccess(CsdTaskQueue);
1706         s->suspendedTaskQ = CpvAccess(CmiSuspendedTaskQueue);
1707 #endif
1711 /** Dequeue and return the next message from the unprocessed message queues.
1713  * This function encapsulates the multiple queues that exist for holding unprocessed
1714  * messages and the rules for the order in which to check them. There are five (5)
1715  * different Qs that converse uses to store and retrieve unprocessed messages. These
1716  * are:
1717  *     Q Purpose                  Type      internal DeQ logic
1718  * -----------------------------------------------------------
1719  * - PE offnode                   pcQ             FIFO
1720  * - PE onnode                    CkQ             FIFO
1721  * - Node offnode                 pcQ             FIFO
1722  * - Node onnode                  prioQ           prio-based
1723  * - Scheduler                    prioQ           prio-based
1725  * The PE queues hold messages that are destined for a specific PE. There is one such
1726  * queue for every PE within a charm node. The node queues hold messages that are
1727  * destined to that node. There is only one of each node queue within a charm node.
1728  * Finally there is also a charm++ message queue for each PE.
1730  * The offnode queues are meant for holding messages that arrive from outside the
1731  * node. The onnode queues hold messages that are generated within the same charm
1732  * node.
1734  * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1735  * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1736  * and hide the implementation specifics for each layer.
1738  * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1739  * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1740  * queues. They are initialized via calls to CqsCreate() which gives each of them
1741  * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1742  * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1743  * is passed into this function.
1745  * The order in which these queues are checked is described below. The function
1746  * proceeds to the next queue in the list only if it does not find any messages in
1747  * the current queue. The first message that is found is returned, terminating the
1748  * call.
1749  * (1) offnode queue for this PE
1750  * (2) onnode queue for this PE
1751  * (3) offnode queue for this node
1752  * (4) highest priority msg from onnode queue or scheduler queue
1754  * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1755  * access (after observing adequate locking rigor) structs representing the scheduler
1756  * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1757  * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1758  * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1760  */
1761 void *CsdNextMessage(CsdSchedulerState_t *s) {
1762         void *msg;
1763         if((*(s->localCounter))-- >0)
1764           {
1765               /* This avoids a race condition with migration detected by megatest*/
1766               msg=CdsFifo_Dequeue(s->localQ);
1767               if (msg!=NULL)
1768                 {
1769 #if CMI_QD
1770                   CpvAccess(cQdState)->mProcessed++;
1771 #endif
1772                   return msg;       
1773                 }
1774               CqsDequeue(s->schedQ,(void **)&msg);
1775               if (msg!=NULL) return msg;
1776           }
1777         
1778         *(s->localCounter)=CsdLocalMax;
1779         if ( NULL!=(msg=CmiGetNonLocal()) || 
1780              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1781 #if CMI_QD
1782             CpvAccess(cQdState)->mProcessed++;
1783 #endif
1784             return msg;
1785         }
1786 #if CMK_GRID_QUEUE_AVAILABLE
1787         /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1788         CqsDequeue (s->gridQ, (void **) &msg);
1789         if (msg != NULL) {
1790           return (msg);
1791         }
1792 #endif
1793 #if CMK_SMP && CMK_TASKQUEUE
1794 #if CMK_OMP
1795         msg = CmiSuspendedTaskPop();
1796         if (msg != NULL) {
1797           return (msg);
1798         }
1799 #endif
1800         msg = TaskQueuePop((TaskQueue)s->taskQ);
1801         if (msg != NULL) {
1802           return (msg);
1803         }
1804 #endif
1805 #if CMK_NODE_QUEUE_AVAILABLE
1806         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1807         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1808 #if !CMK_NO_MSG_PRIOS
1809         if (!CqsEmpty(s->nodeQ)
1810          && CqsPrioGT(CqsGetPriority(s->schedQ),
1811                        CqsGetPriority(s->nodeQ))) {
1812           if(CmiTryLock(s->nodeLock) == 0) {
1813             CqsDequeue(s->nodeQ,(void **)&msg);
1814             CmiUnlock(s->nodeLock);
1815             if (msg!=NULL) return msg;
1816           }
1817         }
1818 #endif
1819 #endif
1820 #if CMK_OBJECT_QUEUE_AVAILABLE
1821         /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE"   */
1822         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1823           return msg;
1824         }
1825 #endif
1826         if(!CsdLocalMax) {
1827           CqsDequeue(s->schedQ,(void **)&msg);
1828           if (msg!=NULL) return msg;        
1829         }
1830         return NULL;
1834 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1835         void *msg;
1836 #if CMK_NODE_QUEUE_AVAILABLE
1837         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1838         /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1839         if (!CqsEmpty(s->nodeQ))
1840         {
1841           CmiLock(s->nodeLock);
1842           CqsDequeue(s->nodeQ,(void **)&msg);
1843           CmiUnlock(s->nodeLock);
1844           if (msg!=NULL) return msg;
1845         }
1846 #endif
1847         return NULL;
1851 int CsdScheduler(int maxmsgs)
1853         if (maxmsgs<0) CsdScheduleForever();    
1854         else if (maxmsgs==0)
1855                 CsdSchedulePoll();
1856         else /*(maxmsgs>0)*/ 
1857                 return CsdScheduleCount(maxmsgs);
1858         return 0;
1861 /*Declare the standard scheduler housekeeping*/
1862 #define SCHEDULE_TOP \
1863       void *msg;\
1864       int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1865       int cycle = CpvAccess(CsdStopFlag); \
1866       CsdSchedulerState_t state;\
1867       CsdSchedulerState_new(&state);
1869 /*A message is available-- process it*/
1870 #define SCHEDULE_MESSAGE \
1871       CmiHandleMessage(msg);\
1872       if (*CsdStopFlag_ptr != cycle) break;
1874 /*No message available-- go (or remain) idle*/
1875 #if CSD_NO_IDLE_TRACING
1876 #define SCHEDULE_IDLE /* do nothing */
1877 #else
1878 #define SCHEDULE_IDLE \
1879       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1880       else CsdStillIdle();\
1881       if (*CsdStopFlag_ptr != cycle) {\
1882         CsdEndIdle();\
1883         break;\
1884       }
1885 #endif
1888         EVAC
1890 extern void CkClearAllArrayElements(void);
1893 extern void machine_OffloadAPIProgress(void);
1895 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1896 void CsdScheduleForever(void)
1898   #if CMK_CELL
1899     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1900     int progressCount = CMK_CELL_PROGRESS_FREQ;
1901   #endif
1903   int isIdle=0;
1904   SCHEDULE_TOP
1905   while (1) {
1906 #if !CMK_NO_INTEROP
1907     /* The interoperation will cost this little overhead in scheduling */
1908     if(CharmLibInterOperate) {
1909       if(CpvAccess(interopExitFlag)) {
1910         CpvAccess(interopExitFlag) = 0;
1911         break;
1912       }
1913     }
1914 #endif
1915     #if CMK_CUDA
1916     // check if any GPU work needs to be processed
1917     if (CpvAccess(n_hapi_events) > 0) {
1918       hapiPollEvents();
1919     }
1920     #endif
1921     msg = CsdNextMessage(&state);
1922     if (msg!=NULL) { /*A message is available-- process it*/
1923 #if !CSD_NO_IDLE_TRACING
1924       if (isIdle) {isIdle=0;CsdEndIdle();}
1925 #endif
1926       SCHEDULE_MESSAGE
1928       #if CMK_CELL
1929         if (progressCount <= 0) {
1930           /*OffloadAPIProgress();*/
1931           machine_OffloadAPIProgress();
1932           progressCount = CMK_CELL_PROGRESS_FREQ;
1933         }
1934         progressCount--;
1935       #endif
1936     } else { /*No message available-- go (or remain) idle*/
1937       SCHEDULE_IDLE
1939       #if CMK_CELL
1940         /*OffloadAPIProgress();*/
1941         machine_OffloadAPIProgress();
1942         progressCount = CMK_CELL_PROGRESS_FREQ;
1943       #endif
1944     }
1945 #if !CSD_NO_PERIODIC
1946     CsdPeriodic();
1947 #endif
1948   }
1950 int CsdScheduleCount(int maxmsgs)
1952   int isIdle=0;
1953   SCHEDULE_TOP
1954   while (1) {
1955     msg = CsdNextMessage(&state);
1956     if (msg!=NULL) { /*A message is available-- process it*/
1957 #if !CSD_NO_IDLE_TRACING
1958       if (isIdle) {isIdle=0;CsdEndIdle();}
1959 #endif
1960       maxmsgs--; 
1961       SCHEDULE_MESSAGE
1962       if (maxmsgs==0) break;
1963     } else { /*No message available-- go (or remain) idle*/
1964       SCHEDULE_IDLE
1965     }
1966 #if !CSD_NO_PERIODIC
1967     CsdPeriodic();
1968 #endif
1969   }
1970   return maxmsgs;
1973 void CsdSchedulePoll(void)
1975   SCHEDULE_TOP
1976   while (1)
1977   {
1978 #if !CSD_NO_PERIODIC
1979         CsdPeriodic();
1980 #endif
1981         /*CmiMachineProgressImpl(); ??? */
1982         if (NULL!=(msg = CsdNextMessage(&state)))
1983         {
1984              SCHEDULE_MESSAGE 
1985         }
1986         else break;
1987   }
1990 void CsdScheduleNodePoll(void)
1992   SCHEDULE_TOP
1993   while (1)
1994   {
1995         /*CsdPeriodic();*/
1996         /*CmiMachineProgressImpl(); ??? */
1997         if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
1998         {
1999              SCHEDULE_MESSAGE 
2000         }
2001         else break;
2002   }
2005 void CmiDeliverSpecificMsg(int handler)
2007   int *msg; int side;
2008   void *localqueue = CpvAccess(CmiLocalQueue);
2010   side = 0;
2011   while (1) {
2012 #if !CSD_NO_PERIODIC
2013     CsdPeriodic();
2014 #endif
2015     side ^= 1;
2016     if (side) msg = (int *)CmiGetNonLocal();
2017     else      msg = (int *)CdsFifo_Dequeue(localqueue);
2018     if (msg) {
2019       if (CmiGetHandler(msg)==handler) {
2020 #if CMI_QD
2021         CpvAccess(cQdState)->mProcessed++;
2022 #endif
2023         CmiHandleMessage(msg);
2024         return;
2025       } else {
2026         CdsFifo_Enqueue(localqueue, msg);
2027       }
2028     }
2029   }
2032 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
2034 /***************************************************************************
2036  * Standin Schedulers.
2038  * We use the following strategy to make sure somebody's always running
2039  * the scheduler (CsdScheduler).  Initially, we assume the main thread
2040  * is responsible for this.  If the main thread blocks, we create a
2041  * "standin scheduler" thread to replace it.  If the standin scheduler
2042  * blocks, we create another standin scheduler to replace that one,
2043  * ad infinitum.  Collectively, the main thread and all the standin
2044  * schedulers are called "scheduling threads".
2046  * Suppose the main thread is blocked waiting for data, and a standin
2047  * scheduler is running instead.  Suppose, then, that the data shows
2048  * up and the main thread is CthAwakened.  This causes a token to be
2049  * pushed into the queue.  When the standin pulls the token from the
2050  * queue and handles it, the standin goes to sleep, and control shifts
2051  * back to the main thread.  In this way, unnecessary standins are put
2052  * back to sleep.  These sleeping standins are stored on the
2053  * CthSleepingStandins list.
2055  ***************************************************************************/
2057 CpvStaticDeclare(CthThread, CthMainThread);
2058 CpvStaticDeclare(CthThread, CthSchedulingThread);
2059 CpvStaticDeclare(CthThread, CthSleepingStandins);
2060 CpvDeclare(int      , CthResumeNormalThreadIdx);
2061 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
2063 #if CMK_OMP
2064 CpvDeclare (int, CthResumeStealableThreadIdx);
2065 CpvDeclare (int, CthResumeSuspendedStealableThreadIdx);
2066 #endif
2068 void CthStandinCode(void *arg)
2070   CsdScheduler(-1);
2073 /* this fix the function pointer for thread migration and pup */
2074 static CthThread CthSuspendNormalThread(void)
2076   return CpvAccess(CthSchedulingThread);
2079 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2080 CthThread CthSuspendSchedulingThread(void);
2082 CthThread CthSuspendSchedulingThread(void)
2084   CthThread succ = CpvAccess(CthSleepingStandins);
2086   if (succ) {
2087     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2088   } else {
2089     succ = CthCreate(CthStandinCode, 0, 256000);
2090     CthSetStrategy(succ,
2091                    CthEnqueueSchedulingThread,
2092                    CthSuspendSchedulingThread);
2093   }
2094   
2095   CpvAccess(CthSchedulingThread) = succ;
2096   return succ;
2099 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2100 CMI_EXTERNC
2101 void CthResumeNormalThread(CthThreadToken* token)
2103   CthThread t = token->thread;
2105   /* BIGSIM_OOC DEBUGGING
2106   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2107   */
2109   if(t == NULL){
2110     free(token);
2111     return;
2112   }
2113 #if CMK_TRACE_ENABLED
2114 #if ! CMK_TRACE_IN_CHARM
2115   if(CpvAccess(traceOn))
2116     CthTraceResume(t);
2117 /*    if(CpvAccess(_traceCoreOn)) 
2118                 resumeTraceCore();*/
2119 #endif
2120 #endif
2121   
2122   /* BIGSIM_OOC DEBUGGING
2123   CmiPrintf("In CthResumeNormalThread:   ");
2124   CthPrintThdMagic(t);
2125   */
2126 #if CMK_OMP
2127   CthSetPrev(t, CthSelf());
2128 #endif
2129   CthResume(t);
2130 #if CMK_OMP
2131   CthScheduledDecrement();
2132   CthSetPrev(CthSelf(), 0);
2133 #endif
2136 void CthResumeSchedulingThread(CthThreadToken  *token)
2138   CthThread t = token->thread;
2139   CthThread me = CthSelf();
2140   if (me == CpvAccess(CthMainThread)) {
2141     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2142   } else {
2143     CthSetNext(me, CpvAccess(CthSleepingStandins));
2144     CpvAccess(CthSleepingStandins) = me;
2145   }
2146   CpvAccess(CthSchedulingThread) = t;
2147 #if CMK_TRACE_ENABLED
2148 #if ! CMK_TRACE_IN_CHARM
2149   if(CpvAccess(traceOn))
2150     CthTraceResume(t);
2151 /*    if(CpvAccess(_traceCoreOn)) 
2152                 resumeTraceCore();*/
2153 #endif
2154 #endif
2155 #if CMK_OMP
2156   CthSetPrev(t, CthSelf());
2157 #endif
2158   CthResume(t);
2159 #if CMK_OMP
2160   CthScheduledDecrement();
2161   CthSetPrev(CthSelf(), 0);
2162 #endif
2165 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2166                                    int pb,unsigned int *prio)
2168   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2169   CsdEnqueueGeneral(token, s, pb, prio);
2172 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2173                                        int pb,unsigned int *prio)
2175   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2176   CsdEnqueueGeneral(token, s, pb, prio);
2179 void CthSetStrategyDefault(CthThread t)
2181   CthSetStrategy(t,
2182                  CthEnqueueNormalThread,
2183                  CthSuspendNormalThread);
2185 #if CMK_OMP
2186 /* Use work-stealing queue for scheduling threads
2187   We use the previous scheduling handlers while we push the message into the work-stealing queue
2189 void CthResumeStealableThread(CthThreadToken *token)
2191   CthThread t = token->thread;
2192   CthSetNext(t, CthSelf());
2193 #if CMK_TRACE_ENABLED
2194 #if ! CMK_TRACE_IN_CHARM
2195   if(CpvAccess(traceOn))
2196     CthTraceResume(t);
2197 #endif
2198 #endif
2199   CthSetPrev(t, CthSelf());
2200   CthResume(t);
2201   CthScheduledDecrement();
2202   CthSetPrev(CthSelf(), 0);
2205 void CthEnqueueStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio) {
2206   CmiSetHandler(token, CpvAccess(CthResumeStealableThreadIdx));
2207   CsdTaskEnqueue((void*)token);
2211 void CthEnqueueSuspendedStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio)
2213   CthThread t = token->thread;
2214   int targetRank = CthGetThreadID(t)->id[2];
2215   CthSetStrategyWorkStealing(t);
2216   if (targetRank == CmiMyRank()) {
2217     CthEnqueueStealableThread(token,s,pb,prio);
2218   }
2219   else {
2220     CmiSetHandler(token, CpvAccess(CthResumeSuspendedStealableThreadIdx));
2221     CmiSuspendedTaskEnqueue(targetRank ,(void*)token);
2222   }
2225 void CthResumeSuspendedStealableThread(CthThreadToken *token) {
2226   CthEnqueueStealableThread(token, 0, 0, NULL);
2229 CthThread CthSuspendStealableThread()
2231   CthThread succ = CthGetNext(CthSelf());
2232 #if CMK_ERROR_CHECKING
2233   if (!succ)
2234     CmiAbort("successor is invalid\n");
2235 #endif
2236   return succ;
2239 void CthSetStrategyWorkStealing(CthThread t)
2241   CthSetStrategy(t, CthEnqueueStealableThread, CthSuspendStealableThread);
2244 void CthSetStrategySuspendedWorkStealing(CthThread t)
2246   CthSetStrategy(t, CthEnqueueSuspendedStealableThread, CthSuspendStealableThread);
2249 #endif
2250 void CthSchedInit()
2252   CpvInitialize(CthThread, CthMainThread);
2253   CpvInitialize(CthThread, CthSchedulingThread);
2254   CpvInitialize(CthThread, CthSleepingStandins);
2255   CpvInitialize(int      , CthResumeNormalThreadIdx);
2256   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2257 #if CMK_OMP
2258   CpvInitialize(int      , CthResumeStealableThreadIdx);
2259   CpvInitialize(int      , CthResumeSuspendedStealableThreadIdx);
2260 #endif
2261   CpvAccess(CthMainThread) = CthSelf();
2262   CpvAccess(CthSchedulingThread) = CthSelf();
2263   CpvAccess(CthSleepingStandins) = 0;
2264   CpvAccess(CthResumeNormalThreadIdx) =
2265     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2266   CpvAccess(CthResumeSchedulingThreadIdx) =
2267     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2268   CthSetStrategy(CthSelf(),
2269                  CthEnqueueSchedulingThread,
2270                  CthSuspendSchedulingThread);
2272 #if CMK_OMP
2273   CpvAccess(CthResumeStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeStealableThread);
2274   CpvAccess(CthResumeSuspendedStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeSuspendedStealableThread);
2275 #endif
2278 void CsdInit(char **argv)
2280   CpvInitialize(Queue, CsdSchedQueue);
2281   CpvInitialize(int,   CsdStopFlag);
2282   CpvInitialize(int,   CsdLocalCounter);
2283   int argCsdLocalMax=CSD_LOCAL_MAX_DEFAULT;
2284   int argmaxset = CmiGetArgIntDesc(argv,"+csdLocalMax",&argCsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages.");
2285   if (CmiMyRank() == 0 ) CsdLocalMax = argCsdLocalMax;
2286   CpvAccess(CsdLocalCounter) = argCsdLocalMax;
2287   CpvAccess(CsdSchedQueue) = CqsCreate();
2288 #if CMK_SMP && CMK_TASKQUEUE
2289   CsvInitialize(unsigned int, idleThreadsCnt);
2290   CsvAccess(idleThreadsCnt) = 0;
2291 #endif
2292    #if CMK_USE_STL_MSGQ
2293    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
2294    #endif
2295    #if CMK_RANDOMIZED_MSGQ
2296    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using randomized msgQ. Priorities will not be respected!\n");
2297    #elif CMK_NO_MSG_PRIOS
2298    if (CmiMyPe() == 0) CmiPrintf("Charm++> Message priorities have been turned off and will not be respected.\n");
2299    #endif
2301 #if CMK_OBJECT_QUEUE_AVAILABLE
2302   CpvInitialize(Queue, CsdObjQueue);
2303   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2304 #endif
2306 #if CMK_NODE_QUEUE_AVAILABLE
2307   CsvInitialize(CmiLock, CsdNodeQueueLock);
2308   CsvInitialize(Queue, CsdNodeQueue);
2309   if (CmiMyRank() ==0) {
2310         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2311         CsvAccess(CsdNodeQueue) = CqsCreate();
2312   }
2313   CmiNodeAllBarrier();
2314 #endif
2316 #if CMK_GRID_QUEUE_AVAILABLE
2317   CsvInitialize(Queue, CsdGridQueue);
2318   CpvAccess(CsdGridQueue) = CqsCreate();
2319 #endif
2321 #if CMK_SMP && CMK_TASKQUEUE
2322   CpvInitialize(Queue, CsdTaskQueue);
2323   CpvInitialize(void *, CmiSuspendedTaskQueue);
2324   CpvAccess(CsdTaskQueue) = (Queue)TaskQueueCreate();
2325 #endif
2326   CpvAccess(CsdStopFlag)  = 0;
2327   CpvInitialize(int, isHelperOn);
2328   CpvAccess(isHelperOn) = 1; // Turn on this bit by default for threads to be used for CkLoop and OpenMP integration
2329   CmiMemoryWriteFence();
2330 #if CMK_SMP && CMK_TASKQUEUE
2331   CmiTaskQueueInit();
2332 #endif
2337 /** 
2338  *  @}
2339  */
2342 /*****************************************************************************
2344  * Vector Send
2346  * The last parameter "system" is by default at zero, in which case the normal
2347  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2348  * CmiAllocced message will also be sent (except for the first one). Useful for
2349  * AllToAll communication, and other system features. If system is 1, also all
2350  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2351  * that.
2353  ****************************************************************************/
2355 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2357 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2358   int total;
2359   char *mesg;
2360 #if CMK_USE_IBVERBS
2361   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2362 #else
2363   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2364 #endif  
2365   CmiSyncSendAndFree(destPE, total, mesg);
2368 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2369   CmiSyncVectorSend(destPE, n, sizes, msgs);
2370   return NULL;
2373 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2374   int i;
2375   CmiSyncVectorSend(destPE, n, sizes, msgs);
2376   for(i=0;i<n;i++) CmiFree(msgs[i]);
2377   CmiFree(sizes);
2378   CmiFree(msgs);
2381 #endif
2383 /*****************************************************************************
2385  * Reduction management
2387  * Only one reduction can be active at a single time in the program.
2388  * Moreover, since every call is supposed to pass in the same arguments,
2389  * having some static variables is not a problem for multithreading.
2390  * 
2391  * Except for "data" and "size", all the other parameters (which are all function
2392  * pointers) MUST be the same in every processor. Having different processors
2393  * pass in different function pointers results in an undefined behaviour.
2394  * 
2395  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2396  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2397  * functions is deleted with the provided function, or it is left intact if no
2398  * function is specified.
2399  * 
2400  * The destination handler for the the first form MUST be embedded into the
2401  * message's header.
2402  * 
2403  * The pup function is used to pup the input data structure into a message to
2404  * be sent to the parent processor. This pup routine is currently used only
2405  * for sizing and packing, NOT unpacking. It MUST be non-null.
2406  * 
2407  * The merge function receives as first parameter the input "data", being it
2408  * a message or a complex data structure (it is up to the user to interpret it
2409  * correctly), and a list of incoming (packed) messages from the children.
2410  * The merge function is responsible to delete "data" if this is no longer needed.
2411  * The system will be in charge of deleting the messages passed in as the second
2412  * argument, and the return value of the function (using the provided deleteFn in
2413  * the second version, or CmiFree in the first). The merge function can return
2414  * data if the merge can be performed in-place. It MUST be non-null.
2415  * 
2416  * At the destination, on processor zero, the final data returned by the last
2417  * merge call will not be deleted by the system, and the CmiHandler function
2418  * will be in charge of its deletion.
2419  * 
2420  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2421  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2422  * particular by the rank zero in each node.
2423  ****************************************************************************/
2425 CpvStaticDeclare(int, CmiReductionMessageHandler);
2426 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2428 CpvStaticDeclare(CmiReduction**, _reduce_info);
2429 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2430 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2431 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2432 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2434 enum {
2435   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2436   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2437   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2438   CmiReductionID_multiplier = 3
2441 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2442   int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2443   CmiReduction *red = CpvAccess(_reduce_info)[index];
2444   if (red != NULL && red->seqID != id) {
2445     /* The table needs to be expanded */
2446     CmiAbort("Too many simultaneous reductions");
2447   }
2448   if (red == NULL || red->numChildren < numChildren) {
2449     CmiReduction *newred;
2450     CmiAssert(red == NULL || red->localContributed == 0);
2451     if (numChildren == 0) numChildren = 4;
2452     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2453     newred->numRemoteReceived = 0;
2454     newred->localContributed = 0;
2455     newred->seqID = id;
2456     if (red != NULL) {
2457       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2458       free(red);
2459     }
2460     red = newred;
2461     red->numChildren = numChildren;
2462     red->remoteData = (char**)(red+1);
2463     CpvAccess(_reduce_info)[index] = red;
2464   }
2465   return red;
2468 CmiReduction* CmiGetReduction(int id) {
2469   return CmiGetReductionCreate(id, 0);
2472 void CmiClearReduction(int id) {
2473   int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2474   free(CpvAccess(_reduce_info)[index]);
2475   CpvAccess(_reduce_info)[index] = NULL;
2478 CmiReduction* CmiGetNextReduction(short int numChildren) {
2479   int id = CpvAccess(_reduce_seqID_global);
2480   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2481   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2482   return CmiGetReductionCreate(id, numChildren);
2485 CmiReductionID CmiGetGlobalReduction(void) {
2486   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2489 CmiReductionID CmiGetDynamicReduction(void) {
2490   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2491   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2494 void CmiReductionHandleDynamicRequest(char *msg) {
2495   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2496   int pe = values[0];
2497   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2498   values[0] = CmiGetDynamicReduction();
2499   CmiSetHandler(msg, CmiGetXHandler(msg));
2500   if (pe >= 0) {
2501     CmiSyncSendAndFree(pe, size, msg);
2502   } else {
2503     CmiSyncBroadcastAllAndFree(size, msg);
2504   }
2507 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2508   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2509   char *msg = (char*)CmiAlloc(size);
2510   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2511   values[0] = pe;
2512   values[1] = dataSize;
2513   CmiSetXHandler(msg, handlerIdx);
2514   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2515   if (CmiMyPe() == 0) {
2516     CmiReductionHandleDynamicRequest(msg);
2517   } else {
2518     /* send the request to processor 0 */
2519     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2520     CmiSyncSendAndFree(0, size, msg);
2521   }
2524 void CmiSendReduce(CmiReduction *red) {
2525   void *mergedData, *msg;
2526   int msg_size;
2527   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2528   mergedData = red->localData;
2529   msg_size = red->localSize;
2530   if (red->numChildren > 0) {
2531     int i, offset=0;
2532     if (red->ops.pupFn != NULL) {
2533       offset = CmiReservedHeaderSize;
2534       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2535     }
2536     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2537     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2538   }
2539   /*CpvAccess(_reduce_num_children) = 0;*/
2540   /*CpvAccess(_reduce_received) = 0;*/
2541   msg = mergedData;
2542   if (red->parent != -1) {
2543     if (red->ops.pupFn != NULL) {
2544       pup_er p = pup_new_sizer();
2545       (red->ops.pupFn)(p, mergedData);
2546       msg_size = pup_size(p) + CmiReservedHeaderSize;
2547       pup_destroy(p);
2548       msg = CmiAlloc(msg_size);
2549       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2550       (red->ops.pupFn)(p, mergedData);
2551       pup_destroy(p);
2552       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2553     }
2554     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2555     CmiSetRedID(msg, red->seqID);
2556     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2557     CmiSyncSendAndFree(red->parent, msg_size, msg);
2558   } else {
2559     (red->ops.destination)(msg);
2560   }
2561   CmiClearReduction(red->seqID);
2564 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2565   return data;
2568 void CmiResetGlobalReduceSeqID(void) {
2569         CpvAccess(_reduce_seqID_global) = 0;
2572 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2573   CmiAssert(red->localContributed == 0);
2574   red->localContributed = 1;
2575   red->localData = msg;
2576   red->localSize = size;
2577   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2578   red->parent = CmiSpanTreeParent(CmiMyPe());
2579   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2580   red->ops.mergeFn = mergeFn;
2581   red->ops.pupFn = NULL;
2582   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2583   CmiSendReduce(red);
2586 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2587                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2588                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2589   CmiAssert(red->localContributed == 0);
2590   red->localContributed = 1;
2591   red->localData = data;
2592   red->localSize = 0;
2593   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2594   red->parent = CmiSpanTreeParent(CmiMyPe());
2595   red->ops.destination = dest;
2596   red->ops.mergeFn = mergeFn;
2597   red->ops.pupFn = pupFn;
2598   red->ops.deleteFn = deleteFn;
2599   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2600   CmiSendReduce(red);
2603 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2604   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2605   CmiGlobalReduce(msg, size, mergeFn, red);
2608 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2609                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2610                      CmiReduceDeleteFn deleteFn) {
2611   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2612   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2615 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2616   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2617   CmiGlobalReduce(msg, size, mergeFn, red);
2620 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2621                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2622                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2623   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2624   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2627 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2628   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2629   int myPos;
2630   CmiAssert(red->localContributed == 0);
2631   red->localContributed = 1;
2632   red->localData = msg;
2633   red->localSize = size;
2634   for (myPos=0; myPos<npes; ++myPos) {
2635     if (pes[myPos] == CmiMyPe()) break;
2636   }
2637   CmiAssert(myPos < npes);
2638   red->numChildren = npes - (myPos << 2) - 1;
2639   if (red->numChildren > 4) red->numChildren = 4;
2640   if (red->numChildren < 0) red->numChildren = 0;
2641   if (myPos == 0) red->parent = -1;
2642   else red->parent = pes[(myPos - 1) >> 2];
2643   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2644   red->ops.mergeFn = mergeFn;
2645   red->ops.pupFn = NULL;
2646   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2647   CmiSendReduce(red);
2650 void CmiListReduceStruct(int npes, int *pes,
2651                      void *data, CmiReducePupFn pupFn,
2652                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2653                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2654   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2655   int myPos;
2656   CmiAssert(red->localContributed == 0);
2657   red->localContributed = 1;
2658   red->localData = data;
2659   red->localSize = 0;
2660   for (myPos=0; myPos<npes; ++myPos) {
2661     if (pes[myPos] == CmiMyPe()) break;
2662   }
2663   CmiAssert(myPos < npes);
2664   red->numChildren = npes - (myPos << 2) - 1;
2665   if (red->numChildren > 4) red->numChildren = 4;
2666   if (red->numChildren < 0) red->numChildren = 0;
2667   red->parent = (myPos - 1) >> 2;
2668   if (myPos == 0) red->parent = -1;
2669   red->ops.destination = dest;
2670   red->ops.mergeFn = mergeFn;
2671   red->ops.pupFn = pupFn;
2672   red->ops.deleteFn = deleteFn;
2673   CmiSendReduce(red);
2676 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2677   int npes, *pes;
2678   CmiLookupGroup(grp, &npes, &pes);
2679   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2682 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2683                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2684                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2685   int npes, *pes;
2686   CmiLookupGroup(grp, &npes, &pes);
2687   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2690 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2691   CmiAbort("Feel free to implement CmiNodeReduce...");
2692   /*
2693   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2694   CpvAccess(_reduce_data) = data;
2695   CpvAccess(_reduce_data_size) = size;
2696   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2697   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2698   _reduce_pupFn = NULL;
2699   _reduce_mergeFn = mergeFn;
2700   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2701   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2702   */
2704 #if 0
2705 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2706   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2707       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2709 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2710   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2712 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2713   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2714       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2716 #endif
2718 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2719                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2720                          CmiReduceDeleteFn deleteFn) {
2721   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2723   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2724   CpvAccess(_reduce_data) = data;
2725   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2726   _reduce_destination = dest;
2727   _reduce_pupFn = pupFn;
2728   _reduce_mergeFn = mergeFn;
2729   _reduce_deleteFn = deleteFn;
2730   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2731   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2732   */
2735 void CmiHandleReductionMessage(void *msg) {
2736   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2737   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2738   red->remoteData[red->numRemoteReceived++] = (char *)msg;
2739   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2740   CmiSendReduce(red);
2742   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2743   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2744   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2747 void CmiReductionsInit(void) {
2748   int i;
2749   CpvInitialize(int, CmiReductionMessageHandler);
2750   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2751   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2752   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2753   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2754   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2755   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2756   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2757   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2758   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2759   CpvInitialize(int, _reduce_info_size);
2760   CpvAccess(_reduce_info_size) = 4;
2761   CpvInitialize(CmiReduction**, _reduce_info);
2762   CpvAccess(_reduce_info) = (CmiReduction **)malloc(16*sizeof(CmiReduction*));
2763   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2766 /*****************************************************************************
2768  * Multicast groups
2770  ****************************************************************************/
2772 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2774 typedef struct GroupDef_s
2776   union {
2777     char core[CmiMsgHeaderSizeBytes];
2778     struct GroupDef_s *next;
2779   } core;
2780   CmiGroup group;
2781   int npes;
2782   int pes[1];
2784 *GroupDef;
2786 #define GROUPTAB_SIZE 101
2788 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2789 CpvStaticDeclare(int, CmiGroupCounter);
2790 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2792 void CmiGroupHandler(GroupDef def)
2794   /* receive group definition, insert into group table */
2795   GroupDef *table = CpvAccess(CmiGroupTable);
2796   unsigned int hashval, bucket;
2797   hashval = (def->group.id ^ def->group.pe);
2798   bucket = hashval % GROUPTAB_SIZE;
2799   def->core.next = table[bucket];
2800   table[bucket] = def;
2803 CmiGroup CmiEstablishGroup(int npes, int *pes)
2805   /* build new group definition, broadcast it */
2806   CmiGroup grp; GroupDef def; int len, i;
2807   grp.id = CpvAccess(CmiGroupCounter)++;
2808   grp.pe = CmiMyPe();
2809   len = sizeof(struct GroupDef_s)+(npes*sizeof(int));
2810   def = (GroupDef)CmiAlloc(len);
2811   def->group = grp;
2812   def->npes = npes;
2813   for (i=0; i<npes; i++)
2814     def->pes[i] = pes[i];
2815   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2816   CmiSyncBroadcastAllAndFree(len, def);
2817   return grp;
2820 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2822   unsigned int hashval, bucket;  GroupDef def;
2823   GroupDef *table = CpvAccess(CmiGroupTable);
2824   hashval = (grp.id ^ grp.pe);
2825   bucket = hashval % GROUPTAB_SIZE;
2826   for (def=table[bucket]; def; def=def->core.next) {
2827     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2828       *npes = def->npes;
2829       *pes = def->pes;
2830       return;
2831     }
2832   }
2833   *npes = 0; *pes = 0;
2836 void CmiGroupInit(void)
2838   CpvInitialize(int, CmiGroupHandlerIndex);
2839   CpvInitialize(int, CmiGroupCounter);
2840   CpvInitialize(GroupDef *, CmiGroupTable);
2841   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2842   CpvAccess(CmiGroupCounter) = 0;
2843   CpvAccess(CmiGroupTable) =
2844     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2845   if (CpvAccess(CmiGroupTable) == 0)
2846     CmiAbort("Memory Allocation Error");
2849 #endif
2851 /*****************************************************************************
2853  * Common List-Cast and Multicast Code
2855  ****************************************************************************/
2857 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2859 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2861   int i;
2862 #if CMK_BROADCAST_USE_CMIREFERENCE
2863   for(i=0;i<npes;i++) {
2864     if (pes[i] == CmiMyPe())
2865       CmiSyncSend(pes[i], len, msg);
2866     else {
2867       CmiReference(msg);
2868       CmiSyncSendAndFree(pes[i], len, msg);
2869     }
2870   }
2871 #else
2872   for(i=0;i<npes;i++) {
2873     CmiSyncSend(pes[i], len, msg);
2874   }
2875 #endif
2878 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2880   /* A better asynchronous implementation may be wanted, but at least it works */
2881   CmiSyncListSendFn(npes, pes, len, msg);
2882   return (CmiCommHandle) 0;
2885 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2887 #if CMK_BROADCAST_USE_CMIREFERENCE
2888   if (npes == 1) {
2889     CmiSyncSendAndFree(pes[0], len, msg);
2890     return;
2891   }
2892   CmiSyncListSendFn(npes, pes, len, msg);
2893   CmiFree(msg);
2894 #else
2895   int i;
2896   for(i=0;i<npes-1;i++) {
2897     CmiSyncSend(pes[i], len, msg);
2898   }
2899   if (npes>0)
2900     CmiSyncSendAndFree(pes[npes-1], len, msg);
2901   else 
2902     CmiFree(msg);
2903 #endif
2906 #endif
2908 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2910 typedef struct MultiMsg_s
2912   char core[CmiMsgHeaderSizeBytes];
2913   CmiGroup group;
2914   int pos;
2915   int origlen;
2917 *MultiMsg;
2920 CpvDeclare(int, CmiMulticastHandlerIndex);
2922 void CmiMulticastDeliver(MultiMsg msg)
2924   int npes, *pes; int olen, nlen, pos, child1, child2;
2925   olen = msg->origlen;
2926   nlen = olen + sizeof(struct MultiMsg_s);
2927   CmiLookupGroup(msg->group, &npes, &pes);
2928   if (pes==0) {
2929     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2930     return;
2931   }
2932   if (npes==0) {
2933     CmiFree(msg);
2934     return;
2935   }
2936   if (msg->pos == -1) {
2937     msg->pos=0;
2938     CmiSyncSendAndFree(pes[0], nlen, msg);
2939     return;
2940   }
2941   pos = msg->pos;
2942   child1 = ((pos+1)<<1);
2943   child2 = child1-1;
2944   if (child1 < npes) {
2945     msg->pos = child1;
2946     CmiSyncSend(pes[child1], nlen, msg);
2947   }
2948   if (child2 < npes) {
2949     msg->pos = child2;
2950     CmiSyncSend(pes[child2], nlen, msg);
2951   }
2952   if(olen < sizeof(struct MultiMsg_s)) {
2953     memcpy(msg, msg+1, olen);
2954   } else {
2955     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg_s));
2956   }
2957   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2960 void CmiMulticastHandler(MultiMsg msg)
2962   CmiMulticastDeliver(msg);
2965 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2967   int newlen; MultiMsg newmsg;
2968   newlen = len + sizeof(struct MultiMsg_s);
2969   newmsg = (MultiMsg)CmiAlloc(newlen);
2970   if(len < sizeof(struct MultiMsg_s)) {
2971     memcpy(newmsg+1, msg, len);
2972   } else {
2973     memcpy(newmsg+1, msg+sizeof(struct MultiMsg_s), len-sizeof(struct MultiMsg_s));
2974     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg_s));
2975   }
2976   newmsg->group = grp;
2977   newmsg->origlen = len;
2978   newmsg->pos = -1;
2979   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2980   CmiMulticastDeliver(newmsg);
2983 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2985   CmiSyncMulticastFn(grp, len, msg);
2986   CmiFree(msg);
2989 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2991   CmiError("Async Multicast not implemented.");
2992   return (CmiCommHandle) 0;
2995 void CmiMulticastInit(void)
2997   CpvInitialize(int, CmiMulticastHandlerIndex);
2998   CpvAccess(CmiMulticastHandlerIndex) =
2999     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
3002 #else
3003 extern void CmiMulticastInit(void);
3004 #endif
3006 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3007 extern void *arena_malloc(int size);
3008 extern void arena_free(void *blockPtr);
3009 #endif
3011 /***************************************************************************
3013  * Memory Allocation routines 
3015  * A block of memory can consist of multiple chunks.  Each chunk has
3016  * a sizefield and a refcount.  The first chunk's refcount is a reference
3017  * count.  That's how many CmiFrees it takes to free the message.
3018  * Subsequent chunks have a refcount which is less than zero.  This is
3019  * the offset back to the start of the first chunk.
3021  * Each chunk has a CmiChunkHeader before the user data, with the fields:
3023  *  size: The user-allocated size of the chunk, in bytes.
3025  *  ref: A magic reference count object. Ordinary blocks start with
3026  *     reference count 1.  When the reference count reaches zero,
3027  *     the block is deleted.  To support nested buffers, the 
3028  *     reference count can also be negative, which means it is 
3029  *     a byte offset to the enclosing buffer's reference count.
3031  ***************************************************************************/
3034 void *CmiAlloc(int size)
3037   char *res;
3039 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3040   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
3041 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3042   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3043 #elif CMK_CONVERSE_UGNI || CMK_OFI
3044   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
3045 #elif CONVERSE_POOL
3046   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
3047 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3048   MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
3049 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3050   res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
3051 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3052   res = (char *) CmiAlloc_ppcq(size+sizeof(CmiChunkHeader));
3053 #else
3054   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3055 #endif
3057   _MEMCHECK(res);
3059 #ifdef MEMMONITOR
3060   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
3061   CpvAccess(AllocCount)++;
3062   CpvAccess(BlocksAllocated)++;
3063   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
3064     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
3065   }
3066   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
3067     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3068             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3069             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3070     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
3071   }
3072   if ((CpvAccess(AllocCount) % 1000) == 0) {
3073     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3074             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3075             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3076   }
3077 #endif
3079   res+=sizeof(CmiChunkHeader);
3080   CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3082   CmiInitMsgHeader(res, size);
3084   SIZEFIELD(res)=size;
3085   REFFIELDSET(res, 1);
3086   return (void *)res;
3089 void *CmiRdmaAlloc(int size) {
3090   char *res;
3092 #if CMK_CONVERSE_UGNI
3093   res = (char *)LrtsRdmaAlloc(size, sizeof(CmiChunkHeader));
3094 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3095   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3096 #elif CMK_OFI
3097   res = (char *)LrtsAlloc(size, sizeof(CmiChunkHeader));
3098 #else
3099   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3100 #endif
3102   _MEMCHECK(res);
3103   res+=sizeof(CmiChunkHeader);
3104   CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3106   CmiInitMsgHeader(res, size);
3107   SIZEFIELD(res)=size;
3108   REFFIELDSET(res, 1);
3109   return (void *)res;
3113 /** Follow the header links out to the most enclosing block */
3114 static void *CmiAllocFindEnclosing(void *blk) {
3115   int refCount = REFFIELD(blk);
3116   while (refCount < 0) {
3117     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
3118     refCount = REFFIELD(blk);
3119   }
3120   return blk;
3123 void CmiInitMsgHeader(void *msg, int size) {
3124 #if CMK_ONESIDED_IMPL
3125   // Set zcMsgType in the converse message header to CMK_REG_NO_ZC_MSG
3126   if(size >= CmiMsgHeaderSizeBytes)
3127     CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
3128 #endif
3131 int CmiGetReference(void *blk)
3133   return REFFIELD(CmiAllocFindEnclosing(blk));
3136 /** Increment the reference count for this block's owner.
3137     This call must be matched by an equivalent CmiFree. */
3138 void CmiReference(void *blk)
3140   REFFIELDINC(CmiAllocFindEnclosing(blk));
3143 /** Return the size of the user portion of this block. */
3144 int CmiSize(void *blk)
3146   return SIZEFIELD(blk);
3149 /** Decrement the reference count for this block. */
3150 void CmiFree(void *blk)
3152   void *parentBlk=CmiAllocFindEnclosing(blk);
3153   int refCount=REFFIELDDEC(parentBlk);
3154 #if CMK_ERROR_CHECKING
3155   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3156     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
3157 #endif
3158   if(refCount==1) { /* This was the last reference to the block-- free it */
3159 #ifdef MEMMONITOR
3160     int size=SIZEFIELD(parentBlk);
3161     if (size > 1000000000) /* Absurdly large size field-- warning */
3162       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3163     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3164     CpvAccess(BlocksAllocated)--;
3165 #endif
3167 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3168     arena_free(BLKSTART(parentBlk));
3169 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3170     /* is this message the head of a MultipleSend that we received?
3171        Then the parts with INFIMULTIPOOL have metadata which must be 
3172        unregistered and freed.  */
3173 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
3174     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
3175       {
3176         infi_freeMultipleSend(parentBlk);
3177       }
3178 #endif
3179     infi_CmiFree(BLKSTART(parentBlk));
3180 #elif CMK_CONVERSE_UGNI || CMK_OFI
3181     LrtsFree(BLKSTART(parentBlk));
3182 #elif CONVERSE_POOL
3183     CmiPoolFree(BLKSTART(parentBlk));
3184 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3185     MPI_Free_mem(parentBlk);
3186 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3187     CmiFree_bgq(BLKSTART(parentBlk));
3188 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3189     CmiFree_ppcq(BLKSTART(parentBlk));
3190 #else
3191     free_nomigrate(BLKSTART(parentBlk));
3192 #endif
3193   }
3196 void CmiRdmaFree(void *blk)
3198   void *parentBlk=CmiAllocFindEnclosing(blk);
3199   int refCount=REFFIELDDEC(parentBlk);
3200 #if CMK_ERROR_CHECKING
3201   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3202     CmiAbort("CmiRdmaFree reference count was zero-- is this a duplicate free?");
3203 #endif
3204   if(refCount==1) { /* This was the last reference to the block-- free it */
3205 #ifdef MEMMONITOR
3206     int size=SIZEFIELD(parentBlk);
3207     if (size > 1000000000) /* Absurdly large size field-- warning */
3208       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3209     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3210     CpvAccess(BlocksAllocated)--;
3211 #endif
3213 #if CMK_CONVERSE_UGNI
3214     LrtsRdmaFree(BLKSTART(parentBlk));
3215 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3216     infi_CmiFree(BLKSTART(parentBlk));
3217 #elif CMK_OFI
3218     LrtsFree(BLKSTART(parentBlk));
3219 #else
3220     free_nomigrate(BLKSTART(parentBlk));
3221 #endif
3222   }
3226 /***************************************************************************
3228  * Temporary-memory Allocation routines 
3230  *  This buffer augments the storage available on the regular machine stack
3231  * for fairly large temporary buffers, which allows us to use smaller machine
3232  * stacks.
3234  ***************************************************************************/
3236 #define CMI_TMP_BUF_MAX 16*1024 /* Allow this much temporary storage. */
3238 typedef struct {
3239   char *buf; /* Start of temporary buffer */
3240   int cur; /* First unused location in temporary buffer */
3241   int max; /* Length of temporary buffer */
3242 } CmiTmpBuf_t;
3243 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
3245 static void CmiTmpSetup(CmiTmpBuf_t *b) {
3246   b->buf=(char *)malloc(CMI_TMP_BUF_MAX);
3247   b->cur=0;
3248   b->max=CMI_TMP_BUF_MAX;
3251 void *CmiTmpAlloc(int size) {
3252   if (!CpvInitialized(CmiTmpBuf)) {
3253     return malloc(size);
3254   }
3255   else { /* regular case */
3256     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3257     void *t;
3258     if (b->cur+size>b->max) {
3259       if (b->max==0) /* We're just uninitialized */
3260         CmiTmpSetup(b);
3261       else /* We're really out of space! */
3262         return malloc(size);
3263     }
3264     t=b->buf+b->cur;
3265     b->cur+=size;
3266     return t;
3267   }
3269 void CmiTmpFree(void *t) {
3270   if (!CpvInitialized(CmiTmpBuf)) {
3271     free(t);
3272   }
3273   else { /* regular case */
3274     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3275     /* t should point into our temporary buffer: figure out where */
3276     int cur=((const char *)t)-b->buf;
3277     if (cur<0 || cur>b->max) {
3278       free(t);
3279     } else {
3280       b->cur=cur;
3281     }
3282   }
3285 void CmiTmpInit(char **argv) {
3286   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3287   /* Set up this processor's temporary buffer */
3288   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3291 /******************************************************************************
3293   Cross-platform directory creation
3295   ****************************************************************************/
3296 #ifdef _WIN32
3297 /* Windows directory creation: */
3298 #include <windows.h>
3300 void CmiMkdir(const char *dirName) {
3301         CreateDirectory(dirName,NULL);
3304 int CmiGetPageSize(void)
3306   SYSTEM_INFO system_info;
3307   GetSystemInfo(&system_info);
3308   return system_info.dwPageSize;
3310 #else
3311 /* UNIX directory creation */
3312 #include <unistd.h> 
3313 #include <sys/stat.h> /* from "mkdir" man page */
3314 #include <sys/types.h>
3316 void CmiMkdir(const char *dirName) {
3317         mkdir(dirName,0777);
3320 int CmiGetPageSize(void)
3322 #if CMK_HAS_GETPAGESIZE
3323   return getpagesize();
3324 #else
3325   return CMK_MEMORY_PAGESIZE;
3326 #endif
3329 #endif
3332 /******************************************************************************
3334   Multiple Send function                               
3336   ****************************************************************************/
3342 /****************************************************************************
3343 * DESCRIPTION : This function call allows the user to send multiple messages
3344 *               from one processor to another, all intended for differnet 
3345 *               handlers.
3347 *               Parameters :
3349 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3351 ****************************************************************************/
3352 /* Round up message size to the message granularity. 
3353    Does this by adding, then truncating.
3355 static int roundUpSize(unsigned int s) {
3356   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3358 /* Return the amount of message padding required for a message
3359    with this many user bytes. 
3360  */
3361 static int paddingSize(unsigned int s) {
3362   return roundUpSize(s)-s;
3365 /* Message header for a bundle of multiple-sent messages */
3366 typedef struct {
3367   char convHeader[CmiMsgHeaderSizeBytes];
3368   int nMessages; /* Number of distinct messages bundled below. */
3369   double pad; /* To align the first message, which follows this header */
3370 } CmiMultipleSendHeader;
3372 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3373 /* given a pointer to a multisend message clean up the metadata */
3375 void infi_freeMultipleSend(void *msgWhole)
3377   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3378   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3379   int offset=sizeof(CmiMultipleSendHeader);
3380   int m;
3381   void *thisMsg=NULL;
3382   if (pad != 1234567.89) return;
3383   for(m=0;m<len;m++)
3384     {
3385       /*unreg meta, free meta, move the ptr */
3386       /* note these weird little things are not pooled */
3387       /* do NOT free the message here, we are only a part of this buffer*/
3388       infiCmiChunkHeader *ch = (infiCmiChunkHeader *)((char *)msgWhole + offset);
3389       char *msg = (char *)msgWhole + offset + sizeof(infiCmiChunkHeader);
3390       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3391       infi_unregAndFreeMeta(ch->metaData);
3392       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3393     }
3395 #endif
3398 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3400   CmiMultipleSendHeader header;
3401   int m; /* Outgoing message */
3403   CmiInitMsgHeader(header.convHeader, sizeof(CmiMultipleSendHeader));
3404 #if CMK_USE_IBVERBS
3405   infiCmiChunkHeader *msgHdr;
3406 #else
3407   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3408 #endif
3409         
3410   double pad = 0; /* padding required */
3411   int vecLen; /* Number of pieces in outgoing message vector */
3412   int *vecSizes; /* Sizes of each piece we're sending out. */
3413   char **vecPtrs; /* Pointers to each piece we're sending out. */
3414   int vec; /* Entry we're currently filling out in above array */
3415         
3416 #if CMK_USE_IBVERBS
3417   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3418 #else
3419   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3420 #endif
3421         
3422   /* Allocate memory for the outgoing vector*/
3423   vecLen=1+3*len; /* Header and 3 parts per message */
3424   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3425   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3426   vec=0;
3427   
3428   /* Build the header */
3429   header.nMessages=len;
3430   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3431   header.pad = 1234567.89;
3432 #if CMK_IMMEDIATE_MSG
3433   if (immed) CmiBecomeImmediate(&header);
3434 #endif
3435   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3436   vec++;
3438   /* Build an entry for each message: 
3439          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3440   */
3441   for (m=0;m<len;m++) {
3442 #if CMK_USE_IBVERBS
3443     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3444     msgHdr[m].chunkHeader.setRef(0); /* Reference count will be filled out on receive side */
3445     msgHdr[m].metaData=NULL;
3446 #else
3447     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3448     msgHdr[m].setRef(0); /* Reference count will be filled out on receive side */
3449 #endif          
3450     
3451     /* First send the message's CmiChunkHeader (for use on receive side) */
3452 #if CMK_USE_IBVERBS
3453     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3454 #else
3455     vecSizes[vec]=sizeof(CmiChunkHeader); 
3456 #endif          
3457                 vecPtrs[vec]=(char *)&msgHdr[m];
3458     vec++;
3459     
3460     /* Now send the actual message data */
3461     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3462     vec++;
3463     
3464     /* Now send padding to align the next message on a double-boundary */
3465     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3466     vec++;
3467   }
3468   CmiAssert(vec==vecLen);
3469   
3470   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3471   
3472   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3473   CmiTmpFree(vecSizes);
3474   CmiTmpFree(msgHdr);
3477 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3479   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3482 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3484   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3487 /****************************************************************************
3488 * DESCRIPTION : This function initializes the main handler required for the
3489 *               CmiMultipleSend() function to work. 
3490 *               
3491 *               This function should be called once in any Converse program
3492 *               that uses CmiMultipleSend()
3494 ****************************************************************************/
3496 static void CmiMultiMsgHandler(char *msgWhole);
3498 void CmiInitMultipleSend(void)
3500   CpvInitialize(int,CmiMainHandlerIDP); 
3501   CpvAccess(CmiMainHandlerIDP) =
3502     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3505 /****************************************************************************
3506 * DESCRIPTION : This function is the main handler that splits up the messages
3507 *               CmiMultipleSend() pastes together. 
3509 ****************************************************************************/
3511 static void CmiMultiMsgHandler(char *msgWhole)
3513   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3514   int offset=sizeof(CmiMultipleSendHeader);
3515   int m;
3516   for (m=0;m<len;m++) {
3517 #if CMK_USE_IBVERBS
3518     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3519     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3520     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3521     ch->chunkHeader.setRef(msgWhole-msg);
3522     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3523 #else
3524     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3525     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3526     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3527     ch->setRef(msgWhole-msg);
3528 #endif          
3529     /* Link new message to owner via a negative ref pointer */
3530     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3531     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3532 #if CMK_USE_IBVERBS
3533     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3534 #else
3535     offset+= sizeof(CmiChunkHeader) + msgSize;
3536 #endif          
3537   }
3538   /* Release our reference to the whole message.  The message will
3539      only actually be deleted once all its sub-messages are free'd as well. */
3540   CmiFree(msgWhole);
3543 /****************************************************************************
3544 * Hypercube broadcast message passing.
3545 ****************************************************************************/
3547 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3548   int num_pes = 0;
3549   for ( ; k>=0; --k) {
3550     /* add the processor destination at level k if it exist */
3551     dest_pes[num_pes] = mype ^ (1<<k);
3552     if (dest_pes[num_pes] >= total_pes) {
3553       /* find the first proc in the other part of the current dimention */
3554       dest_pes[num_pes] &= (~0u)<<k;
3555       /* if the first proc there is over CmiNumPes() then there is no other
3556          dimension, otherwise if it is valid compute my correspondent in such
3557          a way to minimize the load for every processor */
3558       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((~0u)<<k))) % (total_pes - dest_pes[num_pes]);
3559       }
3560     if (dest_pes[num_pes] < total_pes) {
3561       /* if the destination is in the acceptable range increment num_pes */
3562       ++num_pes;
3563     }
3564   }
3565   return num_pes;
3569 /****************************************************************************
3570 * DESCRIPTION : This function initializes the main handler required for the
3571 *               Immediate message
3572 *               
3573 *               This function should be called once in any Converse program
3575 ****************************************************************************/
3577 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3578 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3580 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3582 /* xdl is the real handler */
3583 static void CmiImmediateMsgHandler(char *msg)
3585   CmiSetHandler(msg, CmiGetXHandler(msg));
3586   CmiHandleMessage(msg);
3589 void CmiInitImmediateMsg(void)
3591   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3592   CpvAccess(CmiImmediateMsgHandlerIdx) =
3593     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3596 /*#if !CMK_IMMEDIATE_MSG
3597 #if !CMK_MACHINE_PROGRESS_DEFINED
3598 void CmiProbeImmediateMsg()
3601 #endif
3602 #endif*/
3604 /******** Idle timeout module (+idletimeout=30) *********/
3606 typedef struct {
3607   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3608   int is_idle;/*Boolean currently-idle flag*/
3609   int call_count;/*Number of timeout calls currently in flight*/
3610 } cmi_cpu_idlerec;
3612 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3614   rec->call_count--;
3615   if(rec->call_count==0 && rec->is_idle==1) {
3616     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3617     CmiAbort("Exiting.\n");
3618   }
3620 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3622   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3623   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3624   rec->is_idle = 1;
3626 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3628   rec->is_idle = 0;
3630 static void CIdleTimeoutInit(char **argv)
3632   int idle_timeout=0; /*Seconds to wait*/
3633   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3634   if(idle_timeout != 0) {
3635     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3636     _MEMCHECK(rec);
3637     rec->idle_timeout=idle_timeout*1000;
3638     rec->is_idle=0;
3639     rec->call_count=0;
3640     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3641     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3642   }
3645 /*****************************************************************************
3647  * Converse Initialization
3649  *****************************************************************************/
3651 CMI_EXTERNC void CrnInit(void);
3652 CMI_EXTERNC void CmiIsomallocInit(char **argv);
3653 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3654 void CmiIOInit(char **argv);
3655 #endif
3657 /* defined in cpuaffinity.C */
3658 CMI_EXTERNC void CmiInitCPUAffinityUtil(void);
3660 static void CmiProcessPriority(char **argv)
3662   int dummy, nicelevel=-100;      /* process priority */
3663   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3664   /* ignore others */
3665   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3666   /* call setpriority once on each process to set process's priority */
3667   if (CmiMyRank() == 0 && nicelevel != -100)  {
3668 #ifndef _WIN32
3669     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3670       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3671       perror("setpriority");
3672       CmiAbort("setpriority failed.");
3673     }
3674     else
3675       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3676 #else
3677     HANDLE hProcess = GetCurrentProcess();
3678     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3679     const char *prio_str = "NORMAL_PRIORITY_CLASS";
3680     BOOL status;
3681     /*
3682        <-20:      real time
3683        -20--10:   high 
3684        -10-0:     above normal
3685        0:         normal
3686        0-10:      below normal
3687        10-:       idle
3688     */
3689     if (0) ;
3690 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3691     else if (nicelevel<10 && nicelevel>0) {
3692       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3693       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3694     }
3695 #endif
3696     else if (nicelevel>0) {
3697       dwPriorityClass = IDLE_PRIORITY_CLASS;
3698       prio_str = "IDLE_PRIORITY_CLASS";
3699     }
3700     else if (nicelevel<=-20) {
3701       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3702       prio_str = "REALTIME_PRIORITY_CLASS";
3703     }
3704 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3705     else if (nicelevel>-10 && nicelevel<0) {
3706       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3707       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3708     }
3709 #endif
3710     else if (nicelevel<0) {
3711       dwPriorityClass = HIGH_PRIORITY_CLASS;
3712       prio_str = "HIGH_PRIORITY_CLASS";
3713     }
3714     status = SetPriorityClass(hProcess, dwPriorityClass);
3715     if (!status)  {
3716         int err=GetLastError();
3717         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3718         CmiAbort("SetPriorityClass failed.");
3719     }
3720     else
3721       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3722 #endif
3723   }
3726 void CommunicationServerInit(void)
3728 #if CMK_IMMEDIATE_MSG
3729 #if CMI_QD
3730   CQdCpvInit();
3731 #endif
3732   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3733 #endif
3737 static int testEndian(void)
3739         int test=0x1c;
3740         unsigned char *c=(unsigned char *)&test;
3741         if (c[sizeof(int)-1]==0x1c)
3742                 /* Macintosh and most workstations are big-endian */
3743                 return 1;   /* Big-endian machine */
3744         if (c[0]==0x1c)
3745                 /* Intel x86 PC's, and DEC VAX are little-endian */
3746                 return 0;  /* Little-endian machine */
3747         return -2;  /*Unknown integer type */
3750 int CmiEndianness(void)
3752   static int _cmi_endianness = -1;
3753   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3754   CmiAssert(_cmi_endianness != -2);
3755   return  _cmi_endianness;
3758 #if CMK_USE_TSAN
3759 /* This fixes bug #713, which is caused by tsan deadlocking inside
3760  * a 'write' syscall inside a mutex. */
3761 static void checkTSanOptions(void)
3763   char *env = getenv("TSAN_OPTIONS");
3765   if (!env ||
3766       !strstr(env, "log_path=") ||
3767       strstr(env, "log_path=stdout") ||
3768       strstr(env, "log_path=stderr")) {
3769     CmiAbort("TSAN output must be redirected to disk.\n"
3770              "Run this program with TSAN_OPTIONS=\"log_path=filename\"");
3771   }
3773 #endif
3775 #if CMK_CCS_AVAILABLE
3776 CMI_EXTERNC_VARIABLE int ccsRunning;
3777 int ccsRunning;
3778 #endif
3780 CMI_EXTERNC_VARIABLE int quietModeRequested;
3781 int quietModeRequested;  // user has requested quiet mode
3782 CMI_EXTERNC_VARIABLE int quietMode;
3783 int quietMode; // quiet mode active (CmiPrintf's are disabled)
3784 CmiSpanningTreeInfo* _topoTree = NULL;
3787   Main Converse initialization routine.  This routine is 
3788   called by the machine file (machine.C) to set up Converse.
3789   It's "Common" because it's shared by all the machine.C files.
3790   
3791   The main task of this routine is to set up all the Cpv's
3792   (message queues, handler tables, etc.) used during main execution.
3793   
3794   On SMP versions, this initialization routine is called by 
3795   *all* processors of a node simultaniously.  It's *also* called
3796   by the communication thread, which is rather strange but needed
3797   for immediate messages.  Each call to this routine expects a 
3798   different copy of the argv arguments, so use CmiCopyArgs(argv).
3799   
3800   Requires:
3801     - A working network layer.
3802     - Working Cpv's and CmiNodeBarrier.
3803     - CthInit to already have been called.  CthInit is called
3804       from the machine layer directly, because some machine layers
3805       (like uth) use Converse threads internally.
3807   Initialization is somewhat subtle, in that various modules
3808   won't work properly until they're initialized.  For example,
3809   nobody can register handlers before calling CmiHandlerInit.
3811 CMI_EXTERNC
3812 void ConverseCommonInit(char **argv)
3814   CpvInitialize(int, _urgentSend);
3815   CpvAccess(_urgentSend) = 0;
3816   CpvInitialize(int,interopExitFlag);
3817   CpvAccess(interopExitFlag) = 0;
3819   CpvInitialize(int,_curRestartPhase);
3820   CpvAccess(_curRestartPhase)=1;
3821   CmiArgInit(argv);
3822   CmiMemoryInit(argv);
3823 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3824   CmiIOInit(argv);
3825 #endif
3826   if (CmiMyPe() == 0)
3827       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3829   CpvInitialize(int, cmiMyPeIdle);
3830   CpvAccess(cmiMyPeIdle) = 0;
3832 #if CONVERSE_POOL
3833   CmiPoolAllocInit(30);  
3834 #endif
3835   CmiTmpInit(argv);
3836   CmiTimerInit(argv);
3837   CstatsInit(argv);
3838   CmiInitCPUAffinityUtil();
3840   CcdModuleInit(argv);
3841   CmiHandlerInit();
3842   CmiReductionsInit();
3843   CIdleTimeoutInit(argv);
3844   
3845 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the netlrts-*-smp and multicore versions*/
3846   if(CmiGetArgFlagDesc(argv, "+CmiSpinOnIdle", "Force the runtime system to spin on message reception when idle, rather than sleeping")) {
3847     if(CmiMyRank() == 0) _Cmi_forceSpinOnIdle = 1;
3848   }
3849   if(CmiGetArgFlagDesc(argv, "+CmiSleepOnIdle", "Force the runtime system to sleep when idle, rather than spinning on message reception")) {
3850     if(CmiMyRank() == 0) _Cmi_sleepOnIdle = 1;
3851   }
3852   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for netlrts-smp-*) ?")){
3853     if (CmiMyPe() == 0) {
3854       CmiPrintf("Charm++> Note: The option +CmiNoProcForComThread has been superseded by +CmiSleepOnIdle\n");
3855     }
3856     if(CmiMyRank() == 0) _Cmi_sleepOnIdle=1;
3857   }
3858   if (_Cmi_sleepOnIdle && _Cmi_forceSpinOnIdle) {
3859     if(CmiMyRank() == 0) CmiAbort("The option +CmiSpinOnIdle is mutually exclusive with the options +CmiSleepOnIdle and +CmiNoProcForComThread");
3860   }
3861 #endif
3862         
3863 #if CMK_TRACE_ENABLED
3864   traceInit(argv);
3865 /*initTraceCore(argv);*/ /* projector */
3866 #endif
3867   CmiProcessPriority(argv);
3869 #if CMK_USE_TSAN
3870   checkTSanOptions();
3871 #endif
3873   CmiPersistentInit();
3874   CmiIsomallocInit(argv);
3875   // Initialize converse handlers for supporting generic Direct Nocopy API
3876   CmiOnesidedDirectInit();
3877   CmiDeliversInit();
3878   CsdInit(argv);
3879 #if CMK_CCS_AVAILABLE
3880   ccsRunning = 0;
3881   CcsInit(argv);
3882 #endif
3883   CpdInit();
3884   CthSchedInit();
3885   CmiGroupInit();
3886   CmiMulticastInit();
3887   CmiInitMultipleSend();
3888 #if CMI_QD
3889   CQdInit();
3890 #endif
3892   CrnInit();
3893   CmiInitImmediateMsg();
3894   CldModuleInit(argv);
3895   
3896 #if CMK_CELL
3897   void CmiInitCell();
3898   CmiInitCell();
3899 #endif
3901   /* main thread is suspendable */
3903   CthSetSuspendable(CthSelf(), 0);
3906 #if CMK_BIGSIM_CHARM
3907    /* have to initialize QD here instead of _initCharm */
3908   initQd(argv);
3909 #endif
3912 CMI_EXTERNC
3913 void ConverseCommonExit(void)
3915   CcsImpl_kill();
3917 #if CMK_TRACE_ENABLED
3918   traceClose();
3919 /*closeTraceCore();*/ /* projector */
3920 #endif
3922 #if CMI_IO_BUFFER_EXPLICIT
3923   CmiFlush(stdout);  /* end of program, always flush */
3924 #endif
3926 #if CMK_CELL
3927   CloseOffloadAPI();
3928 #endif
3930 #if CMK_CUDA
3931   // ensure all PEs have finished GPU work before destructing
3932   if(CmiMyRank() < CmiMyNodeSize()) {
3933     CmiNodeBarrier();
3934   }
3935   if (CmiMyRank() == 0) {
3936     exitHybridAPI();
3937   }
3938 #endif
3939   seedBalancerExit();
3940   EmergencyExit();
3944 #if CMK_CELL != 0
3946 extern void register_accel_spe_funcs(void);
3948 void CmiInitCell(void)
3950   // Create a unique string for each PPE to use for the timing
3951   //   data file's name
3952   char fileNameBuf[64];
3953   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3955   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3956   //CcdCallOnConditionKeep(CcdPERIODIC, 
3957   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3958   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3959       (CcdVoidFn) OffloadAPIProgress, NULL);
3961   // Register accelerated entry methods on the PPE
3962   register_accel_spe_funcs();
3965 #include "cell-api.c"
3967 #endif
3969 /****
3970  * CW Lee - 9/14/2005
3971  * Added a mechanism to allow some control over machines with extremely
3972  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3973  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3974  * coupled with a default setup using unbuffered stdout introduced
3975  * severe overheads (and hence limiting scaling) for applications like 
3976  * NAMD.
3977  */
3978 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3979 void CmiIOInit(char **argv) {
3980   CpvInitialize(int, expIOFlushFlag);
3981 #if CMI_IO_BUFFER_EXPLICIT
3982   /* 
3983      Support for an explicit buffer only makes sense if the machine
3984      layer does not wish to make its own implementation.
3986      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3987      MUST NOT make use of stdout if an explicit buffer is requested.
3989      The setvbuf function may only be used after opening a stream and
3990      before any other operations have been performed on it
3991   */
3992   CpvInitialize(char*, explicitIOBuffer);
3993   CpvInitialize(int, expIOBufferSize);
3994   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3995                         "Explicit IO Buffer Size")) {
3996     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3997   }
3998   if (CpvAccess(expIOBufferSize) <= 0) {
3999     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
4000   }
4001   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
4002                                                 sizeof(char));
4003   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
4004               CpvAccess(expIOBufferSize))) {
4005     CmiAbort("Explicit IO Buffering failed\n");
4006   }
4007 #endif
4008 #if CMI_IO_FLUSH_USER
4009   /* system default to have user control flushing of IO */
4010   /* Now look for user override */
4011   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
4012                                                  "System Controls IO Flush");
4013 #else
4014   /* system default to have system handle IO flushing */
4015   /* Now look for user override */
4016   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
4017                                                 "User Controls IO Flush");
4018 #endif
4020 #endif
4022 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
4024 void CmiPrintf(const char *format, ...)
4026   if (quietMode) return;
4027   CpdSystemEnter();
4028   {
4029   va_list args;
4030   va_start(args,format);
4031   vfprintf(stdout,format, args);
4032   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
4033     CmiFlush(stdout);
4034   }
4035   va_end(args);
4036 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4037   if (CpvAccess(cmiArgDebugFlag)) {
4038     va_start(args,format);
4039     print_node0(format, args);
4040     va_end(args);
4041   }
4042 #endif
4043   }
4044   CpdSystemExit();
4047 void CmiError(const char *format, ...)
4049   CpdSystemEnter();
4050   {
4051   va_list args;
4052   va_start(args,format);
4053   vfprintf(stderr,format, args);
4054   CmiFlush(stderr);  /* stderr is always flushed */
4055   va_end(args);
4056 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4057   if (CpvAccess(cmiArgDebugFlag)) {
4058     va_start(args,format);
4059     print_node0(format, args);
4060     va_end(args);
4061   }
4062 #endif
4063   }
4064   CpdSystemExit();
4067 #endif
4069 void __cmi_assert(const char *errmsg)
4071   CmiError("[%d] %s\n", CmiMyPe(), errmsg);
4072   CmiAbort(errmsg);
4075 char *CmiCopyMsg(char *msg, int len)
4077   char *copy = (char *)CmiAlloc(len);
4078   _MEMCHECK(copy);
4079   memcpy(copy, msg, len);
4080   return copy;
4083 CMI_EXTERNC
4084 unsigned char computeCheckSum(unsigned char *data, int len)
4086   int i;
4087   unsigned char ret = 0;
4088   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
4089   return ret;
4092 /* Flag for bigsim's out-of-core emulation */
4093 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
4094 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
4096 #if !CMK_HAS_LOG2
4097 unsigned int CmiILog2(unsigned int val) {
4098   unsigned int log = 0u;
4099   if ( val != 0u ) {
4100       while ( val > (1u<<log) ) { log++; }
4101   }
4102   return log;
4104 double CmiLog2(double x) {
4105   return log(x)/log(2);
4107 #endif
4109 /* for bigsim */
4110 int CmiMyRank_(void)
4112   return CmiMyRank();
4115 double CmiReadSize(const char *str)
4117     double val;
4118     if (strpbrk(str,"Gg")) {
4119         //sscanf(str, "%llf", &val);
4120         //val = strtod(str, &p);
4121         val = atof(str);
4122         val *= 1024ll*1024*1024;
4123     }
4124     else if (strpbrk(str,"Mm")) {
4125         val = atof(str);
4126         val *= 1024*1024;
4127     }
4128     else if (strpbrk(str,"Kk")) {
4129         val = atof(str);
4130         val *= 1024;
4131     }
4132     else {
4133         val = atof(str);
4134     }
4135     return val;
4138 void CmiSetPeHelpsOtherThreads(int input) {
4139   CpvAccess(isHelperOn) = input;
4140   CmiMemoryWriteFence();
4143 /*@}*/