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