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