Fix building AMPI+CUDA
[charm.git] / src / conv-core / convcore.C
blob39fcdf526645818556de45e0058ebfaf15fca789
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 extern const char * const CmiCommitID;
90 #if CMI_QD
91 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 void CcdModuleInit(char **);
110 void CmiMemoryInit(char **);
111 void CldModuleInit(char **);
113 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
114 #include <sys/types.h>
115 #include <sys/time.h>
116 #endif
118 #if CMK_TIMER_USE_TIMES
119 #include <sys/times.h>
120 #include <limits.h>
121 #include <unistd.h>
122 #endif
124 #if CMK_TIMER_USE_GETRUSAGE
125 #include <sys/time.h>
126 #include <sys/resource.h>
127 #endif
129 #if CMK_TIMER_USE_RDTSC
130 #include <string.h>
131 #include <unistd.h>
132 #include <time.h>
133 #include <stdio.h>
134 #include <sys/time.h>
135 #include <sys/resource.h>
136 #endif
138 #ifdef CMK_TIMER_USE_WIN32API
139 #include <stdlib.h>
140 #include <time.h>
141 #include <sys/types.h>
142 #include <sys/timeb.h>
143 #endif
145 #ifdef CMK_HAS_ASCTIME
146 #include <time.h>
147 #endif
149 #include "quiescence.h"
151 #if USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
152 #include <mpi.h>
153 #endif
155 #if CMK_TRACE_ENABLED
156 struct envelope;
157 void traceAddThreadListeners(CthThread tid, struct envelope *env);
158 #endif
160 void seedBalancerExit(void);
161 void EmergencyExit(void);
163 //int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
164 CpvDeclare(int,_curRestartPhase);
165 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
167 int CharmLibInterOperate = 0;
168 CpvCExtern(int,interopExitFlag);
169 CpvDeclare(int,interopExitFlag);
171 CpvStaticDeclare(int, CmiMainHandlerIDP); /* Main handler for _CmiMultipleSend that is run on every node */
173 #if CMK_MEM_CHECKPOINT
174 void (*notify_crash_fn)(int) = NULL;
175 #endif
177 CpvDeclare(char *, _validProcessors);
179 #if CMK_CUDA
180 CpvExtern(int, n_hapi_events);
181 extern "C" void hapiPollEvents();
182 extern "C" void exitHybridAPI();
183 #endif
185 /*****************************************************************************
187  * Unix Stub Functions
189  ****************************************************************************/
191 #ifdef MEMMONITOR
192 typedef unsigned long mmulong;
193 CpvDeclare(mmulong,MemoryUsage);
194 CpvDeclare(mmulong,HiWaterMark);
195 CpvDeclare(mmulong,ReportedHiWaterMark);
196 CpvDeclare(int,AllocCount);
197 CpvDeclare(int,BlocksAllocated);
198 #endif
200 #define MAX_HANDLERS 512
202 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
203 CpvDeclare(int,expIOFlushFlag);
204 #if CMI_IO_BUFFER_EXPLICIT
205 /* 250k not too large depending on how slow terminal IO is */
206 #define DEFAULT_IO_BUFFER_SIZE 250000
207 CpvDeclare(char*,explicitIOBuffer);
208 CpvDeclare(int,expIOBufferSize);
209 #endif
210 #endif
212 #if CMK_NODE_QUEUE_AVAILABLE
213 void  *CmiGetNonLocalNodeQ();
214 #endif
216 CpvDeclare(Queue, CsdSchedQueue);
218 #if CMK_OUT_OF_CORE
219 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
220 CpvDeclare(Queue, CsdPrefetchQueue);
221 pthread_mutex_t prefetchLock;
222 #endif
224 #if CMK_NODE_QUEUE_AVAILABLE
225 CsvDeclare(Queue, CsdNodeQueue);
226 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
227 #endif
228 CpvDeclare(int,   CsdStopFlag);
229 CpvDeclare(int,   CsdLocalCounter);
231 CpvDeclare(int,   _urgentSend);
233 CmiNodeLock _smp_mutex;               /* for smp */
235 #if CMK_USE_IBVERBS | CMK_USE_IBUD
236 void *infi_CmiAlloc(int size);
237 void infi_CmiFree(void *ptr);
238 void infi_freeMultipleSend(void *ptr);
239 void infi_unregAndFreeMeta(void *ch);
240 #endif
242 #if CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
243 void * CmiAlloc_bgq (int     size);
244 void   CmiFree_bgq  (void  * buf);
245 #endif
247 #if CMK_SMP && CMK_PPC_ATOMIC_QUEUE
248 void * CmiAlloc_ppcq (int     size);
249 void   CmiFree_ppcq  (void  * buf);
250 #endif
252 #if CMK_GRID_QUEUE_AVAILABLE
253 CpvDeclare(void *, CkGridObject);
254 CpvDeclare(Queue, CsdGridQueue);
255 #endif
257 #if CMK_CRAYXE || CMK_CRAYXC || CMK_OFI
258 void* LrtsAlloc(int, int);
259 void* LrtsRdmaAlloc(int, int);
260 void  LrtsFree(void*);
261 void  LrtsRdmaFree(void*);
262 #endif
264 CpvStaticDeclare(int, cmiMyPeIdle);
265 #if CMK_SMP && CMK_TASKQUEUE
266 CsvDeclare(unsigned int, idleThreadsCnt);
267 CpvDeclare(Queue, CsdTaskQueue);
268 CpvDeclare(void *, CmiSuspendedTaskQueue);
269 #endif
271 CpvDeclare(int, isHelperOn);
273 extern int CmiMyLocalRank;
274 int    CmiMyLocalRank;        /* local rank only for scalable startup */
276 #if CMK_LOCKLESS_QUEUE
277 /*****************************************************************************
279  * MPSCQueue and MPMCQueue variables
281  *****************************************************************************/
282 int DataNodeSize;
283 int MaxDataNodes;
284 int QueueUpperBound;
285 int DataNodeWrap;
286 int QueueWrap;
287 int messageQueueOverflow;
288 #endif
290 /*****************************************************************************
292  * Command-Line Argument (CLA) parsing routines.
294  *****************************************************************************/
296 static int usageChecked=0; /* set when argv has been searched for a usage request */
297 static int printUsage=0; /* if set, print command-line usage information */
298 static const char *CLAformatString="%20s %10s %s\n";
300 /** This little list of CLA's holds the argument descriptions until it's
301    safe to print them--it's needed because the netlrts- versions don't have 
302    printf until they're pretty well started.
303  */
304 typedef struct {
305         const char *arg; /* Flag name, like "-foo"*/
306         const char *param; /* Argument's parameter type, like "integer" or "none"*/
307         const char *desc; /* Human-readable description of what it does */
308 } CLA;
309 static int CLAlistLen=0;
310 static int CLAlistMax=0;
311 static CLA *CLAlist=NULL;
313 /** Add this CLA */
314 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
315         int i;
316         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
317         if (desc==NULL) return; /*It's an internal argument*/
318         if (usageChecked) { /* Printf should work now */
319                 if (printUsage)
320                         CmiPrintf(CLAformatString,arg,param,desc);
321         }
322         else { /* Printf doesn't work yet-- just add to the list.
323                 This assumes the const char *'s are static references,
324                 which is probably reasonable. */
325                 CLA *temp;
326                 i=CLAlistLen++;
327                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
328                         CLAlistMax=16+2*CLAlistLen;
329                         temp = (CLA *)realloc(CLAlist,sizeof(CLA)*CLAlistMax);
330                         if(temp != NULL) {
331                           CLAlist=temp;
332                         } else {
333                           free(CLAlist);
334                           CmiAbort("Reallocation failed for CLAlist\n");
335                         }
336                 }
337                 CLAlist[i].arg=arg;
338                 CLAlist[i].param=param;
339                 CLAlist[i].desc=desc;
340         }
343 /** Print out the stored list of CLA's */
344 static void CmiPrintCLAs(void) {
345         int i;
346         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
347         CmiPrintf("Converse Machine Command-line Parameters:\n ");
348         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
349         for (i=0;i<CLAlistLen;i++) {
350                 CLA *c=&CLAlist[i];
351                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
352         }
356  * Determines if command-line usage information should be printed--
357  * that is, if a "-?", "-h", or "--help" flag is present.
358  * Must be called after printf is setup.
359  */
360 void CmiArgInit(char **argv) {
361         int i;
362         CmiLock(_smp_mutex);
363         for (i=0;argv[i]!=NULL;i++)
364         {
365                 if (0==strcmp(argv[i],"-?") ||
366                     0==strcmp(argv[i],"-h") ||
367                     0==strcmp(argv[i],"--help")) 
368                 {
369                         printUsage=1;
370                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
371                           Leave it there for user program to see... */
372                         CmiPrintCLAs();
373                 }
374         }
375         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
376                 CLAlistLen=CLAlistMax=0;
377                 free(CLAlist); CLAlist=NULL;
378         }
379         usageChecked=1;
380         CmiUnlock(_smp_mutex);
383 /** Return 1 if we're currently printing command-line usage information. */
384 int CmiArgGivingUsage(void) {
385         return (CmiMyPe()==0) && printUsage;
388 /** Identifies the module that accepts the following command-line parameters */
389 void CmiArgGroup(const char *parentName,const char *groupName) {
390         if (CmiArgGivingUsage()) {
391                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
392                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
393         }
396 /** Count the number of non-NULL arguments in list*/
397 int CmiGetArgc(char **argv)
399         int i=0,argc=0;
400         if (argv)
401         while (argv[i++]!=NULL)
402                 argc++;
403         return argc;
406 /** Return a new, heap-allocated copy of the argv array*/
407 char **CmiCopyArgs(char **argv)
409         int argc=CmiGetArgc(argv);
410         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
411         int i;
412         for (i=0;i<=argc;i++)
413                 ret[i]=argv[i];
414         return ret;
417 /** Delete the first k argument from the given list, shifting
418 all other arguments down by k spaces.
419 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
420 argv={"d",NULL,"c","d",NULL}
422 void CmiDeleteArgs(char **argv,int k)
424         int i=0;
425         while ((argv[i]=argv[i+k])!=NULL)
426                 i++;
429 /** Find the given argment and string option in argv.
430 If the argument is present, set the string option and
431 delete both from argv.  If not present, return NULL.
432 e.g., arg=="-name" returns "bob" from
433 argv=={"a.out","foo","-name","bob","bar"},
434 and sets argv={"a.out","foo","bar"};
436 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
438         int i;
439         CmiAddCLA(arg,"string",desc);
440         for (i=0;argv[i]!=NULL;i++)
441                 if (0==strcmp(argv[i],arg))
442                 {/*We found the argument*/
443                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
444                         *optDest=argv[i+1];
445                         CmiDeleteArgs(&argv[i],2);
446                         return 1;
447                 }
448         return 0;/*Didn't find the argument*/
450 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
451         return CmiGetArgStringDesc(argv,arg,optDest,"");
454 /** Find the given argument and floating-point option in argv.
455 Remove it and return 1; or return 0.
457 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
458         char *number=NULL;
459         CmiAddCLA(arg,"number",desc);
460         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
461         if (1!=sscanf(number,"%lg",optDest)) return 0;
462         return 1;
464 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
465         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
468 /** Find the given argument and integer option in argv.
469 If the argument is present, parse and set the numeric option,
470 delete both from argv, and return 1. If not present, return 0.
471 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
472 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
473 but not argv=={...,"-packsize",...}.
475 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
477         int i;
478         int argLen=strlen(arg);
479         CmiAddCLA(arg,"integer",desc);
480         for (i=0;argv[i]!=NULL;i++)
481                 if (0==strncmp(argv[i],arg,argLen))
482                 {/*We *may* have found the argument*/
483                         const char *opt=NULL;
484                         int nDel=0;
485                         switch(argv[i][argLen]) {
486                         case 0: /* like "-p","27" */
487                                 opt=argv[i+1]; nDel=2; break;
488                         case '=': /* like "-p=27" */
489                                 opt=&argv[i][argLen+1]; nDel=1; break;
490                         case '-':case '+':
491                         case '0':case '1':case '2':case '3':case '4':
492                         case '5':case '6':case '7':case '8':case '9':
493                                 /* like "-p27" */
494                                 opt=&argv[i][argLen]; nDel=1; break;
495                         default:
496                                 continue; /*False alarm-- skip it*/
497                         }
498                         if (opt==NULL) {
499                                 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
500                                                 "but none was provided\n", arg);
501                                 CmiAbort("Bad command-line argument\n");
502                         }
503                         if (sscanf(opt,"%i",optDest)<1) {
504                         /*Bad command line argument-- die*/
505                                 fprintf(stderr,"Cannot parse %s option '%s' "
506                                         "as an integer.\n",arg,opt);
507                                 CmiAbort("Bad command-line argument\n");
508                         }
509                         CmiDeleteArgs(&argv[i],nDel);
510                         return 1;
511                 }
512         return 0;/*Didn't find the argument-- dest is unchanged*/
514 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
515         return CmiGetArgIntDesc(argv,arg,optDest,"");
518 int CmiGetArgLongDesc(char **argv,const char *arg,CmiInt8 *optDest,const char *desc)
520         int i;
521         int argLen=strlen(arg);
522         CmiAddCLA(arg,"integer",desc);
523         for (i=0;argv[i]!=NULL;i++)
524                 if (0==strncmp(argv[i],arg,argLen))
525                 {/*We *may* have found the argument*/
526                         const char *opt=NULL;
527                         int nDel=0;
528                         switch(argv[i][argLen]) {
529                         case 0: /* like "-p","27" */
530                                 opt=argv[i+1]; nDel=2; break;
531                         case '=': /* like "-p=27" */
532                                 opt=&argv[i][argLen+1]; nDel=1; break;
533                         case '-':case '+':
534                         case '0':case '1':case '2':case '3':case '4':
535                         case '5':case '6':case '7':case '8':case '9':
536                                 /* like "-p27" */
537                                 opt=&argv[i][argLen]; nDel=1; break;
538                         default:
539                                 continue; /*False alarm-- skip it*/
540                         }
541                         if (opt==NULL) {
542                                 fprintf(stderr, "Command-line flag '%s' expects a numerical argument, "
543                                                 "but none was provided\n", arg);
544                                 CmiAbort("Bad command-line argument\n");
545                         }
546                         if (sscanf(opt,"%" SCNd64,optDest)<1) {
547                         /*Bad command line argument-- die*/
548                                 fprintf(stderr,"Cannot parse %s option '%s' "
549                                         "as a long integer.\n",arg,opt);
550                                 CmiAbort("Bad command-line argument\n");
551                         }
552                         CmiDeleteArgs(&argv[i],nDel);
553                         return 1;
554                 }
555         return 0;/*Didn't find the argument-- dest is unchanged*/
557 int CmiGetArgLong(char **argv,const char *arg,CmiInt8 *optDest) {
558         return CmiGetArgLongDesc(argv,arg,optDest,"");
561 /** Find the given argument in argv.  If present, delete
562 it and return 1; if not present, return 0.
563 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
564 argv={...,"-foobar",...}.
566 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
568         int i;
569         CmiAddCLA(arg,"",desc);
570         for (i=0;argv[i]!=NULL;i++)
571                 if (0==strcmp(argv[i],arg))
572                 {/*We found the argument*/
573                         CmiDeleteArgs(&argv[i],1);
574                         return 1;
575                 }
576         return 0;/*Didn't find the argument*/
578 int CmiGetArgFlag(char **argv,const char *arg) {
579         return CmiGetArgFlagDesc(argv,arg,"");
582 void CmiDeprecateArgInt(char **argv,const char *arg,const char *desc,const char *warning)
584   int dummy = 0, found = CmiGetArgIntDesc(argv, arg, &dummy, desc);
586   if (found)
587     CmiPrintf(warning);
590 /*****************************************************************************
592  * Stack tracing routines.
594  *****************************************************************************/
595 #include "cmibacktrace.C"
598 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
599 the next parenthesis.  Operates in-place on the character data.
600 or Convert X(Y) to "Y" only, when trimname=1
602 static char *_implTrimParenthesis(char *str, int trimname) {
603   char *lParen=str, *ret=NULL, *rParen=NULL;
604   while (*lParen!='(') {
605     if (*lParen==0) return str; /* No left parenthesis at all. */
606     lParen++;
607   }
608   /* now *lParen=='(', so trim it*/
609   ret=lParen+1;
610   rParen=ret;
611   while (*rParen!=')') {
612     if (*rParen==0) return ret; /* No right parenthesis at all. */
613     rParen++;
614   }
615   /* now *rParen==')', so trim it*/
616   *rParen=trimname?0:' ';
617   return ret;  
621 Return the text description of this trimmed routine name, if 
622 it's a system-generated routine where we should stop printing. 
623 This is probably overkill, but improves the appearance of callbacks.
625 static const char* _implGetBacktraceSys(const char *name) {
626   if (0==strncmp(name,"_call",5)) 
627   { /*it might be something we're interested in*/
628     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
629     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
630   }
631   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
632   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
633   
634   return 0; /*ordinary user routine-- just print normally*/
637 /** Print out the names of these function pointers. */
638 void CmiBacktracePrint(void **retPtrs,int nLevels) {
639   if (nLevels>0) {
640     int i;
641     char **names=CmiBacktraceLookup(retPtrs,nLevels);
642     if (names==NULL) return;
643     CmiPrintf("[%d] Stack Traceback:\n", CmiMyPe());
644     for (i=0;i<nLevels;i++) {
645       if (names[i] == NULL) continue;
646       {
647       const char *trimmed=_implTrimParenthesis(names[i], 0);
648       const char *print=trimmed;
649       const char *sys=_implGetBacktraceSys(print);
650       if (sys) {
651           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
652           break; /*Stop when we hit Charm++ runtime.*/
653       } else {
654           CmiPrintf("  [%d:%d] %s\n",CmiMyPe(),i,print);
655       }
656      }
657     }
658     free(names);
659   }
662 /* Print (to stdout) the names of the functions that have been 
663    called up to this point. nSkip is the number of routines on the
664    top of the stack to *not* print out. */
665 void CmiPrintStackTrace(int nSkip) {
666 #if CMK_USE_BACKTRACE
667         int nLevels=max_stack;
668         void *stackPtrs[max_stack];
669         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
670         CmiBacktracePrint(stackPtrs,nLevels);
671 #endif
674 int CmiIsFortranLibraryCall(void) {
675 #if CMK_USE_BACKTRACE
676   int ret = 0;
677   int nLevels=9;
678   void *stackPtrs[18];
679   CmiBacktraceRecord(stackPtrs,1,&nLevels);
680   if (nLevels>0) {
681     int i;
682     char **names=CmiBacktraceLookup(stackPtrs,nLevels);
683     const char *trimmed;
684     if (names==NULL) return 0;
685     for (i=0;i<nLevels;i++) {
686       if (names[i] == NULL) continue;
687       trimmed=_implTrimParenthesis(names[i], 1);
688       if (strncmp(trimmed, "for__", 5) == 0                /* ifort */
689           || strncmp(trimmed, "_xlf", 4) == 0               /* xlf90 */
690           || strncmp(trimmed, "_xlfBeginIO", 11) == 0 
691           || strncmp(trimmed, "_gfortran_", 10) == 0 
692          )
693           {  /* CmiPrintf("[%d] NAME:%s\n", CmiMyPe(), trimmed); */
694              ret = 1; break; }
695     }
696     free(names);
697   }
698   return ret;
699 #else
700   return 0;
701 #endif
704 /*****************************************************************************
706  * Statistics: currently, the following statistics are not updated by converse.
708  *****************************************************************************/
710 CpvDeclare(int, CstatsMaxChareQueueLength);
711 CpvDeclare(int, CstatsMaxForChareQueueLength);
712 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
713 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
714 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
716 void CstatsInit(char ** argv)
719 #ifdef MEMMONITOR
720   CpvInitialize(mmulong,MemoryUsage);
721   CpvAccess(MemoryUsage) = 0;
722   CpvInitialize(mmulong,HiWaterMark);
723   CpvAccess(HiWaterMark) = 0;
724   CpvInitialize(mmulong,ReportedHiWaterMark);
725   CpvAccess(ReportedHiWaterMark) = 0;
726   CpvInitialize(int,AllocCount);
727   CpvAccess(AllocCount) = 0;
728   CpvInitialize(int,BlocksAllocated);
729   CpvAccess(BlocksAllocated) = 0;
730 #endif
732   CpvInitialize(int, CstatsMaxChareQueueLength);
733   CpvInitialize(int, CstatsMaxForChareQueueLength);
734   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
735   CpvInitialize(int, CstatPrintQueueStatsFlag);
736   CpvInitialize(int, CstatPrintMemStatsFlag);
738   CpvAccess(CstatsMaxChareQueueLength) = 0;
739   CpvAccess(CstatsMaxForChareQueueLength) = 0;
740   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
741   CpvAccess(CstatPrintQueueStatsFlag) = 0;
742   CpvAccess(CstatPrintMemStatsFlag) = 0;
744 #if 0
745   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
746     CpvAccess(CstatPrintMemStatsFlag)=1;
747   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
748     CpvAccess(CstatPrintQueueStatsFlag)=1;
749 #endif
752 int CstatMemory(int i)
754   return 0;
757 int CstatPrintQueueStats(void)
759   return CpvAccess(CstatPrintQueueStatsFlag);
762 int CstatPrintMemStats(void)
764   return CpvAccess(CstatPrintMemStatsFlag);
767 /*****************************************************************************
769  * Cmi handler registration
771  *****************************************************************************/
773 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
774 CpvStaticDeclare(int  , CmiHandlerCount);
775 CpvStaticDeclare(int  , CmiHandlerLocal);
776 CpvStaticDeclare(int  , CmiHandlerGlobal);
777 CpvDeclare(int,         CmiHandlerMax);
779 static void CmiExtendHandlerTable(int atLeastLen) {
780     int max = CpvAccess(CmiHandlerMax);
781     int newmax = (atLeastLen+(atLeastLen>>2)+32);
782     int bytes = max*sizeof(CmiHandlerInfo);
783     int newbytes = newmax*sizeof(CmiHandlerInfo);
784     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
785     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
786     _MEMCHECK(nu);
787     if (tab) {
788       memcpy(nu, tab, bytes);
789     }
790     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
791     free(tab); tab=nu;
792     CpvAccess(CmiHandlerTable) = tab;
793     CpvAccess(CmiHandlerMax) = newmax;
796 void CmiAssignOnce(int* variable, int value) {
797   if (CmiMyRank() == 0) { *variable = value; }
798   CmiNodeAllBarrier();
801 void CmiNumberHandler(int n, CmiHandler h)
803   CmiHandlerInfo *tab;
804   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
805   tab = CpvAccess(CmiHandlerTable);
806   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
807   tab[n].userPtr = 0;
809 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
810   CmiHandlerInfo *tab;
811   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
812   tab = CpvAccess(CmiHandlerTable);
813   tab[n].hdlr = h;
814   tab[n].userPtr=userPtr;
817 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
818 #  define DIST_BETWEEN_HANDLERS 3
819 #else /*No local or global handlers; ordinary handlers are back-to-back*/
820 #  define DIST_BETWEEN_HANDLERS 1
821 #endif
823 int CmiRegisterHandler(CmiHandler h)
825   int Count = CpvAccess(CmiHandlerCount);
826   CmiNumberHandler(Count, h);
827   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
828   return Count;
831 void CmiRegisterHandlerAssignOnce(CmiHandler h, int *index)
833   if (CmiMyRank() == 0) { *index = CmiRegisterHandler(h); }
834   else { CmiRegisterHandler(h); }
835   CmiBarrier();
838 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
840   int Count = CpvAccess(CmiHandlerCount);
841   CmiNumberHandlerEx(Count, h, userPtr);
842   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
843   return Count;
846 void CmiRegisterHandlerExAssignOnce(CmiHandlerEx h, void *userPtr, int *index)
848   if (CmiMyRank() == 0) { *index = CmiRegisterHandlerEx(h, userPtr); }
849   else { CmiRegisterHandlerEx(h, userPtr); }
850   CmiBarrier();
853 #if CMI_LOCAL_GLOBAL_AVAILABLE
854 int CmiRegisterHandlerLocal(CmiHandler h)
856   int Local = CpvAccess(CmiHandlerLocal);
857   CmiNumberHandler(Local, h);
858   CpvAccess(CmiHandlerLocal) = Local+3;
859   return Local;
862 int CmiRegisterHandlerGlobal(CmiHandler h)
864   int Global = CpvAccess(CmiHandlerGlobal);
865   if (CmiMyPe()!=0) 
866     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
867   CmiNumberHandler(Global, h);
868   CpvAccess(CmiHandlerGlobal) = Global+3;
869   return Global;
871 #endif
873 static void _cmiZeroHandler(void *msg) {
874         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
877 static void CmiHandlerInit(void)
879   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
880   CpvInitialize(int         , CmiHandlerCount);
881   CpvInitialize(int         , CmiHandlerLocal);
882   CpvInitialize(int         , CmiHandlerGlobal);
883   CpvInitialize(int         , CmiHandlerMax);
884   CpvAccess(CmiHandlerCount)  = 0;
885   CpvAccess(CmiHandlerLocal)  = 1;
886   CpvAccess(CmiHandlerGlobal) = 2;
887   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
888   CpvAccess(CmiHandlerTable) = NULL;
889   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
893 /******************************************************************************
895  * CmiTimer
897  * Here are two possible implementations of CmiTimer.  Some machines don't
898  * select either, and define the timer in machine.C instead.
900  *****************************************************************************/
902 #if CMK_HAS_ASCTIME
904 char *CmiPrintDate(void)
906   struct tm *local;
907   time_t t;
909   t = time(NULL);
910   local = localtime(&t);
911   return asctime(local);
914 #else
916 char *CmiPrintDate(void)
918   return "N/A";
921 #endif
923 static int _absoluteTime = 0;
925 #if CMK_TIMER_USE_TIMES
927 CpvStaticDeclare(double, clocktick);
928 CpvStaticDeclare(int,inittime_wallclock);
929 CpvStaticDeclare(int,inittime_virtual);
931 int CmiTimerIsSynchronized(void)
933   return 0;
936 int CmiTimerAbsolute(void)
938   return 0;
941 double CmiStartTimer(void)
943   return 0.0;
946 double CmiInitTime(void)
948   return CpvAccess(inittime_wallclock);
951 void CmiTimerInit(char **argv)
953   struct tms temp;
954   CpvInitialize(double, clocktick);
955   CpvInitialize(int, inittime_wallclock);
956   CpvInitialize(int, inittime_virtual);
957   CpvAccess(inittime_wallclock) = times(&temp);
958   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
959   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
962 double CmiWallTimer(void)
964   struct tms temp;
965   double currenttime;
966   int now;
968   now = times(&temp);
969   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
970   return (currenttime);
973 double CmiCpuTimer(void)
975   struct tms temp;
976   double currenttime;
977   int now;
979   times(&temp);
980   now = temp.tms_stime + temp.tms_utime;
981   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
982   return (currenttime);
985 double CmiTimer(void)
987   return CmiCpuTimer();
990 #endif
992 #if CMK_TIMER_USE_GETRUSAGE
994 #if CMK_SMP
995 # if CMK_HAS_RUSAGE_THREAD
996 #define RUSAGE_WHO        1   /* RUSAGE_THREAD, only in latest Linux kernels */
997 #else
998 #undef RUSAGE_WHO
999 #endif
1000 #else
1001 #define RUSAGE_WHO        0
1002 #endif
1004 static double inittime_wallclock;
1005 CpvStaticDeclare(double, inittime_virtual);
1007 int CmiTimerIsSynchronized(void)
1009   return 0;
1012 int CmiTimerAbsolute(void)
1014   return _absoluteTime;
1017 double CmiStartTimer(void)
1019   return 0.0;
1022 double CmiInitTime(void)
1024   return inittime_wallclock;
1027 void CmiTimerInit(char **argv)
1029   struct rusage ru;
1030   CpvInitialize(double, inittime_virtual);
1032   int tmptime = CmiGetArgFlagDesc(argv,"+useAbsoluteTime", "Use system's absolute time as wallclock time.");
1033   if(CmiMyRank() == 0) _absoluteTime = tmptime;   /* initialize only  once */
1034 #if !(__FAULT__)
1035   /* try to synchronize calling barrier */
1036   CmiBarrier();
1037   CmiBarrier();
1038   CmiBarrier();
1039 #endif
1040 if(CmiMyRank() == 0) /* initialize only  once */
1041   {
1042     inittime_wallclock = inithrc();
1043 #ifndef RUSAGE_WHO
1044     CpvAccess(inittime_virtual) = inittime_wallclock;
1045 #else
1046     getrusage(RUSAGE_WHO, &ru); 
1047     CpvAccess(inittime_virtual) =
1048       (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1049       (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1050 #endif
1051   }
1053 #if !(__FAULT__)
1054   CmiBarrier();
1055 /*  CmiBarrierZero(); */
1056 #endif
1059 double CmiCpuTimer(void)
1061 #ifndef RUSAGE_WHO
1062   return CmiWallTimer();
1063 #else
1064   struct rusage ru;
1065   double currenttime;
1067   getrusage(RUSAGE_WHO, &ru);
1068   currenttime =
1069     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1070     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1071   
1072   return currenttime - CpvAccess(inittime_virtual);
1073 #endif
1076 static double lastT = -1.0;
1078 double CmiWallTimer(void)
1080   double currenttime;
1081   currenttime = gethrctime();
1082   return _absoluteTime?currenttime+inittime_wallclock:currenttime;
1085 double CmiTimer(void)
1087   return CmiCpuTimer();
1090 #endif
1092 #if CMK_TIMER_USE_RDTSC
1094 static double readMHz(void)
1096   double x;
1097   char str[1000];
1098   char buf[100];
1099   FILE *fp;
1100   CmiLock(_smp_mutex);
1101   fp = fopen("/proc/cpuinfo", "r");
1102   if (fp != NULL)
1103   while(fgets(str, 1000, fp)!=0) {
1104     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
1105     {
1106       char *s = strchr(str, ':'); s=s+1;
1107       sscanf(s, "%lf", &x);
1108       fclose(fp);
1109       CmiUnlock(_smp_mutex);
1110       return x;
1111     }
1112   }
1113   CmiUnlock(_smp_mutex);
1114   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
1115   return 0.0;
1118 double _cpu_speed_factor;
1119 CpvStaticDeclare(double, inittime_virtual);
1120 CpvStaticDeclare(double, inittime_walltime);
1122 double  CmiStartTimer(void)
1124   return CpvAccess(inittime_walltime);
1127 double CmiInitTime(void)
1129   return CpvAccess(inittime_walltime);
1132 void CmiTimerInit(char **argv)
1134   struct rusage ru;
1136   CmiBarrier();
1137   CmiBarrier();
1139   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
1140   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
1141   CpvInitialize(double, inittime_walltime);
1142   CpvAccess(inittime_walltime) = CmiWallTimer();
1143   CpvInitialize(double, inittime_virtual);
1144   getrusage(0, &ru); 
1145   CpvAccess(inittime_virtual) =
1146     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1147     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1149   CmiBarrierZero();
1152 double CmiCpuTimer(void)
1154   struct rusage ru;
1155   double currenttime;
1157   getrusage(0, &ru);
1158   currenttime =
1159     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1160     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1161   return currenttime - CpvAccess(inittime_virtual);
1164 #endif
1166 #if CMK_TIMER_USE_BLUEGENEQ  /* This module just compiles with GCC charm. */
1168 CpvStaticDeclare(unsigned long, inittime);
1169 CpvStaticDeclare(double, clocktick);
1171 int CmiTimerIsSynchronized(void)
1173   return 1;
1176 int CmiTimerAbsolute(void)
1178   return 0;
1181 #include "hwi/include/bqc/A2_inlines.h"
1182 #include "spi/include/kernel/process.h"
1184 double CmiStartTimer(void)
1186   return 0.0;
1189 double CmiInitTime(void)
1191   return CpvAccess(inittime);
1194 void CmiTimerInit(char **argv)
1196   CpvInitialize(double, clocktick);
1197   CpvInitialize(unsigned long, inittime);
1199   Personality_t  pers;
1200   Kernel_GetPersonality(&pers, sizeof(pers));
1201   uint32_t clockMhz = pers.Kernel_Config.FreqMHz;
1202   CpvAccess(clocktick) = 1.0 / (clockMhz * 1e6); 
1204   /*fprintf(stderr, "Blue Gene/Q running at clock speed of %d Mhz\n", clockMhz);*/
1206   /* try to synchronize calling barrier */
1207 #if !(__FAULT__)
1208   CmiBarrier();
1209   CmiBarrier();
1210   CmiBarrier();
1211 #endif
1212   CpvAccess(inittime) = GetTimeBase (); 
1215 double CmiWallTimer(void)
1217   unsigned long long currenttime;
1218   currenttime = GetTimeBase();
1219   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1222 double CmiCpuTimer(void)
1224   return CmiWallTimer();
1227 double CmiTimer(void)
1229   return CmiWallTimer();
1232 #endif
1235 #if CMK_TIMER_USE_PPC64
1237 #include <sys/time.h>
1238 #include <sys/platform/ppc.h>
1240 CpvStaticDeclare(uint64_t, inittime);
1241 CpvStaticDeclare(double, clocktick);
1243 int CmiTimerIsSynchronized(void)
1245   return 1;
1248 int CmiTimerAbsolute(void)
1250   return 0;
1253 double CmiStartTimer(void)
1255   return 0.0;
1258 double CmiInitTime(void)
1260   return CpvAccess(inittime);
1263 static inline uint64_t PPC64_TimeBase(void)
1265   register volatile uint64_t result;
1267   /* For 64-bit only */
1268   asm volatile (
1269             "   isync    \n\t"
1270             "   mftb  %0 \n\t"
1271             "   isync    \n\t"
1272             : "=r"(result));
1274   return result;
1277 void CmiTimerInit(char **argv)
1279   CpvInitialize(double, clocktick);
1280   CpvInitialize(unsigned long, inittime);
1281   CpvAccess(clocktick) =  1.0 / ((double) __ppc_get_timebase_freq());
1283   /* try to synchronize calling barrier */
1284 #if !(__FAULT__)
1285   CmiBarrier();
1286   CmiBarrier();
1287   CmiBarrier();
1288 #endif
1289   CpvAccess(inittime) = PPC64_TimeBase ();
1292 double CmiWallTimer(void)
1294   uint64_t currenttime;
1295   currenttime = PPC64_TimeBase();
1296   return CpvAccess(clocktick)*(currenttime-CpvAccess(inittime));
1299 double CmiCpuTimer(void)
1301   return CmiWallTimer();
1304 double CmiTimer(void)
1306   return CmiWallTimer();
1309 #endif
1312 #if CMK_TIMER_USE_WIN32API
1314 CpvStaticDeclare(double, inittime_wallclock);
1315 CpvStaticDeclare(double, inittime_virtual);
1317 double CmiStartTimer(void)
1319   return 0.0;
1322 int CmiTimerAbsolute(void)
1324   return 0;
1327 double CmiInitTime(void)
1329   return CpvAccess(inittime_wallclock);
1332 void CmiTimerInit(char **argv)
1334         struct timeb tv;
1335         clock_t       ru;
1337         CpvInitialize(double, inittime_wallclock);
1338         CpvInitialize(double, inittime_virtual);
1339         ftime(&tv);
1340         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
1341         ru = clock();
1342         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
1345 double CmiCpuTimer(void)
1347         clock_t ru;
1348         double currenttime;
1350         ru = clock();
1351         currenttime = (double) ru/CLOCKS_PER_SEC;
1353         return currenttime - CpvAccess(inittime_virtual);
1356 double CmiWallTimer(void)
1358         struct timeb tv;
1359         double currenttime;
1361         ftime(&tv);
1362         currenttime = tv.time*1.0 + tv.millitm*0.001;
1364         return currenttime - CpvAccess(inittime_wallclock);
1366         
1368 double CmiTimer(void)
1370         return CmiCpuTimer();
1373 #endif
1375 #if CMK_TIMER_USE_RTC
1377 static double clocktick;
1378 CpvStaticDeclare(long long, inittime_wallclock);
1380 double CmiStartTimer(void)
1382   return 0.0;
1385 double CmiInitTime(void)
1387   return CpvAccess(inittime_wallclock);
1390 void CmiTimerInit(char **argv)
1392   CpvInitialize(long long, inittime_wallclock);
1393   CpvAccess(inittime_wallclock) = _rtc();
1394   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
1397 int CmiTimerAbsolute(void)
1399   return 0;
1402 double CmiWallTimer(void)
1404   long long now;
1406   now = _rtc();
1407   return (clocktick * (now - CpvAccess(inittime_wallclock)));
1410 double CmiCpuTimer(void)
1412   return CmiWallTimer();
1415 double CmiTimer(void)
1417   return CmiCpuTimer();
1420 #endif
1422 #if CMK_TIMER_USE_AIX_READ_TIME
1424 #include <sys/time.h>
1426 static timebasestruct_t inittime_wallclock;
1427 static double clocktick;
1428 CpvStaticDeclare(double, inittime_virtual);
1430 double CmiStartTimer(void)
1432   return 0.0;
1435 double CmiInitTime(void)
1437   return inittime_wallclock;
1440 void CmiTimerInit(char **argv)
1442   struct rusage ru;
1444   if (CmiMyRank() == 0) {
1445     read_wall_time(&inittime_wallclock, TIMEBASE_SZ);
1446     time_base_to_time(&inittime_wallclock, TIMEBASE_SZ);
1447   }
1449   CpvInitialize(double, inittime_virtual);
1450   getrusage(0, &ru);
1451   CpvAccess(inittime_virtual) =
1452     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1453     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1456 int CmiTimerAbsolute(void)
1458   return 0;
1461 double CmiWallTimer(void)
1463   int secs, n_secs;
1464   double curt;
1465   timebasestruct_t now;
1466   read_wall_time(&now, TIMEBASE_SZ);
1467   time_base_to_time(&now, TIMEBASE_SZ);
1469   secs = now.tb_high - inittime_wallclock.tb_high;
1470   n_secs = now.tb_low - inittime_wallclock.tb_low;
1471   if (n_secs < 0)  {
1472     secs--;
1473     n_secs += 1000000000;
1474   }
1475   curt = secs*1.0 + n_secs*1e-9;
1476   return curt;
1479 double CmiCpuTimer(void)
1481   struct rusage ru;
1482   double currenttime;
1484   getrusage(0, &ru);
1485   currenttime =
1486     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
1487     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
1488   return currenttime - CpvAccess(inittime_virtual);
1491 double CmiTimer(void)
1493   return CmiWallTimer();
1496 #endif
1498 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
1499 /** Return 1 if our outgoing message queue 
1500    for this node is longer than this many bytes. */
1501 int CmiLongSendQueue(int forNode,int longerThanBytes) {
1502   return 0;
1504 #endif
1506 #if CMK_SIGNAL_USE_SIGACTION
1507 #include <signal.h>
1508 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1510   struct sigaction in, out ;
1511   in.sa_handler = handler;
1512   sigemptyset(&in.sa_mask);
1513   if (sig1) sigaddset(&in.sa_mask, sig1);
1514   if (sig2) sigaddset(&in.sa_mask, sig2);
1515   if (sig3) sigaddset(&in.sa_mask, sig3);
1516   in.sa_flags = 0;
1517   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1518   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1519   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1521 #endif
1523 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1524 #include <signal.h>
1525 void CmiSignal(int sig1, int sig2, int sig3, void (*handler)(int))
1527   struct sigaction in, out ;
1528   in.sa_handler = handler;
1529   sigemptyset(&in.sa_mask);
1530   if (sig1) sigaddset(&in.sa_mask, sig1);
1531   if (sig2) sigaddset(&in.sa_mask, sig2);
1532   if (sig3) sigaddset(&in.sa_mask, sig3);
1533   in.sa_flags = SA_RESTART;
1534   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1535   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1536   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1538 #endif
1540 /** 
1541  *  @addtogroup ConverseScheduler
1542  *  @{
1543  */
1545 /*****************************************************************************
1546  * 
1547  * The following is the CsdScheduler function.  A common
1548  * implementation is provided below.  The machine layer can provide an
1549  * alternate implementation if it so desires.
1551  * void CmiDeliversInit()
1553  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1554  *        or any of the other functions in this section.
1556  * int CmiDeliverMsgs(int maxmsgs)
1558  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1559  *        with the Cmi, and will invoke their handlers.  It does not wait
1560  *        if no message is unavailable.  Instead, it returns the quantity
1561  *        (maxmsgs-delivered), where delivered is the number of messages it
1562  *        delivered.
1564  * void CmiDeliverSpecificMsg(int handlerno)
1566  *      - Waits for a message with the specified handler to show up, then
1567  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1568  *        This function _does_ wait.
1570  * For this common implementation to work, the machine layer must provide the
1571  * following:
1573  * void *CmiGetNonLocal()
1575  *      - returns a message just retrieved from some other PE, not from
1576  *        local.  If no such message exists, returns 0.
1578  * CpvExtern(CdsFifo, CmiLocalQueue);
1580  *      - a FIFO queue containing all messages from the local processor.
1582  *****************************************************************************/
1584 void CsdBeginIdle(void)
1586   CcdCallBacks();
1587 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1588   _LOG_E_PROC_IDLE();   /* projector */
1589 #endif
1590 #if CMK_SMP && CMK_TASKQUEUE
1591   if (CpvAccess(cmiMyPeIdle) !=1) {
1592     CpvAccess(cmiMyPeIdle) = 1;
1593     CmiMemoryAtomicIncrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1594   }
1595 #else
1596   CpvAccess(cmiMyPeIdle) = 1;
1597 #endif // CMK_SMP
1598   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1601 void CsdStillIdle(void)
1603   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1606 void CsdEndIdle(void)
1608 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1609   _LOG_E_PROC_BUSY();   /* projector */
1610 #endif
1611 #if CMK_SMP && CMK_TASKQUEUE
1612   if (CpvAccess(cmiMyPeIdle) != 0){
1613     CpvAccess(cmiMyPeIdle) = 0;
1614     CmiMemoryAtomicDecrement(CsvAccess(idleThreadsCnt), memory_order_relaxed);
1615   }
1616 #else
1617   CpvAccess(cmiMyPeIdle) = 0;
1618 #endif // CMK_SMP
1619   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1622 extern int _exitHandlerIdx;
1624 /** Takes a message and calls its corresponding handler. */
1625 void CmiHandleMessage(void *msg)
1627 /* this is wrong because it counts the Charm++ messages in sched queue
1628         CpvAccess(cQdState)->mProcessed++;
1630         CmiHandlerInfo *h;
1631         CmiUInt2 handlerIdx=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1632 #if CMK_TRACE_ENABLED && CMK_PROJECTOR
1633         _LOG_E_HANDLER_BEGIN(handlerIdx); /* projector */
1634         /* setMemoryStatus(1) */ /* charmdebug */
1635 #endif
1638         CMK_FAULT_EVAC
1640 /*      if((!CpvAccess(_validProcessors)[CmiMyPe()]) && handler != _exitHandlerIdx){
1641                 return;
1642         }*/
1643         
1644         MESSAGE_PHASE_CHECK(msg)
1645 #if CMK_ERROR_CHECKING
1646         if (handlerIdx >= CpvAccess(CmiHandlerCount)) {
1647           CmiAbort("Msg handler does not exist, possible race condition during init\n");
1648         }
1649 #endif
1650         h=&CmiHandlerToInfo(handlerIdx);
1651 #if CMK_ERROR_CHECKING
1652         if (h->hdlr == NULL) {
1653           CmiAbort("Msg handler does not exist, possible race condition during init\n");
1654         }
1655 #endif
1656         (h->hdlr)(msg,h->userPtr);
1657 #if CMK_TRACE_ENABLED
1658         /* setMemoryStatus(0) */ /* charmdebug */
1659         //_LOG_E_HANDLER_END(handlerIdx);       /* projector */
1660 #endif
1663 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1665 void CmiDeliversInit(void)
1669 int CmiDeliverMsgs(int maxmsgs)
1671   return CsdScheduler(maxmsgs);
1674 #if CMK_OBJECT_QUEUE_AVAILABLE
1675 CpvDeclare(void *, CsdObjQueue);
1676 #endif
1678 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1680 #if CMK_OBJECT_QUEUE_AVAILABLE
1681         s->objQ=CpvAccess(CsdObjQueue);
1682 #endif
1683         s->localQ=CpvAccess(CmiLocalQueue);
1684         s->schedQ=CpvAccess(CsdSchedQueue);
1685         s->localCounter=&(CpvAccess(CsdLocalCounter));
1686 #if CMK_NODE_QUEUE_AVAILABLE
1687         s->nodeQ=CsvAccess(CsdNodeQueue);
1688         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1689 #endif
1690 #if CMK_GRID_QUEUE_AVAILABLE
1691         s->gridQ=CpvAccess(CsdGridQueue);
1692 #endif
1693 #if CMK_SMP && CMK_TASKQUEUE
1694         s->taskQ = CpvAccess(CsdTaskQueue);
1695         s->suspendedTaskQ = CpvAccess(CmiSuspendedTaskQueue);
1696 #endif
1700 /** Dequeue and return the next message from the unprocessed message queues.
1702  * This function encapsulates the multiple queues that exist for holding unprocessed
1703  * messages and the rules for the order in which to check them. There are five (5)
1704  * different Qs that converse uses to store and retrieve unprocessed messages. These
1705  * are:
1706  *     Q Purpose                  Type      internal DeQ logic
1707  * -----------------------------------------------------------
1708  * - PE offnode                   pcQ             FIFO
1709  * - PE onnode                    CkQ             FIFO
1710  * - Node offnode                 pcQ             FIFO
1711  * - Node onnode                  prioQ           prio-based
1712  * - Scheduler                    prioQ           prio-based
1714  * The PE queues hold messages that are destined for a specific PE. There is one such
1715  * queue for every PE within a charm node. The node queues hold messages that are
1716  * destined to that node. There is only one of each node queue within a charm node.
1717  * Finally there is also a charm++ message queue for each PE.
1719  * The offnode queues are meant for holding messages that arrive from outside the
1720  * node. The onnode queues hold messages that are generated within the same charm
1721  * node.
1723  * The PE and node level offnode queues are accessed via functions CmiGetNonLocal()
1724  * and CmiGetNonLocalNodeQ(). These are implemented separately by each machine layer
1725  * and hide the implementation specifics for each layer.
1727  * The PE onnode queue is implemented as a FIFO CkQ and is initialized via a call to
1728  * CdsFifo_Create(). The node local queue and the scheduler queue are both priority
1729  * queues. They are initialized via calls to CqsCreate() which gives each of them
1730  * three separate internal queues for different priority ranges (-ve, 0 and +ve).
1731  * Access to these queues is via pointers stored in the struct CsdSchedulerState that
1732  * is passed into this function.
1734  * The order in which these queues are checked is described below. The function
1735  * proceeds to the next queue in the list only if it does not find any messages in
1736  * the current queue. The first message that is found is returned, terminating the
1737  * call.
1738  * (1) offnode queue for this PE
1739  * (2) onnode queue for this PE
1740  * (3) offnode queue for this node
1741  * (4) highest priority msg from onnode queue or scheduler queue
1743  * @note: Across most (all?) machine layers, the two GetNonLocal functions simply
1744  * access (after observing adequate locking rigor) structs representing the scheduler
1745  * state, to dequeue from the queues stored within them. The structs (CmiStateStruct
1746  * and CmiNodeStateStruct) implement these queues as \ref Machine "pc (producer-consumer)
1747  * queues". The functions also perform other necessary actions like PumpMsgs() etc.
1749  */
1750 void *CsdNextMessage(CsdSchedulerState_t *s) {
1751         void *msg;
1752         if((*(s->localCounter))-- >0)
1753           {
1754               /* This avoids a race condition with migration detected by megatest*/
1755               msg=CdsFifo_Dequeue(s->localQ);
1756               if (msg!=NULL)
1757                 {
1758 #if CMI_QD
1759                   CpvAccess(cQdState)->mProcessed++;
1760 #endif
1761                   return msg;       
1762                 }
1763               CqsDequeue(s->schedQ,(void **)&msg);
1764               if (msg!=NULL) return msg;
1765           }
1766         
1767         *(s->localCounter)=CsdLocalMax;
1768         if ( NULL!=(msg=CmiGetNonLocal()) || 
1769              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1770 #if CMI_QD
1771             CpvAccess(cQdState)->mProcessed++;
1772 #endif
1773             return msg;
1774         }
1775 #if CMK_GRID_QUEUE_AVAILABLE
1776         /*#warning "CsdNextMessage: CMK_GRID_QUEUE_AVAILABLE" */
1777         CqsDequeue (s->gridQ, (void **) &msg);
1778         if (msg != NULL) {
1779           return (msg);
1780         }
1781 #endif
1782 #if CMK_SMP && CMK_TASKQUEUE
1783 #if CMK_OMP
1784         msg = CmiSuspendedTaskPop();
1785         if (msg != NULL) {
1786           return (msg);
1787         }
1788 #endif
1789         msg = TaskQueuePop((TaskQueue)s->taskQ);
1790         if (msg != NULL) {
1791           return (msg);
1792         }
1793 #endif
1794 #if CMK_NODE_QUEUE_AVAILABLE
1795         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1796         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1797 #if !CMK_NO_MSG_PRIOS
1798         if (!CqsEmpty(s->nodeQ)
1799          && CqsPrioGT(CqsGetPriority(s->schedQ),
1800                        CqsGetPriority(s->nodeQ))) {
1801           if(CmiTryLock(s->nodeLock) == 0) {
1802             CqsDequeue(s->nodeQ,(void **)&msg);
1803             CmiUnlock(s->nodeLock);
1804             if (msg!=NULL) return msg;
1805           }
1806         }
1807 #endif
1808 #endif
1809 #if CMK_OBJECT_QUEUE_AVAILABLE
1810         /*#warning "CsdNextMessage: CMK_OBJECT_QUEUE_AVAILABLE"   */
1811         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1812           return msg;
1813         }
1814 #endif
1815         if(!CsdLocalMax) {
1816           CqsDequeue(s->schedQ,(void **)&msg);
1817           if (msg!=NULL) return msg;        
1818         }
1819         return NULL;
1823 void *CsdNextLocalNodeMessage(CsdSchedulerState_t *s) {
1824         void *msg;
1825 #if CMK_NODE_QUEUE_AVAILABLE
1826         /*#warning "CsdNextMessage: CMK_NODE_QUEUE_AVAILABLE" */
1827         /*if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;*/
1828         if (!CqsEmpty(s->nodeQ))
1829         {
1830           CmiLock(s->nodeLock);
1831           CqsDequeue(s->nodeQ,(void **)&msg);
1832           CmiUnlock(s->nodeLock);
1833           if (msg!=NULL) return msg;
1834         }
1835 #endif
1836         return NULL;
1840 int CsdScheduler(int maxmsgs)
1842         if (maxmsgs<0) CsdScheduleForever();    
1843         else if (maxmsgs==0)
1844                 CsdSchedulePoll();
1845         else /*(maxmsgs>0)*/ 
1846                 return CsdScheduleCount(maxmsgs);
1847         return 0;
1850 /*Declare the standard scheduler housekeeping*/
1851 #define SCHEDULE_TOP \
1852       void *msg;\
1853       int *CsdStopFlag_ptr = &CpvAccess(CsdStopFlag); \
1854       int cycle = CpvAccess(CsdStopFlag); \
1855       CsdSchedulerState_t state;\
1856       CsdSchedulerState_new(&state);
1858 /*A message is available-- process it*/
1859 #define SCHEDULE_MESSAGE \
1860       CmiHandleMessage(msg);\
1861       if (*CsdStopFlag_ptr != cycle) break;
1863 /*No message available-- go (or remain) idle*/
1864 #if CSD_NO_IDLE_TRACING
1865 #define SCHEDULE_IDLE /* do nothing */
1866 #else
1867 #define SCHEDULE_IDLE \
1868       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1869       else CsdStillIdle();\
1870       if (*CsdStopFlag_ptr != cycle) {\
1871         CsdEndIdle();\
1872         break;\
1873       }
1874 #endif
1877         EVAC
1881 extern void machine_OffloadAPIProgress(void);
1883 /** The main scheduler loop that repeatedly executes messages from a queue, forever. */
1884 void CsdScheduleForever(void)
1886   #if CMK_CELL
1887     #define CMK_CELL_PROGRESS_FREQ  96  /* (MSG-Q Entries x1.5) */
1888     int progressCount = CMK_CELL_PROGRESS_FREQ;
1889   #endif
1891   int isIdle=0;
1892   SCHEDULE_TOP
1893   while (1) {
1894 #if !CMK_NO_INTEROP
1895     /* The interoperation will cost this little overhead in scheduling */
1896     if(CharmLibInterOperate) {
1897       if(CpvAccess(interopExitFlag)) {
1898         CpvAccess(interopExitFlag) = 0;
1899         break;
1900       }
1901     }
1902 #endif
1903     #if CMK_CUDA
1904     // check if any GPU work needs to be processed
1905     if (CpvAccess(n_hapi_events) > 0) {
1906       hapiPollEvents();
1907     }
1908     #endif
1909     msg = CsdNextMessage(&state);
1910     if (msg!=NULL) { /*A message is available-- process it*/
1911 #if !CSD_NO_IDLE_TRACING
1912       if (isIdle) {isIdle=0;CsdEndIdle();}
1913 #endif
1914       SCHEDULE_MESSAGE
1916       #if CMK_CELL
1917         if (progressCount <= 0) {
1918           /*OffloadAPIProgress();*/
1919           machine_OffloadAPIProgress();
1920           progressCount = CMK_CELL_PROGRESS_FREQ;
1921         }
1922         progressCount--;
1923       #endif
1924     } else { /*No message available-- go (or remain) idle*/
1925       SCHEDULE_IDLE
1927       #if CMK_CELL
1928         /*OffloadAPIProgress();*/
1929         machine_OffloadAPIProgress();
1930         progressCount = CMK_CELL_PROGRESS_FREQ;
1931       #endif
1932     }
1933 #if !CSD_NO_PERIODIC
1934     CsdPeriodic();
1935 #endif
1936   }
1938 int CsdScheduleCount(int maxmsgs)
1940   int isIdle=0;
1941   SCHEDULE_TOP
1942   while (1) {
1943     msg = CsdNextMessage(&state);
1944     if (msg!=NULL) { /*A message is available-- process it*/
1945 #if !CSD_NO_IDLE_TRACING
1946       if (isIdle) {isIdle=0;CsdEndIdle();}
1947 #endif
1948       maxmsgs--; 
1949       SCHEDULE_MESSAGE
1950       if (maxmsgs==0) break;
1951     } else { /*No message available-- go (or remain) idle*/
1952       SCHEDULE_IDLE
1953     }
1954 #if !CSD_NO_PERIODIC
1955     CsdPeriodic();
1956 #endif
1957   }
1958   return maxmsgs;
1961 void CsdSchedulePoll(void)
1963   SCHEDULE_TOP
1964   while (1)
1965   {
1966 #if !CSD_NO_PERIODIC
1967         CsdPeriodic();
1968 #endif
1969         /*CmiMachineProgressImpl(); ??? */
1970         if (NULL!=(msg = CsdNextMessage(&state)))
1971         {
1972              SCHEDULE_MESSAGE 
1973         }
1974         else break;
1975   }
1978 void CsdScheduleNodePoll(void)
1980   SCHEDULE_TOP
1981   while (1)
1982   {
1983         /*CsdPeriodic();*/
1984         /*CmiMachineProgressImpl(); ??? */
1985         if (NULL!=(msg = CsdNextLocalNodeMessage(&state)))
1986         {
1987              SCHEDULE_MESSAGE 
1988         }
1989         else break;
1990   }
1993 void CmiDeliverSpecificMsg(int handler)
1995   int *msg; int side;
1996   void *localqueue = CpvAccess(CmiLocalQueue);
1998   side = 0;
1999   while (1) {
2000 #if !CSD_NO_PERIODIC
2001     CsdPeriodic();
2002 #endif
2003     side ^= 1;
2004     if (side) msg = (int *)CmiGetNonLocal();
2005     else      msg = (int *)CdsFifo_Dequeue(localqueue);
2006     if (msg) {
2007       if (CmiGetHandler(msg)==handler) {
2008 #if CMI_QD
2009         CpvAccess(cQdState)->mProcessed++;
2010 #endif
2011         CmiHandleMessage(msg);
2012         return;
2013       } else {
2014         CdsFifo_Enqueue(localqueue, msg);
2015       }
2016     }
2017   }
2020 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
2022 /***************************************************************************
2024  * Standin Schedulers.
2026  * We use the following strategy to make sure somebody's always running
2027  * the scheduler (CsdScheduler).  Initially, we assume the main thread
2028  * is responsible for this.  If the main thread blocks, we create a
2029  * "standin scheduler" thread to replace it.  If the standin scheduler
2030  * blocks, we create another standin scheduler to replace that one,
2031  * ad infinitum.  Collectively, the main thread and all the standin
2032  * schedulers are called "scheduling threads".
2034  * Suppose the main thread is blocked waiting for data, and a standin
2035  * scheduler is running instead.  Suppose, then, that the data shows
2036  * up and the main thread is CthAwakened.  This causes a token to be
2037  * pushed into the queue.  When the standin pulls the token from the
2038  * queue and handles it, the standin goes to sleep, and control shifts
2039  * back to the main thread.  In this way, unnecessary standins are put
2040  * back to sleep.  These sleeping standins are stored on the
2041  * CthSleepingStandins list.
2043  ***************************************************************************/
2045 CpvStaticDeclare(CthThread, CthMainThread);
2046 CpvStaticDeclare(CthThread, CthSchedulingThread);
2047 CpvStaticDeclare(CthThread, CthSleepingStandins);
2048 CpvDeclare(int      , CthResumeNormalThreadIdx);
2049 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
2051 #if CMK_OMP
2052 CpvDeclare (int, CthResumeStealableThreadIdx);
2053 CpvDeclare (int, CthResumeSuspendedStealableThreadIdx);
2054 #endif
2056 void CthStandinCode(void *arg)
2058   CsdScheduler(-1);
2061 /* this fix the function pointer for thread migration and pup */
2062 static CthThread CthSuspendNormalThread(void)
2064   return CpvAccess(CthSchedulingThread);
2067 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
2068 CthThread CthSuspendSchedulingThread(void);
2070 CthThread CthSuspendSchedulingThread(void)
2072   CthThread succ = CpvAccess(CthSleepingStandins);
2074   if (succ) {
2075     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
2076   } else {
2077     succ = CthCreate(CthStandinCode, 0, 256000);
2078     CthSetStrategy(succ,
2079                    CthEnqueueSchedulingThread,
2080                    CthSuspendSchedulingThread);
2081   }
2082   
2083   CpvAccess(CthSchedulingThread) = succ;
2084   return succ;
2087 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
2088 void CthResumeNormalThread(CthThreadToken* token)
2090   CthThread t = token->thread;
2092   /* BIGSIM_OOC DEBUGGING
2093   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
2094   */
2096   if(t == NULL){
2097     free(token);
2098     return;
2099   }
2100 #if CMK_TRACE_ENABLED
2101 #if ! CMK_TRACE_IN_CHARM
2102   if(CpvAccess(traceOn))
2103     CthTraceResume(t);
2104 /*    if(CpvAccess(_traceCoreOn)) 
2105                 resumeTraceCore();*/
2106 #endif
2107 #endif
2108   
2109   /* BIGSIM_OOC DEBUGGING
2110   CmiPrintf("In CthResumeNormalThread:   ");
2111   CthPrintThdMagic(t);
2112   */
2113 #if CMK_OMP
2114   CthSetPrev(t, CthSelf());
2115 #endif
2116   CthResume(t);
2117 #if CMK_OMP
2118   CthScheduledDecrement();
2119   CthSetPrev(CthSelf(), 0);
2120 #endif
2123 void CthResumeSchedulingThread(CthThreadToken  *token)
2125   CthThread t = token->thread;
2126   CthThread me = CthSelf();
2127   if (me == CpvAccess(CthMainThread)) {
2128     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2129   } else {
2130     CthSetNext(me, CpvAccess(CthSleepingStandins));
2131     CpvAccess(CthSleepingStandins) = me;
2132   }
2133   CpvAccess(CthSchedulingThread) = t;
2134 #if CMK_TRACE_ENABLED
2135 #if ! CMK_TRACE_IN_CHARM
2136   if(CpvAccess(traceOn))
2137     CthTraceResume(t);
2138 /*    if(CpvAccess(_traceCoreOn)) 
2139                 resumeTraceCore();*/
2140 #endif
2141 #endif
2142 #if CMK_OMP
2143   CthSetPrev(t, CthSelf());
2144 #endif
2145   CthResume(t);
2146 #if CMK_OMP
2147   CthScheduledDecrement();
2148   CthSetPrev(CthSelf(), 0);
2149 #endif
2152 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2153                                    int pb,unsigned int *prio)
2155   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2156   CsdEnqueueGeneral(token, s, pb, prio);
2159 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2160                                        int pb,unsigned int *prio)
2162   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2163   CsdEnqueueGeneral(token, s, pb, prio);
2166 void CthSetStrategyDefault(CthThread t)
2168   CthSetStrategy(t,
2169                  CthEnqueueNormalThread,
2170                  CthSuspendNormalThread);
2172 #if CMK_OMP
2173 /* Use work-stealing queue for scheduling threads
2174   We use the previous scheduling handlers while we push the message into the work-stealing queue
2176 void CthResumeStealableThread(CthThreadToken *token)
2178   CthThread t = token->thread;
2179   CthSetNext(t, CthSelf());
2180 #if CMK_TRACE_ENABLED
2181 #if ! CMK_TRACE_IN_CHARM
2182   if(CpvAccess(traceOn))
2183     CthTraceResume(t);
2184 #endif
2185 #endif
2186   CthSetPrev(t, CthSelf());
2187   CthResume(t);
2188   CthScheduledDecrement();
2189   CthSetPrev(CthSelf(), 0);
2192 void CthEnqueueStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio) {
2193   CmiSetHandler(token, CpvAccess(CthResumeStealableThreadIdx));
2194   CsdTaskEnqueue((void*)token);
2198 void CthEnqueueSuspendedStealableThread(CthThreadToken * token, int s, int pb, unsigned int *prio)
2200   CthThread t = token->thread;
2201   int targetRank = CthGetThreadID(t)->id[2];
2202   CthSetStrategyWorkStealing(t);
2203   if (targetRank == CmiMyRank()) {
2204     CthEnqueueStealableThread(token,s,pb,prio);
2205   }
2206   else {
2207     CmiSetHandler(token, CpvAccess(CthResumeSuspendedStealableThreadIdx));
2208     CmiSuspendedTaskEnqueue(targetRank ,(void*)token);
2209   }
2212 void CthResumeSuspendedStealableThread(CthThreadToken *token) {
2213   CthEnqueueStealableThread(token, 0, 0, NULL);
2216 CthThread CthSuspendStealableThread()
2218   CthThread succ = CthGetNext(CthSelf());
2219 #if CMK_ERROR_CHECKING
2220   if (!succ)
2221     CmiAbort("successor is invalid\n");
2222 #endif
2223   return succ;
2226 void CthSetStrategyWorkStealing(CthThread t)
2228   CthSetStrategy(t, CthEnqueueStealableThread, CthSuspendStealableThread);
2231 void CthSetStrategySuspendedWorkStealing(CthThread t)
2233   CthSetStrategy(t, CthEnqueueSuspendedStealableThread, CthSuspendStealableThread);
2236 #endif
2237 void CthSchedInit()
2239   CpvInitialize(CthThread, CthMainThread);
2240   CpvInitialize(CthThread, CthSchedulingThread);
2241   CpvInitialize(CthThread, CthSleepingStandins);
2242   CpvInitialize(int      , CthResumeNormalThreadIdx);
2243   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2244 #if CMK_OMP
2245   CpvInitialize(int      , CthResumeStealableThreadIdx);
2246   CpvInitialize(int      , CthResumeSuspendedStealableThreadIdx);
2247 #endif
2248   CpvAccess(CthMainThread) = CthSelf();
2249   CpvAccess(CthSchedulingThread) = CthSelf();
2250   CpvAccess(CthSleepingStandins) = 0;
2251   CpvAccess(CthResumeNormalThreadIdx) =
2252     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2253   CpvAccess(CthResumeSchedulingThreadIdx) =
2254     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2255   CthSetStrategy(CthSelf(),
2256                  CthEnqueueSchedulingThread,
2257                  CthSuspendSchedulingThread);
2259 #if CMK_OMP
2260   CpvAccess(CthResumeStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeStealableThread);
2261   CpvAccess(CthResumeSuspendedStealableThreadIdx) = CmiRegisterHandler((CmiHandler)CthResumeSuspendedStealableThread);
2262 #endif
2265 void CsdInit(char **argv)
2267   CpvInitialize(Queue, CsdSchedQueue);
2268   CpvInitialize(int,   CsdStopFlag);
2269   CpvInitialize(int,   CsdLocalCounter);
2270   int argCsdLocalMax=CSD_LOCAL_MAX_DEFAULT;
2271   int argmaxset = CmiGetArgIntDesc(argv,"+csdLocalMax",&argCsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages.");
2272   if (CmiMyRank() == 0 ) CsdLocalMax = argCsdLocalMax;
2273   CpvAccess(CsdLocalCounter) = argCsdLocalMax;
2274   CpvAccess(CsdSchedQueue) = CqsCreate();
2275 #if CMK_SMP && CMK_TASKQUEUE
2276   CsvInitialize(unsigned int, idleThreadsCnt);
2277   CsvAccess(idleThreadsCnt) = 0;
2278 #endif
2279    #if CMK_USE_STL_MSGQ
2280    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using STL-based msgQ:\n");
2281    #endif
2282    #if CMK_RANDOMIZED_MSGQ
2283    if (CmiMyPe() == 0) CmiPrintf("Charm++> Using randomized msgQ. Priorities will not be respected!\n");
2284    #elif CMK_NO_MSG_PRIOS
2285    if (CmiMyPe() == 0) CmiPrintf("Charm++> Message priorities have been turned off and will not be respected.\n");
2286    #endif
2288 #if CMK_OBJECT_QUEUE_AVAILABLE
2289   CpvInitialize(Queue, CsdObjQueue);
2290   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2291 #endif
2293 #if CMK_NODE_QUEUE_AVAILABLE
2294   CsvInitialize(CmiLock, CsdNodeQueueLock);
2295   CsvInitialize(Queue, CsdNodeQueue);
2296   if (CmiMyRank() ==0) {
2297         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2298         CsvAccess(CsdNodeQueue) = CqsCreate();
2299   }
2300   CmiNodeAllBarrier();
2301 #endif
2303 #if CMK_GRID_QUEUE_AVAILABLE
2304   CsvInitialize(Queue, CsdGridQueue);
2305   CpvAccess(CsdGridQueue) = CqsCreate();
2306 #endif
2308 #if CMK_SMP && CMK_TASKQUEUE
2309   CpvInitialize(Queue, CsdTaskQueue);
2310   CpvInitialize(void *, CmiSuspendedTaskQueue);
2311   CpvAccess(CsdTaskQueue) = (Queue)TaskQueueCreate();
2312 #endif
2313   CpvAccess(CsdStopFlag)  = 0;
2314   CpvInitialize(int, isHelperOn);
2315   CpvAccess(isHelperOn) = 1; // Turn on this bit by default for threads to be used for CkLoop and OpenMP integration
2316   CmiMemoryWriteFence();
2317 #if CMK_SMP && CMK_TASKQUEUE
2318   CmiTaskQueueInit();
2319 #endif
2324 /** 
2325  *  @}
2326  */
2329 /*****************************************************************************
2331  * Vector Send
2333  * The last parameter "system" is by default at zero, in which case the normal
2334  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2335  * CmiAllocced message will also be sent (except for the first one). Useful for
2336  * AllToAll communication, and other system features. If system is 1, also all
2337  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2338  * that.
2340  ****************************************************************************/
2342 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2344 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2345   int total;
2346   char *mesg;
2347 #if CMK_USE_IBVERBS
2348   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2349 #else
2350   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2351 #endif  
2352   CmiSyncSendAndFree(destPE, total, mesg);
2355 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2356   CmiSyncVectorSend(destPE, n, sizes, msgs);
2357   return NULL;
2360 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2361   int i;
2362   CmiSyncVectorSend(destPE, n, sizes, msgs);
2363   for(i=0;i<n;i++) CmiFree(msgs[i]);
2364   CmiFree(sizes);
2365   CmiFree(msgs);
2368 #endif
2370 /*****************************************************************************
2372  * Reduction management
2374  * Only one reduction can be active at a single time in the program.
2375  * Moreover, since every call is supposed to pass in the same arguments,
2376  * having some static variables is not a problem for multithreading.
2377  * 
2378  * Except for "data" and "size", all the other parameters (which are all function
2379  * pointers) MUST be the same in every processor. Having different processors
2380  * pass in different function pointers results in an undefined behaviour.
2381  * 
2382  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2383  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2384  * functions is deleted with the provided function, or it is left intact if no
2385  * function is specified.
2386  * 
2387  * The destination handler for the the first form MUST be embedded into the
2388  * message's header.
2389  * 
2390  * The pup function is used to pup the input data structure into a message to
2391  * be sent to the parent processor. This pup routine is currently used only
2392  * for sizing and packing, NOT unpacking. It MUST be non-null.
2393  * 
2394  * The merge function receives as first parameter the input "data", being it
2395  * a message or a complex data structure (it is up to the user to interpret it
2396  * correctly), and a list of incoming (packed) messages from the children.
2397  * The merge function is responsible to delete "data" if this is no longer needed.
2398  * The system will be in charge of deleting the messages passed in as the second
2399  * argument, and the return value of the function (using the provided deleteFn in
2400  * the second version, or CmiFree in the first). The merge function can return
2401  * data if the merge can be performed in-place. It MUST be non-null.
2402  * 
2403  * At the destination, on processor zero, the final data returned by the last
2404  * merge call will not be deleted by the system, and the CmiHandler function
2405  * will be in charge of its deletion.
2406  * 
2407  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2408  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2409  * particular by the rank zero in each node.
2410  ****************************************************************************/
2412 CpvStaticDeclare(int, CmiReductionMessageHandler);
2413 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2415 CpvStaticDeclare(CmiReduction**, _reduce_info);
2416 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2417 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2418 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2419 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2421 enum {
2422   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2423   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2424   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2425   CmiReductionID_multiplier = 3
2428 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2429   int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2430   CmiReduction *red = CpvAccess(_reduce_info)[index];
2431   if (red != NULL && red->seqID != id) {
2432     /* The table needs to be expanded */
2433     CmiAbort("Too many simultaneous reductions");
2434   }
2435   if (red == NULL || red->numChildren < numChildren) {
2436     CmiReduction *newred;
2437     CmiAssert(red == NULL || red->localContributed == 0);
2438     if (numChildren == 0) numChildren = 4;
2439     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2440     newred->numRemoteReceived = 0;
2441     newred->localContributed = 0;
2442     newred->seqID = id;
2443     if (red != NULL) {
2444       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2445       free(red);
2446     }
2447     red = newred;
2448     red->numChildren = numChildren;
2449     red->remoteData = (char**)(red+1);
2450     CpvAccess(_reduce_info)[index] = red;
2451   }
2452   return red;
2455 CmiReduction* CmiGetReduction(int id) {
2456   return CmiGetReductionCreate(id, 0);
2459 void CmiClearReduction(int id) {
2460   int index = id & ~((~0u)<<CpvAccess(_reduce_info_size));
2461   free(CpvAccess(_reduce_info)[index]);
2462   CpvAccess(_reduce_info)[index] = NULL;
2465 CmiReduction* CmiGetNextReduction(short int numChildren) {
2466   int id = CpvAccess(_reduce_seqID_global);
2467   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2468   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2469   return CmiGetReductionCreate(id, numChildren);
2472 CmiReductionID CmiGetGlobalReduction(void) {
2473   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2476 CmiReductionID CmiGetDynamicReduction(void) {
2477   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2478   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2481 void CmiReductionHandleDynamicRequest(char *msg) {
2482   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2483   int pe = values[0];
2484   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2485   values[0] = CmiGetDynamicReduction();
2486   CmiSetHandler(msg, CmiGetXHandler(msg));
2487   if (pe >= 0) {
2488     CmiSyncSendAndFree(pe, size, msg);
2489   } else {
2490     CmiSyncBroadcastAllAndFree(size, msg);
2491   }
2494 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2495   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2496   char *msg = (char*)CmiAlloc(size);
2497   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2498   values[0] = pe;
2499   values[1] = dataSize;
2500   CmiSetXHandler(msg, handlerIdx);
2501   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2502   if (CmiMyPe() == 0) {
2503     CmiReductionHandleDynamicRequest(msg);
2504   } else {
2505     /* send the request to processor 0 */
2506     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2507     CmiSyncSendAndFree(0, size, msg);
2508   }
2511 void CmiSendReduce(CmiReduction *red) {
2512   void *mergedData, *msg;
2513   int msg_size;
2514   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2515   mergedData = red->localData;
2516   msg_size = red->localSize;
2517   if (red->numChildren > 0) {
2518     int i, offset=0;
2519     if (red->ops.pupFn != NULL) {
2520       offset = CmiReservedHeaderSize;
2521       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2522     }
2523     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2524     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2525   }
2526   /*CpvAccess(_reduce_num_children) = 0;*/
2527   /*CpvAccess(_reduce_received) = 0;*/
2528   msg = mergedData;
2529   if (red->parent != -1) {
2530     if (red->ops.pupFn != NULL) {
2531       pup_er p = pup_new_sizer();
2532       (red->ops.pupFn)(p, mergedData);
2533       msg_size = pup_size(p) + CmiReservedHeaderSize;
2534       pup_destroy(p);
2535       msg = CmiAlloc(msg_size);
2536       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2537       (red->ops.pupFn)(p, mergedData);
2538       pup_destroy(p);
2539       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2540     }
2541     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2542     CmiSetRedID(msg, red->seqID);
2543     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2544     CmiSyncSendAndFree(red->parent, msg_size, msg);
2545   } else {
2546     (red->ops.destination)(msg);
2547   }
2548   CmiClearReduction(red->seqID);
2551 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2552   return data;
2555 void CmiResetGlobalReduceSeqID(void) {
2556         CpvAccess(_reduce_seqID_global) = 0;
2559 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2560   CmiAssert(red->localContributed == 0);
2561   red->localContributed = 1;
2562   red->localData = msg;
2563   red->localSize = size;
2564   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2565   red->parent = CmiSpanTreeParent(CmiMyPe());
2566   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2567   red->ops.mergeFn = mergeFn;
2568   red->ops.pupFn = NULL;
2569   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2570   CmiSendReduce(red);
2573 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2574                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2575                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2576   CmiAssert(red->localContributed == 0);
2577   red->localContributed = 1;
2578   red->localData = data;
2579   red->localSize = 0;
2580   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2581   red->parent = CmiSpanTreeParent(CmiMyPe());
2582   red->ops.destination = dest;
2583   red->ops.mergeFn = mergeFn;
2584   red->ops.pupFn = pupFn;
2585   red->ops.deleteFn = deleteFn;
2586   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2587   CmiSendReduce(red);
2590 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2591   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2592   CmiGlobalReduce(msg, size, mergeFn, red);
2595 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2596                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2597                      CmiReduceDeleteFn deleteFn) {
2598   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2599   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2602 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2603   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2604   CmiGlobalReduce(msg, size, mergeFn, red);
2607 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2608                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2609                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2610   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2611   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2614 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2615   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2616   int myPos;
2617   CmiAssert(red->localContributed == 0);
2618   red->localContributed = 1;
2619   red->localData = msg;
2620   red->localSize = size;
2621   for (myPos=0; myPos<npes; ++myPos) {
2622     if (pes[myPos] == CmiMyPe()) break;
2623   }
2624   CmiAssert(myPos < npes);
2625   red->numChildren = npes - (myPos << 2) - 1;
2626   if (red->numChildren > 4) red->numChildren = 4;
2627   if (red->numChildren < 0) red->numChildren = 0;
2628   if (myPos == 0) red->parent = -1;
2629   else red->parent = pes[(myPos - 1) >> 2];
2630   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2631   red->ops.mergeFn = mergeFn;
2632   red->ops.pupFn = NULL;
2633   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2634   CmiSendReduce(red);
2637 void CmiListReduceStruct(int npes, int *pes,
2638                      void *data, CmiReducePupFn pupFn,
2639                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2640                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2641   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2642   int myPos;
2643   CmiAssert(red->localContributed == 0);
2644   red->localContributed = 1;
2645   red->localData = data;
2646   red->localSize = 0;
2647   for (myPos=0; myPos<npes; ++myPos) {
2648     if (pes[myPos] == CmiMyPe()) break;
2649   }
2650   CmiAssert(myPos < npes);
2651   red->numChildren = npes - (myPos << 2) - 1;
2652   if (red->numChildren > 4) red->numChildren = 4;
2653   if (red->numChildren < 0) red->numChildren = 0;
2654   red->parent = (myPos - 1) >> 2;
2655   if (myPos == 0) red->parent = -1;
2656   red->ops.destination = dest;
2657   red->ops.mergeFn = mergeFn;
2658   red->ops.pupFn = pupFn;
2659   red->ops.deleteFn = deleteFn;
2660   CmiSendReduce(red);
2663 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2664   int npes, *pes;
2665   CmiLookupGroup(grp, &npes, &pes);
2666   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2669 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2670                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2671                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2672   int npes, *pes;
2673   CmiLookupGroup(grp, &npes, &pes);
2674   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2677 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2678   CmiAbort("Feel free to implement CmiNodeReduce...");
2679   /*
2680   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2681   CpvAccess(_reduce_data) = data;
2682   CpvAccess(_reduce_data_size) = size;
2683   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2684   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2685   _reduce_pupFn = NULL;
2686   _reduce_mergeFn = mergeFn;
2687   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2688   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2689   */
2691 #if 0
2692 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2693   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2694       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2696 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2697   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2699 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2700   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2701       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2703 #endif
2705 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2706                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2707                          CmiReduceDeleteFn deleteFn) {
2708   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2710   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2711   CpvAccess(_reduce_data) = data;
2712   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2713   _reduce_destination = dest;
2714   _reduce_pupFn = pupFn;
2715   _reduce_mergeFn = mergeFn;
2716   _reduce_deleteFn = deleteFn;
2717   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2718   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2719   */
2722 void CmiHandleReductionMessage(void *msg) {
2723   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2724   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2725   red->remoteData[red->numRemoteReceived++] = (char *)msg;
2726   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2727   CmiSendReduce(red);
2729   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2730   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2731   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2734 void CmiReductionsInit(void) {
2735   int i;
2736   CpvInitialize(int, CmiReductionMessageHandler);
2737   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2738   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2739   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2740   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2741   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2742   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2743   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2744   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2745   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2746   CpvInitialize(int, _reduce_info_size);
2747   CpvAccess(_reduce_info_size) = 4;
2748   CpvInitialize(CmiReduction**, _reduce_info);
2749   CpvAccess(_reduce_info) = (CmiReduction **)malloc(16*sizeof(CmiReduction*));
2750   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2753 /*****************************************************************************
2755  * Multicast groups
2757  ****************************************************************************/
2759 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2761 typedef struct GroupDef_s
2763   union {
2764     char core[CmiMsgHeaderSizeBytes];
2765     struct GroupDef_s *next;
2766   } core;
2767   CmiGroup group;
2768   int npes;
2769   int pes[1];
2771 *GroupDef;
2773 #define GROUPTAB_SIZE 101
2775 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2776 CpvStaticDeclare(int, CmiGroupCounter);
2777 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2779 void CmiGroupHandler(GroupDef def)
2781   /* receive group definition, insert into group table */
2782   GroupDef *table = CpvAccess(CmiGroupTable);
2783   unsigned int hashval, bucket;
2784   hashval = (def->group.id ^ def->group.pe);
2785   bucket = hashval % GROUPTAB_SIZE;
2786   def->core.next = table[bucket];
2787   table[bucket] = def;
2790 CmiGroup CmiEstablishGroup(int npes, int *pes)
2792   /* build new group definition, broadcast it */
2793   CmiGroup grp; GroupDef def; int len, i;
2794   grp.id = CpvAccess(CmiGroupCounter)++;
2795   grp.pe = CmiMyPe();
2796   len = sizeof(struct GroupDef_s)+(npes*sizeof(int));
2797   def = (GroupDef)CmiAlloc(len);
2798   def->group = grp;
2799   def->npes = npes;
2800   for (i=0; i<npes; i++)
2801     def->pes[i] = pes[i];
2802   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2803   CmiSyncBroadcastAllAndFree(len, def);
2804   return grp;
2807 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2809   unsigned int hashval, bucket;  GroupDef def;
2810   GroupDef *table = CpvAccess(CmiGroupTable);
2811   hashval = (grp.id ^ grp.pe);
2812   bucket = hashval % GROUPTAB_SIZE;
2813   for (def=table[bucket]; def; def=def->core.next) {
2814     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2815       *npes = def->npes;
2816       *pes = def->pes;
2817       return;
2818     }
2819   }
2820   *npes = 0; *pes = 0;
2823 void CmiGroupInit(void)
2825   CpvInitialize(int, CmiGroupHandlerIndex);
2826   CpvInitialize(int, CmiGroupCounter);
2827   CpvInitialize(GroupDef *, CmiGroupTable);
2828   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2829   CpvAccess(CmiGroupCounter) = 0;
2830   CpvAccess(CmiGroupTable) =
2831     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2832   if (CpvAccess(CmiGroupTable) == 0)
2833     CmiAbort("Memory Allocation Error");
2836 #endif
2838 /*****************************************************************************
2840  * Common List-Cast and Multicast Code
2842  ****************************************************************************/
2844 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2846 void CmiSyncListSendFn(int npes, const int *pes, int len, char *msg)
2848   int i;
2849 #if CMK_BROADCAST_USE_CMIREFERENCE
2850   for(i=0;i<npes;i++) {
2851     if (pes[i] == CmiMyPe())
2852       CmiSyncSend(pes[i], len, msg);
2853     else {
2854       CmiReference(msg);
2855       CmiSyncSendAndFree(pes[i], len, msg);
2856     }
2857   }
2858 #else
2859   for(i=0;i<npes;i++) {
2860     CmiSyncSend(pes[i], len, msg);
2861   }
2862 #endif
2865 CmiCommHandle CmiAsyncListSendFn(int npes, const int *pes, int len, char *msg)
2867   /* A better asynchronous implementation may be wanted, but at least it works */
2868   CmiSyncListSendFn(npes, pes, len, msg);
2869   return (CmiCommHandle) 0;
2872 void CmiFreeListSendFn(int npes, const int *pes, int len, char *msg)
2874 #if CMK_BROADCAST_USE_CMIREFERENCE
2875   if (npes == 1) {
2876     CmiSyncSendAndFree(pes[0], len, msg);
2877     return;
2878   }
2879   CmiSyncListSendFn(npes, pes, len, msg);
2880   CmiFree(msg);
2881 #else
2882   int i;
2883   for(i=0;i<npes-1;i++) {
2884     CmiSyncSend(pes[i], len, msg);
2885   }
2886   if (npes>0)
2887     CmiSyncSendAndFree(pes[npes-1], len, msg);
2888   else 
2889     CmiFree(msg);
2890 #endif
2893 #endif
2895 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2897 typedef struct MultiMsg_s
2899   char core[CmiMsgHeaderSizeBytes];
2900   CmiGroup group;
2901   int pos;
2902   int origlen;
2904 *MultiMsg;
2907 CpvDeclare(int, CmiMulticastHandlerIndex);
2909 void CmiMulticastDeliver(MultiMsg msg)
2911   int npes, *pes; int olen, nlen, pos, child1, child2;
2912   olen = msg->origlen;
2913   nlen = olen + sizeof(struct MultiMsg_s);
2914   CmiLookupGroup(msg->group, &npes, &pes);
2915   if (pes==0) {
2916     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2917     return;
2918   }
2919   if (npes==0) {
2920     CmiFree(msg);
2921     return;
2922   }
2923   if (msg->pos == -1) {
2924     msg->pos=0;
2925     CmiSyncSendAndFree(pes[0], nlen, msg);
2926     return;
2927   }
2928   pos = msg->pos;
2929   child1 = ((pos+1)<<1);
2930   child2 = child1-1;
2931   if (child1 < npes) {
2932     msg->pos = child1;
2933     CmiSyncSend(pes[child1], nlen, msg);
2934   }
2935   if (child2 < npes) {
2936     msg->pos = child2;
2937     CmiSyncSend(pes[child2], nlen, msg);
2938   }
2939   if(olen < sizeof(struct MultiMsg_s)) {
2940     memcpy(msg, msg+1, olen);
2941   } else {
2942     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg_s));
2943   }
2944   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2947 void CmiMulticastHandler(MultiMsg msg)
2949   CmiMulticastDeliver(msg);
2952 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2954   int newlen; MultiMsg newmsg;
2955   newlen = len + sizeof(struct MultiMsg_s);
2956   newmsg = (MultiMsg)CmiAlloc(newlen);
2957   if(len < sizeof(struct MultiMsg_s)) {
2958     memcpy(newmsg+1, msg, len);
2959   } else {
2960     memcpy(newmsg+1, msg+sizeof(struct MultiMsg_s), len-sizeof(struct MultiMsg_s));
2961     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg_s));
2962   }
2963   newmsg->group = grp;
2964   newmsg->origlen = len;
2965   newmsg->pos = -1;
2966   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2967   CmiMulticastDeliver(newmsg);
2970 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2972   CmiSyncMulticastFn(grp, len, msg);
2973   CmiFree(msg);
2976 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2978   CmiError("Async Multicast not implemented.");
2979   return (CmiCommHandle) 0;
2982 void CmiMulticastInit(void)
2984   CpvInitialize(int, CmiMulticastHandlerIndex);
2985   CpvAccess(CmiMulticastHandlerIndex) =
2986     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2989 #else
2990 extern void CmiMulticastInit(void);
2991 #endif
2993 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2994 extern void *arena_malloc(int size);
2995 extern void arena_free(void *blockPtr);
2996 #endif
2998 /***************************************************************************
3000  * Memory Allocation routines 
3002  * A block of memory can consist of multiple chunks.  Each chunk has
3003  * a sizefield and a refcount.  The first chunk's refcount is a reference
3004  * count.  That's how many CmiFrees it takes to free the message.
3005  * Subsequent chunks have a refcount which is less than zero.  This is
3006  * the offset back to the start of the first chunk.
3008  * Each chunk has a CmiChunkHeader before the user data, with the fields:
3010  *  size: The user-allocated size of the chunk, in bytes.
3012  *  ref: A magic reference count object. Ordinary blocks start with
3013  *     reference count 1.  When the reference count reaches zero,
3014  *     the block is deleted.  To support nested buffers, the 
3015  *     reference count can also be negative, which means it is 
3016  *     a byte offset to the enclosing buffer's reference count.
3018  ***************************************************************************/
3021 void *CmiAlloc(int size)
3024   char *res;
3026 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3027   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
3028 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3029   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3030 #elif CMK_CONVERSE_UGNI || CMK_OFI
3031   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
3032 #elif CONVERSE_POOL
3033   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
3034 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3035   MPI_Alloc_mem(size+sizeof(CmiChunkHeader), MPI_INFO_NULL, &res);
3036 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3037   res = (char *) CmiAlloc_bgq(size+sizeof(CmiChunkHeader));
3038 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3039   res = (char *) CmiAlloc_ppcq(size+sizeof(CmiChunkHeader));
3040 #else
3041   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3042 #endif
3044   _MEMCHECK(res);
3046 #ifdef MEMMONITOR
3047   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
3048   CpvAccess(AllocCount)++;
3049   CpvAccess(BlocksAllocated)++;
3050   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
3051     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
3052   }
3053   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
3054     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3055             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3056             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3057     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
3058   }
3059   if ((CpvAccess(AllocCount) % 1000) == 0) {
3060     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
3061             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
3062             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
3063   }
3064 #endif
3066   res+=sizeof(CmiChunkHeader);
3067   CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3069   CmiInitMsgHeader(res, size);
3071   SIZEFIELD(res)=size;
3072   REFFIELDSET(res, 1);
3073   return (void *)res;
3076 void *CmiRdmaAlloc(int size) {
3077   char *res;
3079 #if CMK_CONVERSE_UGNI
3080   res = (char *)LrtsRdmaAlloc(size, sizeof(CmiChunkHeader));
3081 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3082   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
3083 #elif CMK_OFI
3084   res = (char *)LrtsAlloc(size, sizeof(CmiChunkHeader));
3085 #else
3086   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
3087 #endif
3089   _MEMCHECK(res);
3090   res+=sizeof(CmiChunkHeader);
3091   CmiAssert((intptr_t)res % ALIGN_BYTES == 0);
3093   CmiInitMsgHeader(res, size);
3094   SIZEFIELD(res)=size;
3095   REFFIELDSET(res, 1);
3096   return (void *)res;
3100 /** Follow the header links out to the most enclosing block */
3101 static void *CmiAllocFindEnclosing(void *blk) {
3102   int refCount = REFFIELD(blk);
3103   while (refCount < 0) {
3104     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
3105     refCount = REFFIELD(blk);
3106   }
3107   return blk;
3110 void CmiInitMsgHeader(void *msg, int size) {
3111 #if CMK_ONESIDED_IMPL
3112   // Set zcMsgType in the converse message header to CMK_REG_NO_ZC_MSG
3113   if(size >= CmiMsgHeaderSizeBytes)
3114     CMI_ZC_MSGTYPE(msg) = CMK_REG_NO_ZC_MSG;
3115 #endif
3118 int CmiGetReference(void *blk)
3120   return REFFIELD(CmiAllocFindEnclosing(blk));
3123 /** Increment the reference count for this block's owner.
3124     This call must be matched by an equivalent CmiFree. */
3125 void CmiReference(void *blk)
3127   REFFIELDINC(CmiAllocFindEnclosing(blk));
3130 /** Return the size of the user portion of this block. */
3131 int CmiSize(void *blk)
3133   return SIZEFIELD(blk);
3136 /** Decrement the reference count for this block. */
3137 void CmiFree(void *blk)
3139   void *parentBlk=CmiAllocFindEnclosing(blk);
3140   int refCount=REFFIELDDEC(parentBlk);
3141 #if CMK_ERROR_CHECKING
3142   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3143     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
3144 #endif
3145   if(refCount==1) { /* This was the last reference to the block-- free it */
3146 #ifdef MEMMONITOR
3147     int size=SIZEFIELD(parentBlk);
3148     if (size > 1000000000) /* Absurdly large size field-- warning */
3149       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3150     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3151     CpvAccess(BlocksAllocated)--;
3152 #endif
3154 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
3155     arena_free(BLKSTART(parentBlk));
3156 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
3157     /* is this message the head of a MultipleSend that we received?
3158        Then the parts with INFIMULTIPOOL have metadata which must be 
3159        unregistered and freed.  */
3160 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
3161     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
3162       {
3163         infi_freeMultipleSend(parentBlk);
3164       }
3165 #endif
3166     infi_CmiFree(BLKSTART(parentBlk));
3167 #elif CMK_CONVERSE_UGNI || CMK_OFI
3168     LrtsFree(BLKSTART(parentBlk));
3169 #elif CONVERSE_POOL
3170     CmiPoolFree(BLKSTART(parentBlk));
3171 #elif USE_MPI_CTRLMSG_SCHEME && CMK_CONVERSE_MPI
3172     MPI_Free_mem(parentBlk);
3173 #elif CMK_SMP && CMK_BLUEGENEQ && SPECIFIC_PCQUEUE
3174     CmiFree_bgq(BLKSTART(parentBlk));
3175 #elif CMK_SMP && CMK_PPC_ATOMIC_QUEUE
3176     CmiFree_ppcq(BLKSTART(parentBlk));
3177 #else
3178     free_nomigrate(BLKSTART(parentBlk));
3179 #endif
3180   }
3183 void CmiRdmaFree(void *blk)
3185   void *parentBlk=CmiAllocFindEnclosing(blk);
3186   int refCount=REFFIELDDEC(parentBlk);
3187 #if CMK_ERROR_CHECKING
3188   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
3189     CmiAbort("CmiRdmaFree reference count was zero-- is this a duplicate free?");
3190 #endif
3191   if(refCount==1) { /* This was the last reference to the block-- free it */
3192 #ifdef MEMMONITOR
3193     int size=SIZEFIELD(parentBlk);
3194     if (size > 1000000000) /* Absurdly large size field-- warning */
3195       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
3196     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
3197     CpvAccess(BlocksAllocated)--;
3198 #endif
3200 #if CMK_CONVERSE_UGNI
3201     LrtsRdmaFree(BLKSTART(parentBlk));
3202 #elif CMK_USE_IBVERBS || CMK_USE_IBUD
3203     infi_CmiFree(BLKSTART(parentBlk));
3204 #elif CMK_OFI
3205     LrtsFree(BLKSTART(parentBlk));
3206 #else
3207     free_nomigrate(BLKSTART(parentBlk));
3208 #endif
3209   }
3213 /***************************************************************************
3215  * Temporary-memory Allocation routines 
3217  *  This buffer augments the storage available on the regular machine stack
3218  * for fairly large temporary buffers, which allows us to use smaller machine
3219  * stacks.
3221  ***************************************************************************/
3223 #define CMI_TMP_BUF_MAX 16*1024 /* Allow this much temporary storage. */
3225 typedef struct {
3226   char *buf; /* Start of temporary buffer */
3227   int cur; /* First unused location in temporary buffer */
3228   int max; /* Length of temporary buffer */
3229 } CmiTmpBuf_t;
3230 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
3232 static void CmiTmpSetup(CmiTmpBuf_t *b) {
3233   b->buf=(char *)malloc(CMI_TMP_BUF_MAX);
3234   b->cur=0;
3235   b->max=CMI_TMP_BUF_MAX;
3238 void *CmiTmpAlloc(int size) {
3239   if (!CpvInitialized(CmiTmpBuf)) {
3240     return malloc(size);
3241   }
3242   else { /* regular case */
3243     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3244     void *t;
3245     if (b->cur+size>b->max) {
3246       if (b->max==0) /* We're just uninitialized */
3247         CmiTmpSetup(b);
3248       else /* We're really out of space! */
3249         return malloc(size);
3250     }
3251     t=b->buf+b->cur;
3252     b->cur+=size;
3253     return t;
3254   }
3256 void CmiTmpFree(void *t) {
3257   if (!CpvInitialized(CmiTmpBuf)) {
3258     free(t);
3259   }
3260   else { /* regular case */
3261     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
3262     /* t should point into our temporary buffer: figure out where */
3263     int cur=((const char *)t)-b->buf;
3264     if (cur<0 || cur>b->max) {
3265       free(t);
3266     } else {
3267       b->cur=cur;
3268     }
3269   }
3272 void CmiTmpInit(char **argv) {
3273   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
3274   /* Set up this processor's temporary buffer */
3275   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
3278 /******************************************************************************
3280   Cross-platform directory creation
3282   ****************************************************************************/
3283 #ifdef _WIN32
3284 /* Windows directory creation: */
3285 #include <windows.h>
3287 void CmiMkdir(const char *dirName) {
3288         CreateDirectory(dirName,NULL);
3291 int CmiGetPageSize(void)
3293   SYSTEM_INFO system_info;
3294   GetSystemInfo(&system_info);
3295   return system_info.dwPageSize;
3297 #else
3298 /* UNIX directory creation */
3299 #include <unistd.h> 
3300 #include <sys/stat.h> /* from "mkdir" man page */
3301 #include <sys/types.h>
3303 void CmiMkdir(const char *dirName) {
3304         mkdir(dirName,0777);
3307 int CmiGetPageSize(void)
3309 #if CMK_HAS_GETPAGESIZE
3310   return getpagesize();
3311 #else
3312   return CMK_MEMORY_PAGESIZE;
3313 #endif
3316 #endif
3319 /******************************************************************************
3321   Multiple Send function                               
3323   ****************************************************************************/
3329 /****************************************************************************
3330 * DESCRIPTION : This function call allows the user to send multiple messages
3331 *               from one processor to another, all intended for differnet 
3332 *               handlers.
3334 *               Parameters :
3336 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3338 ****************************************************************************/
3339 /* Round up message size to the message granularity. 
3340    Does this by adding, then truncating.
3342 static int roundUpSize(unsigned int s) {
3343   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3345 /* Return the amount of message padding required for a message
3346    with this many user bytes. 
3347  */
3348 static int paddingSize(unsigned int s) {
3349   return roundUpSize(s)-s;
3352 /* Message header for a bundle of multiple-sent messages */
3353 typedef struct {
3354   char convHeader[CmiMsgHeaderSizeBytes];
3355   int nMessages; /* Number of distinct messages bundled below. */
3356   double pad; /* To align the first message, which follows this header */
3357 } CmiMultipleSendHeader;
3359 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3360 /* given a pointer to a multisend message clean up the metadata */
3362 void infi_freeMultipleSend(void *msgWhole)
3364   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3365   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3366   int offset=sizeof(CmiMultipleSendHeader);
3367   int m;
3368   void *thisMsg=NULL;
3369   if (pad != 1234567.89) return;
3370   for(m=0;m<len;m++)
3371     {
3372       /*unreg meta, free meta, move the ptr */
3373       /* note these weird little things are not pooled */
3374       /* do NOT free the message here, we are only a part of this buffer*/
3375       infiCmiChunkHeader *ch = (infiCmiChunkHeader *)((char *)msgWhole + offset);
3376       char *msg = (char *)msgWhole + offset + sizeof(infiCmiChunkHeader);
3377       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3378       infi_unregAndFreeMeta(ch->metaData);
3379       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3380     }
3382 #endif
3385 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3387   CmiMultipleSendHeader header;
3388   int m; /* Outgoing message */
3390   CmiInitMsgHeader(header.convHeader, sizeof(CmiMultipleSendHeader));
3391 #if CMK_USE_IBVERBS
3392   infiCmiChunkHeader *msgHdr;
3393 #else
3394   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3395 #endif
3396         
3397   double pad = 0; /* padding required */
3398   int vecLen; /* Number of pieces in outgoing message vector */
3399   int *vecSizes; /* Sizes of each piece we're sending out. */
3400   char **vecPtrs; /* Pointers to each piece we're sending out. */
3401   int vec; /* Entry we're currently filling out in above array */
3402         
3403 #if CMK_USE_IBVERBS
3404   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3405 #else
3406   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3407 #endif
3408         
3409   /* Allocate memory for the outgoing vector*/
3410   vecLen=1+3*len; /* Header and 3 parts per message */
3411   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3412   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3413   vec=0;
3414   
3415   /* Build the header */
3416   header.nMessages=len;
3417   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3418   header.pad = 1234567.89;
3419 #if CMK_IMMEDIATE_MSG
3420   if (immed) CmiBecomeImmediate(&header);
3421 #endif
3422   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3423   vec++;
3425   /* Build an entry for each message: 
3426          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3427   */
3428   for (m=0;m<len;m++) {
3429 #if CMK_USE_IBVERBS
3430     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3431     msgHdr[m].chunkHeader.setRef(0); /* Reference count will be filled out on receive side */
3432     msgHdr[m].metaData=NULL;
3433 #else
3434     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3435     msgHdr[m].setRef(0); /* Reference count will be filled out on receive side */
3436 #endif          
3437     
3438     /* First send the message's CmiChunkHeader (for use on receive side) */
3439 #if CMK_USE_IBVERBS
3440     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3441 #else
3442     vecSizes[vec]=sizeof(CmiChunkHeader); 
3443 #endif          
3444                 vecPtrs[vec]=(char *)&msgHdr[m];
3445     vec++;
3446     
3447     /* Now send the actual message data */
3448     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3449     vec++;
3450     
3451     /* Now send padding to align the next message on a double-boundary */
3452     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3453     vec++;
3454   }
3455   CmiAssert(vec==vecLen);
3456   
3457   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3458   
3459   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3460   CmiTmpFree(vecSizes);
3461   CmiTmpFree(msgHdr);
3464 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3466   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3469 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3471   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3474 /****************************************************************************
3475 * DESCRIPTION : This function initializes the main handler required for the
3476 *               CmiMultipleSend() function to work. 
3477 *               
3478 *               This function should be called once in any Converse program
3479 *               that uses CmiMultipleSend()
3481 ****************************************************************************/
3483 static void CmiMultiMsgHandler(char *msgWhole);
3485 void CmiInitMultipleSend(void)
3487   CpvInitialize(int,CmiMainHandlerIDP); 
3488   CpvAccess(CmiMainHandlerIDP) =
3489     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3492 /****************************************************************************
3493 * DESCRIPTION : This function is the main handler that splits up the messages
3494 *               CmiMultipleSend() pastes together. 
3496 ****************************************************************************/
3498 static void CmiMultiMsgHandler(char *msgWhole)
3500   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3501   int offset=sizeof(CmiMultipleSendHeader);
3502   int m;
3503   for (m=0;m<len;m++) {
3504 #if CMK_USE_IBVERBS
3505     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3506     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3507     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3508     ch->chunkHeader.setRef(msgWhole-msg);
3509     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3510 #else
3511     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3512     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3513     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3514     ch->setRef(msgWhole-msg);
3515 #endif          
3516     /* Link new message to owner via a negative ref pointer */
3517     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3518     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3519 #if CMK_USE_IBVERBS
3520     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3521 #else
3522     offset+= sizeof(CmiChunkHeader) + msgSize;
3523 #endif          
3524   }
3525   /* Release our reference to the whole message.  The message will
3526      only actually be deleted once all its sub-messages are free'd as well. */
3527   CmiFree(msgWhole);
3530 /****************************************************************************
3531 * Hypercube broadcast message passing.
3532 ****************************************************************************/
3534 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3535   int num_pes = 0;
3536   for ( ; k>=0; --k) {
3537     /* add the processor destination at level k if it exist */
3538     dest_pes[num_pes] = mype ^ (1<<k);
3539     if (dest_pes[num_pes] >= total_pes) {
3540       /* find the first proc in the other part of the current dimention */
3541       dest_pes[num_pes] &= (~0u)<<k;
3542       /* if the first proc there is over CmiNumPes() then there is no other
3543          dimension, otherwise if it is valid compute my correspondent in such
3544          a way to minimize the load for every processor */
3545       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((~0u)<<k))) % (total_pes - dest_pes[num_pes]);
3546       }
3547     if (dest_pes[num_pes] < total_pes) {
3548       /* if the destination is in the acceptable range increment num_pes */
3549       ++num_pes;
3550     }
3551   }
3552   return num_pes;
3556 /****************************************************************************
3557 * DESCRIPTION : This function initializes the main handler required for the
3558 *               Immediate message
3559 *               
3560 *               This function should be called once in any Converse program
3562 ****************************************************************************/
3564 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3565 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3567 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3569 /* xdl is the real handler */
3570 static void CmiImmediateMsgHandler(char *msg)
3572   CmiSetHandler(msg, CmiGetXHandler(msg));
3573   CmiHandleMessage(msg);
3576 void CmiInitImmediateMsg(void)
3578   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3579   CpvAccess(CmiImmediateMsgHandlerIdx) =
3580     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3583 /*#if !CMK_IMMEDIATE_MSG
3584 #if !CMK_MACHINE_PROGRESS_DEFINED
3585 void CmiProbeImmediateMsg()
3588 #endif
3589 #endif*/
3591 /******** Idle timeout module (+idletimeout=30) *********/
3593 typedef struct {
3594   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3595   int is_idle;/*Boolean currently-idle flag*/
3596   int call_count;/*Number of timeout calls currently in flight*/
3597 } cmi_cpu_idlerec;
3599 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3601   rec->call_count--;
3602   if(rec->call_count==0 && rec->is_idle==1) {
3603     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3604     CmiAbort("Exiting.\n");
3605   }
3607 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3609   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3610   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3611   rec->is_idle = 1;
3613 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3615   rec->is_idle = 0;
3617 static void CIdleTimeoutInit(char **argv)
3619   int idle_timeout=0; /*Seconds to wait*/
3620   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3621   if(idle_timeout != 0) {
3622     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3623     _MEMCHECK(rec);
3624     rec->idle_timeout=idle_timeout*1000;
3625     rec->is_idle=0;
3626     rec->call_count=0;
3627     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3628     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3629   }
3632 /*****************************************************************************
3634  * Converse Initialization
3636  *****************************************************************************/
3638 void CrnInit(void);
3639 void CmiIsomallocInit(char **argv);
3640 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3641 void CmiIOInit(char **argv);
3642 #endif
3644 /* defined in cpuaffinity.C */
3645 void CmiInitCPUAffinityUtil(void);
3647 static void CmiProcessPriority(char **argv)
3649   int dummy, nicelevel=-100;      /* process priority */
3650   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3651   /* ignore others */
3652   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3653   /* call setpriority once on each process to set process's priority */
3654   if (CmiMyRank() == 0 && nicelevel != -100)  {
3655 #ifndef _WIN32
3656     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3657       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3658       perror("setpriority");
3659       CmiAbort("setpriority failed.");
3660     }
3661     else
3662       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3663 #else
3664     HANDLE hProcess = GetCurrentProcess();
3665     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3666     const char *prio_str = "NORMAL_PRIORITY_CLASS";
3667     BOOL status;
3668     /*
3669        <-20:      real time
3670        -20--10:   high 
3671        -10-0:     above normal
3672        0:         normal
3673        0-10:      below normal
3674        10-:       idle
3675     */
3676     if (0) ;
3677 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3678     else if (nicelevel<10 && nicelevel>0) {
3679       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3680       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3681     }
3682 #endif
3683     else if (nicelevel>0) {
3684       dwPriorityClass = IDLE_PRIORITY_CLASS;
3685       prio_str = "IDLE_PRIORITY_CLASS";
3686     }
3687     else if (nicelevel<=-20) {
3688       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3689       prio_str = "REALTIME_PRIORITY_CLASS";
3690     }
3691 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3692     else if (nicelevel>-10 && nicelevel<0) {
3693       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3694       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3695     }
3696 #endif
3697     else if (nicelevel<0) {
3698       dwPriorityClass = HIGH_PRIORITY_CLASS;
3699       prio_str = "HIGH_PRIORITY_CLASS";
3700     }
3701     status = SetPriorityClass(hProcess, dwPriorityClass);
3702     if (!status)  {
3703         int err=GetLastError();
3704         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3705         CmiAbort("SetPriorityClass failed.");
3706     }
3707     else
3708       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3709 #endif
3710   }
3713 void CommunicationServerInit(void)
3715 #if CMK_IMMEDIATE_MSG
3716 #if CMI_QD
3717   CQdCpvInit();
3718 #endif
3719   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3720 #endif
3724 static int testEndian(void)
3726         int test=0x1c;
3727         unsigned char *c=(unsigned char *)&test;
3728         if (c[sizeof(int)-1]==0x1c)
3729                 /* Macintosh and most workstations are big-endian */
3730                 return 1;   /* Big-endian machine */
3731         if (c[0]==0x1c)
3732                 /* Intel x86 PC's, and DEC VAX are little-endian */
3733                 return 0;  /* Little-endian machine */
3734         return -2;  /*Unknown integer type */
3737 int CmiEndianness(void)
3739   static int _cmi_endianness = -1;
3740   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3741   CmiAssert(_cmi_endianness != -2);
3742   return  _cmi_endianness;
3745 #if CMK_USE_TSAN
3746 /* This fixes bug #713, which is caused by tsan deadlocking inside
3747  * a 'write' syscall inside a mutex. */
3748 static void checkTSanOptions(void)
3750   char *env = getenv("TSAN_OPTIONS");
3752   if (!env ||
3753       !strstr(env, "log_path=") ||
3754       strstr(env, "log_path=stdout") ||
3755       strstr(env, "log_path=stderr")) {
3756     CmiAbort("TSAN output must be redirected to disk.\n"
3757              "Run this program with TSAN_OPTIONS=\"log_path=filename\"");
3758   }
3760 #endif
3762 #if CMK_CCS_AVAILABLE
3763 extern int ccsRunning;
3764 int ccsRunning;
3765 #endif
3767 extern int quietModeRequested;
3768 int quietModeRequested;  // user has requested quiet mode
3769 extern int quietMode;
3770 int quietMode; // quiet mode active (CmiPrintf's are disabled)
3771 CmiSpanningTreeInfo* _topoTree = NULL;
3774   Main Converse initialization routine.  This routine is 
3775   called by the machine file (machine.C) to set up Converse.
3776   It's "Common" because it's shared by all the machine.C files.
3777   
3778   The main task of this routine is to set up all the Cpv's
3779   (message queues, handler tables, etc.) used during main execution.
3780   
3781   On SMP versions, this initialization routine is called by 
3782   *all* processors of a node simultaniously.  It's *also* called
3783   by the communication thread, which is rather strange but needed
3784   for immediate messages.  Each call to this routine expects a 
3785   different copy of the argv arguments, so use CmiCopyArgs(argv).
3786   
3787   Requires:
3788     - A working network layer.
3789     - Working Cpv's and CmiNodeBarrier.
3790     - CthInit to already have been called.  CthInit is called
3791       from the machine layer directly, because some machine layers
3792       (like uth) use Converse threads internally.
3794   Initialization is somewhat subtle, in that various modules
3795   won't work properly until they're initialized.  For example,
3796   nobody can register handlers before calling CmiHandlerInit.
3798 void ConverseCommonInit(char **argv)
3800   CpvInitialize(int, _urgentSend);
3801   CpvAccess(_urgentSend) = 0;
3802   CpvInitialize(int,interopExitFlag);
3803   CpvAccess(interopExitFlag) = 0;
3805   CpvInitialize(int,_curRestartPhase);
3806   CpvAccess(_curRestartPhase)=1;
3807   CmiArgInit(argv);
3808   CmiMemoryInit(argv);
3809 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3810   CmiIOInit(argv);
3811 #endif
3812   if (CmiMyPe() == 0)
3813       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3815   CpvInitialize(int, cmiMyPeIdle);
3816   CpvAccess(cmiMyPeIdle) = 0;
3818 #if CONVERSE_POOL
3819   CmiPoolAllocInit(30);  
3820 #endif
3821   CmiTmpInit(argv);
3822   CmiTimerInit(argv);
3823   CstatsInit(argv);
3824   CmiInitCPUAffinityUtil();
3826   CcdModuleInit(argv);
3827   CmiHandlerInit();
3828   CmiReductionsInit();
3829   CIdleTimeoutInit(argv);
3830   
3831 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the netlrts-*-smp and multicore versions*/
3832   if(CmiGetArgFlagDesc(argv, "+CmiSpinOnIdle", "Force the runtime system to spin on message reception when idle, rather than sleeping")) {
3833     if(CmiMyRank() == 0) _Cmi_forceSpinOnIdle = 1;
3834   }
3835   if(CmiGetArgFlagDesc(argv, "+CmiSleepOnIdle", "Force the runtime system to sleep when idle, rather than spinning on message reception")) {
3836     if(CmiMyRank() == 0) _Cmi_sleepOnIdle = 1;
3837   }
3838   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for netlrts-smp-*) ?")){
3839     if (CmiMyPe() == 0) {
3840       CmiPrintf("Charm++> Note: The option +CmiNoProcForComThread has been superseded by +CmiSleepOnIdle\n");
3841     }
3842     if(CmiMyRank() == 0) _Cmi_sleepOnIdle=1;
3843   }
3844   if (_Cmi_sleepOnIdle && _Cmi_forceSpinOnIdle) {
3845     if(CmiMyRank() == 0) CmiAbort("The option +CmiSpinOnIdle is mutually exclusive with the options +CmiSleepOnIdle and +CmiNoProcForComThread");
3846   }
3847 #endif
3848         
3849 #if CMK_TRACE_ENABLED
3850   traceInit(argv);
3851 /*initTraceCore(argv);*/ /* projector */
3852 #endif
3853   CmiProcessPriority(argv);
3855 #if CMK_USE_TSAN
3856   checkTSanOptions();
3857 #endif
3859   CmiPersistentInit();
3860   CmiIsomallocInit(argv);
3861   // Initialize converse handlers for supporting generic Direct Nocopy API
3862   CmiOnesidedDirectInit();
3863   CmiDeliversInit();
3864   CsdInit(argv);
3865 #if CMK_CCS_AVAILABLE
3866   ccsRunning = 0;
3867   CcsInit(argv);
3868 #endif
3869   CpdInit();
3870   CthSchedInit();
3871   CmiGroupInit();
3872   CmiMulticastInit();
3873   CmiInitMultipleSend();
3874 #if CMI_QD
3875   CQdInit();
3876 #endif
3878   CrnInit();
3879   CmiInitImmediateMsg();
3880   CldModuleInit(argv);
3881   
3882 #if CMK_CELL
3883   void CmiInitCell();
3884   CmiInitCell();
3885 #endif
3887   /* main thread is suspendable */
3889   CthSetSuspendable(CthSelf(), 0);
3892 #if CMK_BIGSIM_CHARM
3893    /* have to initialize QD here instead of _initCharm */
3894   initQd(argv);
3895 #endif
3898 void ConverseCommonExit(void)
3900   CcsImpl_kill();
3902 #if CMK_TRACE_ENABLED
3903   traceClose();
3904 /*closeTraceCore();*/ /* projector */
3905 #endif
3907 #if CMI_IO_BUFFER_EXPLICIT
3908   CmiFlush(stdout);  /* end of program, always flush */
3909 #endif
3911 #if CMK_CELL
3912   CloseOffloadAPI();
3913 #endif
3915 #if CMK_CUDA
3916   // ensure all PEs have finished GPU work before destructing
3917   if(CmiMyRank() < CmiMyNodeSize()) {
3918     CmiNodeBarrier();
3919   }
3920   if (CmiMyRank() == 0) {
3921     exitHybridAPI();
3922   }
3923 #endif
3924   seedBalancerExit();
3925   EmergencyExit();
3929 #if CMK_CELL != 0
3931 extern void register_accel_spe_funcs(void);
3933 void CmiInitCell(void)
3935   // Create a unique string for each PPE to use for the timing
3936   //   data file's name
3937   char fileNameBuf[64];
3938   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3940   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3941   //CcdCallOnConditionKeep(CcdPERIODIC, 
3942   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3943   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3944       (CcdVoidFn) OffloadAPIProgress, NULL);
3946   // Register accelerated entry methods on the PPE
3947   register_accel_spe_funcs();
3950 #include "cell-api.c"
3952 #endif
3954 /****
3955  * CW Lee - 9/14/2005
3956  * Added a mechanism to allow some control over machines with extremely
3957  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3958  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3959  * coupled with a default setup using unbuffered stdout introduced
3960  * severe overheads (and hence limiting scaling) for applications like 
3961  * NAMD.
3962  */
3963 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3964 void CmiIOInit(char **argv) {
3965   CpvInitialize(int, expIOFlushFlag);
3966 #if CMI_IO_BUFFER_EXPLICIT
3967   /* 
3968      Support for an explicit buffer only makes sense if the machine
3969      layer does not wish to make its own implementation.
3971      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3972      MUST NOT make use of stdout if an explicit buffer is requested.
3974      The setvbuf function may only be used after opening a stream and
3975      before any other operations have been performed on it
3976   */
3977   CpvInitialize(char*, explicitIOBuffer);
3978   CpvInitialize(int, expIOBufferSize);
3979   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3980                         "Explicit IO Buffer Size")) {
3981     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3982   }
3983   if (CpvAccess(expIOBufferSize) <= 0) {
3984     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3985   }
3986   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3987                                                 sizeof(char));
3988   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
3989               CpvAccess(expIOBufferSize))) {
3990     CmiAbort("Explicit IO Buffering failed\n");
3991   }
3992 #endif
3993 #if CMI_IO_FLUSH_USER
3994   /* system default to have user control flushing of IO */
3995   /* Now look for user override */
3996   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
3997                                                  "System Controls IO Flush");
3998 #else
3999   /* system default to have system handle IO flushing */
4000   /* Now look for user override */
4001   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
4002                                                 "User Controls IO Flush");
4003 #endif
4005 #endif
4007 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
4009 void CmiPrintf(const char *format, ...)
4011   if (quietMode) return;
4012   CpdSystemEnter();
4013   {
4014   va_list args;
4015   va_start(args,format);
4016   vfprintf(stdout,format, args);
4017   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
4018     CmiFlush(stdout);
4019   }
4020   va_end(args);
4021 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4022   if (CpvAccess(cmiArgDebugFlag)) {
4023     va_start(args,format);
4024     print_node0(format, args);
4025     va_end(args);
4026   }
4027 #endif
4028   }
4029   CpdSystemExit();
4032 void CmiError(const char *format, ...)
4034   CpdSystemEnter();
4035   {
4036   va_list args;
4037   va_start(args,format);
4038   vfprintf(stderr,format, args);
4039   CmiFlush(stderr);  /* stderr is always flushed */
4040   va_end(args);
4041 #if CMK_CCS_AVAILABLE && CMK_CMIPRINTF_IS_A_BUILTIN
4042   if (CpvAccess(cmiArgDebugFlag)) {
4043     va_start(args,format);
4044     print_node0(format, args);
4045     va_end(args);
4046   }
4047 #endif
4048   }
4049   CpdSystemExit();
4052 #endif
4054 void __cmi_assert(const char *errmsg)
4056   CmiError("[%d] %s\n", CmiMyPe(), errmsg);
4057   CmiAbort(errmsg);
4060 char *CmiCopyMsg(char *msg, int len)
4062   char *copy = (char *)CmiAlloc(len);
4063   _MEMCHECK(copy);
4064   memcpy(copy, msg, len);
4065   return copy;
4068 unsigned char computeCheckSum(unsigned char *data, int len)
4070   int i;
4071   unsigned char ret = 0;
4072   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
4073   return ret;
4076 /* Flag for bigsim's out-of-core emulation */
4077 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
4078 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
4080 #if !CMK_HAS_LOG2
4081 unsigned int CmiILog2(unsigned int val) {
4082   unsigned int log = 0u;
4083   if ( val != 0u ) {
4084       while ( val > (1u<<log) ) { log++; }
4085   }
4086   return log;
4088 double CmiLog2(double x) {
4089   return log(x)/log(2);
4091 #endif
4093 /* for bigsim */
4094 int CmiMyRank_(void)
4096   return CmiMyRank();
4099 double CmiReadSize(const char *str)
4101     double val;
4102     if (strpbrk(str,"Gg")) {
4103         //sscanf(str, "%llf", &val);
4104         //val = strtod(str, &p);
4105         val = atof(str);
4106         val *= 1024ll*1024*1024;
4107     }
4108     else if (strpbrk(str,"Mm")) {
4109         val = atof(str);
4110         val *= 1024*1024;
4111     }
4112     else if (strpbrk(str,"Kk")) {
4113         val = atof(str);
4114         val *= 1024;
4115     }
4116     else {
4117         val = atof(str);
4118     }
4119     return val;
4122 void CmiSetPeHelpsOtherThreads(int input) {
4123   CpvAccess(isHelperOn) = input;
4124   CmiMemoryWriteFence();
4127 /*@}*/