0c79cbf0f63fc055a2cc6fb65569cff1ed58965d
[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 CpvDeclare(int,interOperate);
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     if(CpvAccess(interOperate)) {
1798       if(CpvAccess(charmLibExitFlag)) {
1799         CpvAccess(charmLibExitFlag) = 0;
1800         break;
1801       }
1802     }
1803     msg = CsdNextMessage(&state);
1804     if (msg!=NULL) { /*A message is available-- process it*/
1805       if (isIdle) {isIdle=0;CsdEndIdle();}
1806       SCHEDULE_MESSAGE
1807
1808       #if CMK_CELL
1809         if (progressCount <= 0) {
1810           /*OffloadAPIProgress();*/
1811           machine_OffloadAPIProgress();
1812           progressCount = CMK_CELL_PROGRESS_FREQ;
1813         }
1814         progressCount--;
1815       #endif
1816
1817       #ifdef CMK_CUDA
1818         if (cudaProgressCount == 0) {
1819           gpuProgressFn(); 
1820           cudaProgressCount = CMK_CUDA_PROGRESS_FREQ; 
1821         }
1822         cudaProgressCount--; 
1823       #endif
1824
1825     } else { /*No message available-- go (or remain) idle*/
1826       SCHEDULE_IDLE
1827
1828       #if CMK_CELL
1829         /*OffloadAPIProgress();*/
1830         machine_OffloadAPIProgress();
1831         progressCount = CMK_CELL_PROGRESS_FREQ;
1832       #endif
1833
1834       #ifdef CMK_CUDA
1835         gpuProgressFn(); 
1836         cudaProgressCount = CMK_CUDA_PROGRESS_FREQ;
1837       #endif
1838
1839     }
1840     CsdPeriodic();
1841   }
1842 }
1843 int CsdScheduleCount(int maxmsgs)
1844 {
1845   int isIdle=0;
1846   SCHEDULE_TOP
1847   while (1) {
1848     msg = CsdNextMessage(&state);
1849     if (msg!=NULL) { /*A message is available-- process it*/
1850       if (isIdle) {isIdle=0;CsdEndIdle();}
1851       maxmsgs--; 
1852       SCHEDULE_MESSAGE
1853       if (maxmsgs==0) break;
1854     } else { /*No message available-- go (or remain) idle*/
1855       SCHEDULE_IDLE
1856     }
1857     CsdPeriodic();
1858   }
1859   return maxmsgs;
1860 }
1861
1862 void CsdSchedulePoll(void)
1863 {
1864   SCHEDULE_TOP
1865   while (1)
1866   {
1867         CsdPeriodic();
1868         /*CmiMachineProgressImpl(); ??? */
1869         if (NULL!=(msg = CsdNextMessage(&state)))
1870         {
1871              SCHEDULE_MESSAGE 
1872         }
1873         else break;
1874   }
1875 }
1876
1877 void CmiDeliverSpecificMsg(handler)
1878 int handler;
1879 {
1880   int *msg; int side;
1881   void *localqueue = CpvAccess(CmiLocalQueue);
1882  
1883   side = 0;
1884   while (1) {
1885     CsdPeriodic();
1886     side ^= 1;
1887     if (side) msg = CmiGetNonLocal();
1888     else      msg = CdsFifo_Dequeue(localqueue);
1889     if (msg) {
1890       if (CmiGetHandler(msg)==handler) {
1891         CpvAccess(cQdState)->mProcessed++;
1892         CmiHandleMessage(msg);
1893         return;
1894       } else {
1895         CdsFifo_Enqueue(localqueue, msg);
1896       }
1897     }
1898   }
1899 }
1900  
1901 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1902
1903 /***************************************************************************
1904  *
1905  * Standin Schedulers.
1906  *
1907  * We use the following strategy to make sure somebody's always running
1908  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1909  * is responsible for this.  If the main thread blocks, we create a
1910  * "standin scheduler" thread to replace it.  If the standin scheduler
1911  * blocks, we create another standin scheduler to replace that one,
1912  * ad infinitum.  Collectively, the main thread and all the standin
1913  * schedulers are called "scheduling threads".
1914  *
1915  * Suppose the main thread is blocked waiting for data, and a standin
1916  * scheduler is running instead.  Suppose, then, that the data shows
1917  * up and the main thread is CthAwakened.  This causes a token to be
1918  * pushed into the queue.  When the standin pulls the token from the
1919  * queue and handles it, the standin goes to sleep, and control shifts
1920  * back to the main thread.  In this way, unnecessary standins are put
1921  * back to sleep.  These sleeping standins are stored on the
1922  * CthSleepingStandins list.
1923  *
1924  ***************************************************************************/
1925
1926 CpvStaticDeclare(CthThread, CthMainThread);
1927 CpvStaticDeclare(CthThread, CthSchedulingThread);
1928 CpvStaticDeclare(CthThread, CthSleepingStandins);
1929 CpvDeclare(int      , CthResumeNormalThreadIdx);
1930 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1931
1932
1933 void CthStandinCode()
1934 {
1935   while (1) CsdScheduler(0);
1936 }
1937
1938 /* this fix the function pointer for thread migration and pup */
1939 static CthThread CthSuspendNormalThread()
1940 {
1941   return CpvAccess(CthSchedulingThread);
1942 }
1943
1944 void CthEnqueueSchedulingThread(CthThreadToken *token, int, int, unsigned int*);
1945 CthThread CthSuspendSchedulingThread();
1946
1947 CthThread CthSuspendSchedulingThread()
1948 {
1949   CthThread succ = CpvAccess(CthSleepingStandins);
1950
1951   if (succ) {
1952     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
1953   } else {
1954     succ = CthCreate(CthStandinCode, 0, 256000);
1955     CthSetStrategy(succ,
1956                    CthEnqueueSchedulingThread,
1957                    CthSuspendSchedulingThread);
1958   }
1959   
1960   CpvAccess(CthSchedulingThread) = succ;
1961   return succ;
1962 }
1963
1964 /* Notice: For changes to the following function, make sure the function CthResumeNormalThreadDebug is also kept updated. */
1965 void CthResumeNormalThread(CthThreadToken* token)
1966 {
1967   CthThread t = token->thread;
1968
1969   /* BIGSIM_OOC DEBUGGING
1970   CmiPrintf("Resume normal thread with token[%p] ==> thread[%p]\n", token, t);
1971   */
1972
1973   if(t == NULL){
1974     free(token);
1975     return;
1976   }
1977 #if CMK_TRACE_ENABLED
1978 #if ! CMK_TRACE_IN_CHARM
1979   if(CpvAccess(traceOn))
1980     CthTraceResume(t);
1981 /*    if(CpvAccess(_traceCoreOn)) 
1982                 resumeTraceCore();*/
1983 #endif
1984 #endif
1985   
1986   /* BIGSIM_OOC DEBUGGING
1987   CmiPrintf("In CthResumeNormalThread:   ");
1988   CthPrintThdMagic(t);
1989   */
1990
1991   CthResume(t);
1992 }
1993
1994 void CthResumeSchedulingThread(CthThreadToken  *token)
1995 {
1996   CthThread t = token->thread;
1997   CthThread me = CthSelf();
1998   if (me == CpvAccess(CthMainThread)) {
1999     CthEnqueueSchedulingThread(CthGetToken(me),CQS_QUEUEING_FIFO, 0, 0);
2000   } else {
2001     CthSetNext(me, CpvAccess(CthSleepingStandins));
2002     CpvAccess(CthSleepingStandins) = me;
2003   }
2004   CpvAccess(CthSchedulingThread) = t;
2005 #if CMK_TRACE_ENABLED
2006 #if ! CMK_TRACE_IN_CHARM
2007   if(CpvAccess(traceOn))
2008     CthTraceResume(t);
2009 /*    if(CpvAccess(_traceCoreOn)) 
2010                 resumeTraceCore();*/
2011 #endif
2012 #endif
2013   CthResume(t);
2014 }
2015
2016 void CthEnqueueNormalThread(CthThreadToken* token, int s, 
2017                                    int pb,unsigned int *prio)
2018 {
2019   CmiSetHandler(token, CpvAccess(CthResumeNormalThreadIdx));
2020   CsdEnqueueGeneral(token, s, pb, prio);
2021 }
2022
2023 void CthEnqueueSchedulingThread(CthThreadToken* token, int s, 
2024                                        int pb,unsigned int *prio)
2025 {
2026   CmiSetHandler(token, CpvAccess(CthResumeSchedulingThreadIdx));
2027   CsdEnqueueGeneral(token, s, pb, prio);
2028 }
2029
2030 void CthSetStrategyDefault(CthThread t)
2031 {
2032   CthSetStrategy(t,
2033                  CthEnqueueNormalThread,
2034                  CthSuspendNormalThread);
2035 }
2036
2037 void CthSchedInit()
2038 {
2039   CpvInitialize(CthThread, CthMainThread);
2040   CpvInitialize(CthThread, CthSchedulingThread);
2041   CpvInitialize(CthThread, CthSleepingStandins);
2042   CpvInitialize(int      , CthResumeNormalThreadIdx);
2043   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
2044
2045   CpvAccess(CthMainThread) = CthSelf();
2046   CpvAccess(CthSchedulingThread) = CthSelf();
2047   CpvAccess(CthSleepingStandins) = 0;
2048   CpvAccess(CthResumeNormalThreadIdx) =
2049     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
2050   CpvAccess(CthResumeSchedulingThreadIdx) =
2051     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
2052   CthSetStrategy(CthSelf(),
2053                  CthEnqueueSchedulingThread,
2054                  CthSuspendSchedulingThread);
2055 }
2056
2057 void CsdInit(argv)
2058   char **argv;
2059 {
2060   CpvInitialize(void *, CsdSchedQueue);
2061   CpvInitialize(int,   CsdStopFlag);
2062   CpvInitialize(int,   CsdLocalCounter);
2063   if(!CmiGetArgIntDesc(argv,"+csdLocalMax",&CsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages."))
2064     {
2065       CsdLocalMax= CSD_LOCAL_MAX_DEFAULT;
2066     }
2067   CpvAccess(CsdLocalCounter) = CsdLocalMax;
2068   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
2069
2070 #if CMK_OBJECT_QUEUE_AVAILABLE
2071   CpvInitialize(void *,CsdObjQueue);
2072   CpvAccess(CsdObjQueue) = CdsFifo_Create();
2073 #endif
2074
2075 #if CMK_NODE_QUEUE_AVAILABLE
2076   CsvInitialize(CmiLock, CsdNodeQueueLock);
2077   CsvInitialize(void *, CsdNodeQueue);
2078   if (CmiMyRank() ==0) {
2079         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
2080         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
2081   }
2082   CmiNodeAllBarrier();
2083 #endif
2084
2085 #if CMK_GRID_QUEUE_AVAILABLE
2086   CsvInitialize(void *, CsdGridQueue);
2087   CpvAccess(CsdGridQueue) = (void *)CqsCreate();
2088 #endif
2089
2090   CpvAccess(CsdStopFlag)  = 0;
2091 }
2092
2093
2094
2095 /** 
2096  *  @}
2097  */
2098
2099
2100 /*****************************************************************************
2101  *
2102  * Vector Send
2103  *
2104  * The last parameter "system" is by default at zero, in which case the normal
2105  * messages are sent. If it is set to 1, the CmiChunkHeader prepended to every
2106  * CmiAllocced message will also be sent (except for the first one). Useful for
2107  * AllToAll communication, and other system features. If system is 1, also all
2108  * the messages will be padded to 8 bytes. Thus, the caller must be aware of
2109  * that.
2110  *
2111  ****************************************************************************/
2112
2113 #if CMK_VECTOR_SEND_USES_COMMON_CODE
2114
2115 void CmiSyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2116   int total;
2117   char *mesg;
2118 #if CMK_USE_IBVERBS
2119   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(infiCmiChunkHeader));
2120 #else
2121   VECTOR_COMPACT(total, mesg, n, sizes, msgs,sizeof(CmiChunkHeader));
2122 #endif  
2123   CmiSyncSendAndFree(destPE, total, mesg);
2124 }
2125
2126 CmiCommHandle CmiASyncVectorSend(int destPE, int n, int *sizes, char **msgs) {
2127   CmiSyncVectorSend(destPE, n, sizes, msgs);
2128   return NULL;
2129 }
2130
2131 void CmiSyncVectorSendAndFree(int destPE, int n, int *sizes, char **msgs) {
2132   int i;
2133   CmiSyncVectorSend(destPE, n, sizes, msgs);
2134   for(i=0;i<n;i++) CmiFree(msgs[i]);
2135   CmiFree(sizes);
2136   CmiFree(msgs);
2137 }
2138
2139 #endif
2140
2141 /*****************************************************************************
2142  *
2143  * Reduction management
2144  *
2145  * Only one reduction can be active at a single time in the program.
2146  * Moreover, since every call is supposed to pass in the same arguments,
2147  * having some static variables is not a problem for multithreading.
2148  * 
2149  * Except for "data" and "size", all the other parameters (which are all function
2150  * pointers) MUST be the same in every processor. Having different processors
2151  * pass in different function pointers results in an undefined behaviour.
2152  * 
2153  * The data passed in to CmiReduce and CmiNodeReduce is deleted by the system,
2154  * and MUST be allocated with CmiAlloc. The data passed in to the "Struct"
2155  * functions is deleted with the provided function, or it is left intact if no
2156  * function is specified.
2157  * 
2158  * The destination handler for the the first form MUST be embedded into the
2159  * message's header.
2160  * 
2161  * The pup function is used to pup the input data structure into a message to
2162  * be sent to the parent processor. This pup routine is currently used only
2163  * for sizing and packing, NOT unpacking. It MUST be non-null.
2164  * 
2165  * The merge function receives as first parameter the input "data", being it
2166  * a message or a complex data structure (it is up to the user to interpret it
2167  * correctly), and a list of incoming (packed) messages from the children.
2168  * The merge function is responsible to delete "data" if this is no longer needed.
2169  * The system will be in charge of deleting the messages passed in as the second
2170  * argument, and the return value of the function (using the provided deleteFn in
2171  * the second version, or CmiFree in the first). The merge function can return
2172  * data if the merge can be performed in-place. It MUST be non-null.
2173  * 
2174  * At the destination, on processor zero, the final data returned by the last
2175  * merge call will not be deleted by the system, and the CmiHandler function
2176  * will be in charge of its deletion.
2177  * 
2178  * CmiReduce/CmiReduceStruct MUST be called once by every processor,
2179  * CmiNodeReduce/CmiNodeReduceStruct MUST be called once by every node, and in
2180  * particular by the rank zero in each node.
2181  ****************************************************************************/
2182
2183 CpvStaticDeclare(int, CmiReductionMessageHandler);
2184 CpvStaticDeclare(int, CmiReductionDynamicRequestHandler);
2185
2186 CpvStaticDeclare(CmiReduction**, _reduce_info);
2187 CpvStaticDeclare(int, _reduce_info_size); /* This is the log2 of the size of the array */
2188 CpvStaticDeclare(CmiUInt2, _reduce_seqID_global); /* This is used only by global reductions */
2189 CpvStaticDeclare(CmiUInt2, _reduce_seqID_request);
2190 CpvStaticDeclare(CmiUInt2, _reduce_seqID_dynamic);
2191
2192 enum {
2193   CmiReductionID_globalOffset = 0, /* Reductions that involve the whole set of processors */
2194   CmiReductionID_requestOffset = 1, /* Reductions IDs that are requested by all the processors (i.e during intialization) */
2195   CmiReductionID_dynamicOffset = 2, /* Reductions IDs that are requested by only one processor (typically at runtime) */
2196   CmiReductionID_multiplier = 3
2197 };
2198
2199 CmiReduction* CmiGetReductionCreate(int id, short int numChildren) {
2200   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2201   CmiReduction *red = CpvAccess(_reduce_info)[index];
2202   if (red != NULL && red->seqID != id) {
2203     /* The table needs to be expanded */
2204     CmiAbort("Too many simultaneous reductions");
2205   }
2206   if (red == NULL || red->numChildren < numChildren) {
2207     CmiReduction *newred;
2208     if (red != NULL) CmiPrintf("[%d] Reduction structure reallocated\n",CmiMyPe());
2209     CmiAssert(red == NULL || red->localContributed == 0);
2210     if (numChildren == 0) numChildren = 4;
2211     newred = (CmiReduction*)malloc(sizeof(CmiReduction)+numChildren*sizeof(void*));
2212     newred->numRemoteReceived = 0;
2213     newred->localContributed = 0;
2214     newred->seqID = id;
2215     if (red != NULL) {
2216       memcpy(newred, red, sizeof(CmiReduction)+red->numChildren*sizeof(void*));
2217       free(red);
2218     }
2219     red = newred;
2220     red->numChildren = numChildren;
2221     red->remoteData = (char**)(red+1);
2222     CpvAccess(_reduce_info)[index] = red;
2223   }
2224   return red;
2225 }
2226
2227 CmiReduction* CmiGetReduction(int id) {
2228   return CmiGetReductionCreate(id, 0);
2229 }
2230
2231 void CmiClearReduction(int id) {
2232   int index = id & ~((~0)<<CpvAccess(_reduce_info_size));
2233   free(CpvAccess(_reduce_info)[index]);
2234   CpvAccess(_reduce_info)[index] = NULL;
2235 }
2236
2237 CmiReduction* CmiGetNextReduction(short int numChildren) {
2238   int id = CpvAccess(_reduce_seqID_global);
2239   CpvAccess(_reduce_seqID_global) += CmiReductionID_multiplier;
2240   if (id > 0xFFF0) CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2241   return CmiGetReductionCreate(id, numChildren);
2242 }
2243
2244 CmiReductionID CmiGetGlobalReduction() {
2245   return CpvAccess(_reduce_seqID_request)+=CmiReductionID_multiplier;
2246 }
2247
2248 CmiReductionID CmiGetDynamicReduction() {
2249   if (CmiMyPe() != 0) CmiAbort("Cannot call CmiGetDynamicReduction on processors other than zero!\n");
2250   return CpvAccess(_reduce_seqID_dynamic)+=CmiReductionID_multiplier;
2251 }
2252
2253 void CmiReductionHandleDynamicRequest(char *msg) {
2254   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2255   int pe = values[0];
2256   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+values[1];
2257   values[0] = CmiGetDynamicReduction();
2258   CmiSetHandler(msg, CmiGetXHandler(msg));
2259   if (pe >= 0) {
2260     CmiSyncSendAndFree(pe, size, msg);
2261   } else {
2262     CmiSyncBroadcastAllAndFree(size, msg);
2263   }
2264 }
2265
2266 void CmiGetDynamicReductionRemote(int handlerIdx, int pe, int dataSize, void *data) {
2267   int size = CmiMsgHeaderSizeBytes+2*sizeof(int)+dataSize;
2268   char *msg = (char*)CmiAlloc(size);
2269   int *values = (int*)(msg+CmiMsgHeaderSizeBytes);
2270   values[0] = pe;
2271   values[1] = dataSize;
2272   CmiSetXHandler(msg, handlerIdx);
2273   if (dataSize) memcpy(msg+CmiMsgHeaderSizeBytes+2*sizeof(int), data, dataSize);
2274   if (CmiMyPe() == 0) {
2275     CmiReductionHandleDynamicRequest(msg);
2276   } else {
2277     /* send the request to processor 0 */
2278     CmiSetHandler(msg, CpvAccess(CmiReductionDynamicRequestHandler));
2279     CmiSyncSendAndFree(0, size, msg);
2280   }
2281 }
2282
2283 void CmiSendReduce(CmiReduction *red) {
2284   void *mergedData, *msg;
2285   int msg_size;
2286   if (!red->localContributed || red->numChildren != red->numRemoteReceived) return;
2287   mergedData = red->localData;
2288   msg_size = red->localSize;
2289   if (red->numChildren > 0) {
2290     int i, offset=0;
2291     if (red->ops.pupFn != NULL) {
2292       offset = CmiReservedHeaderSize;
2293       for (i=0; i<red->numChildren; ++i) red->remoteData[i] += offset;
2294     }
2295     mergedData = (red->ops.mergeFn)(&msg_size, red->localData, (void **)red->remoteData, red->numChildren);
2296     for (i=0; i<red->numChildren; ++i) CmiFree(red->remoteData[i] - offset);
2297   }
2298   /*CpvAccess(_reduce_num_children) = 0;*/
2299   /*CpvAccess(_reduce_received) = 0;*/
2300   msg = mergedData;
2301   if (red->parent != -1) {
2302     if (red->ops.pupFn != NULL) {
2303       pup_er p = pup_new_sizer();
2304       (red->ops.pupFn)(p, mergedData);
2305       msg_size = pup_size(p) + CmiReservedHeaderSize;
2306       pup_destroy(p);
2307       msg = CmiAlloc(msg_size);
2308       p = pup_new_toMem((void*)(((char*)msg)+CmiReservedHeaderSize));
2309       (red->ops.pupFn)(p, mergedData);
2310       pup_destroy(p);
2311       if (red->ops.deleteFn != NULL) (red->ops.deleteFn)(red->localData);
2312     }
2313     CmiSetHandler(msg, CpvAccess(CmiReductionMessageHandler));
2314     CmiSetRedID(msg, red->seqID);
2315     /*CmiPrintf("CmiSendReduce(%d): sending %d bytes to %d\n",CmiMyPe(),msg_size,red->parent);*/
2316     CmiSyncSendAndFree(red->parent, msg_size, msg);
2317   } else {
2318     (red->ops.destination)(msg);
2319   }
2320   CmiClearReduction(red->seqID);
2321 }
2322
2323 void *CmiReduceMergeFn_random(int *size, void *data, void** remote, int n) {
2324   return data;
2325 }
2326
2327 static void CmiGlobalReduce(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReduction *red) {
2328   CmiAssert(red->localContributed == 0);
2329   red->localContributed = 1;
2330   red->localData = msg;
2331   red->localSize = size;
2332   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2333   red->parent = CmiSpanTreeParent(CmiMyPe());
2334   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2335   red->ops.mergeFn = mergeFn;
2336   red->ops.pupFn = NULL;
2337   /*CmiPrintf("[%d] CmiReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2338   CmiSendReduce(red);
2339 }
2340
2341 static void CmiGlobalReduceStruct(void *data, CmiReducePupFn pupFn,
2342                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2343                      CmiReduceDeleteFn deleteFn, CmiReduction *red) {
2344   CmiAssert(red->localContributed == 0);
2345   red->localContributed = 1;
2346   red->localData = data;
2347   red->localSize = 0;
2348   red->numChildren = CmiNumSpanTreeChildren(CmiMyPe());
2349   red->parent = CmiSpanTreeParent(CmiMyPe());
2350   red->ops.destination = dest;
2351   red->ops.mergeFn = mergeFn;
2352   red->ops.pupFn = pupFn;
2353   red->ops.deleteFn = deleteFn;
2354   /*CmiPrintf("[%d] CmiReduceStruct::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2355   CmiSendReduce(red);
2356 }
2357
2358 void CmiReduce(void *msg, int size, CmiReduceMergeFn mergeFn) {
2359   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2360   CmiGlobalReduce(msg, size, mergeFn, red);
2361 }
2362
2363 void CmiReduceStruct(void *data, CmiReducePupFn pupFn,
2364                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2365                      CmiReduceDeleteFn deleteFn) {
2366   CmiReduction *red = CmiGetNextReduction(CmiNumSpanTreeChildren(CmiMyPe()));
2367   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2368 }
2369
2370 void CmiReduceID(void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2371   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2372   CmiGlobalReduce(msg, size, mergeFn, red);
2373 }
2374
2375 void CmiReduceStructID(void *data, CmiReducePupFn pupFn,
2376                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2377                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2378   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2379   CmiGlobalReduceStruct(data, pupFn, mergeFn, dest, deleteFn, red);
2380 }
2381
2382 void CmiListReduce(int npes, int *pes, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2383   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2384   int myPos;
2385   CmiAssert(red->localContributed == 0);
2386   red->localContributed = 1;
2387   red->localData = msg;
2388   red->localSize = size;
2389   for (myPos=0; myPos<npes; ++myPos) {
2390     if (pes[myPos] == CmiMyPe()) break;
2391   }
2392   CmiAssert(myPos < npes);
2393   red->numChildren = npes - (myPos << 2) - 1;
2394   if (red->numChildren > 4) red->numChildren = 4;
2395   if (red->numChildren < 0) red->numChildren = 0;
2396   if (myPos == 0) red->parent = -1;
2397   else red->parent = pes[(myPos - 1) >> 2];
2398   red->ops.destination = (CmiHandler)CmiGetHandlerFunction(msg);
2399   red->ops.mergeFn = mergeFn;
2400   red->ops.pupFn = NULL;
2401   /*CmiPrintf("[%d] CmiListReduce::local %hd parent=%d, numChildren=%d\n",CmiMyPe(),red->seqID,red->parent,red->numChildren);*/
2402   CmiSendReduce(red);
2403 }
2404
2405 void CmiListReduceStruct(int npes, int *pes,
2406                      void *data, CmiReducePupFn pupFn,
2407                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2408                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2409   CmiReduction *red = CmiGetReductionCreate(id, CmiNumSpanTreeChildren(CmiMyPe()));
2410   int myPos;
2411   CmiAssert(red->localContributed == 0);
2412   red->localContributed = 1;
2413   red->localData = data;
2414   red->localSize = 0;
2415   for (myPos=0; myPos<npes; ++myPos) {
2416     if (pes[myPos] == CmiMyPe()) break;
2417   }
2418   CmiAssert(myPos < npes);
2419   red->numChildren = npes - (myPos << 2) - 1;
2420   if (red->numChildren > 4) red->numChildren = 4;
2421   if (red->numChildren < 0) red->numChildren = 0;
2422   red->parent = (myPos - 1) >> 2;
2423   if (myPos == 0) red->parent = -1;
2424   red->ops.destination = dest;
2425   red->ops.mergeFn = mergeFn;
2426   red->ops.pupFn = pupFn;
2427   red->ops.deleteFn = deleteFn;
2428   CmiSendReduce(red);
2429 }
2430
2431 void CmiGroupReduce(CmiGroup grp, void *msg, int size, CmiReduceMergeFn mergeFn, CmiReductionID id) {
2432   int npes, *pes;
2433   CmiLookupGroup(grp, &npes, &pes);
2434   CmiListReduce(npes, pes, msg, size, mergeFn, id);
2435 }
2436
2437 void CmiGroupReduceStruct(CmiGroup grp, void *data, CmiReducePupFn pupFn,
2438                      CmiReduceMergeFn mergeFn, CmiHandler dest,
2439                      CmiReduceDeleteFn deleteFn, CmiReductionID id) {
2440   int npes, *pes;
2441   CmiLookupGroup(grp, &npes, &pes);
2442   CmiListReduceStruct(npes, pes, data, pupFn, mergeFn, dest, deleteFn, id);
2443 }
2444
2445 void CmiNodeReduce(void *data, int size, CmiReduceMergeFn mergeFn, int redID, int numChildren, int parent) {
2446   CmiAbort("Feel free to implement CmiNodeReduce...");
2447   /*
2448   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2449   CpvAccess(_reduce_data) = data;
2450   CpvAccess(_reduce_data_size) = size;
2451   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2452   _reduce_destination = (CmiHandler)CmiGetHandlerFunction(data);
2453   _reduce_pupFn = NULL;
2454   _reduce_mergeFn = mergeFn;
2455   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2456   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(size);
2457   */
2458 }
2459 #if 0
2460 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int redID) {
2461   CmiNodeReduce(data, size, mergeFn, redID, CmiNumNodeSpanTreeChildren(CmiMyNode()),
2462       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2463 }
2464 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int), int numChildren, int parent) {
2465   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), numChildren, parent);
2466 }
2467 void CmiNodeReduce(void *data, int size, void * (*mergeFn)(void*,void**,int)) {
2468   CmiNodeReduce(data, size, mergeFn, CmiReduceNextID(), CmiNumNodeSpanTreeChildren(CmiMyNode()),
2469       CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode())));
2470 }
2471 #endif
2472
2473 void CmiNodeReduceStruct(void *data, CmiReducePupFn pupFn,
2474                          CmiReduceMergeFn mergeFn, CmiHandler dest,
2475                          CmiReduceDeleteFn deleteFn) {
2476   CmiAbort("Feel free to implement CmiNodeReduceStruct...");
2477 /*
2478   CmiAssert(CmiRankOf(CmiMyPe()) == 0);
2479   CpvAccess(_reduce_data) = data;
2480   CpvAccess(_reduce_parent) = CmiNodeFirst(CmiNodeSpanTreeParent(CmiMyNode()));
2481   _reduce_destination = dest;
2482   _reduce_pupFn = pupFn;
2483   _reduce_mergeFn = mergeFn;
2484   _reduce_deleteFn = deleteFn;
2485   CpvAccess(_reduce_num_children) = CmiNumNodeSpanTreeChildren(CmiMyNode());
2486   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce(0);
2487   */
2488 }
2489
2490 void CmiHandleReductionMessage(void *msg) {
2491   CmiReduction *red = CmiGetReduction(CmiGetRedID(msg));
2492   if (red->numRemoteReceived == red->numChildren) red = CmiGetReductionCreate(CmiGetRedID(msg), red->numChildren+4);
2493   red->remoteData[red->numRemoteReceived++] = msg;
2494   /*CmiPrintf("[%d] CmiReduce::remote %hd\n",CmiMyPe(),red->seqID);*/
2495   CmiSendReduce(red);
2496 /*
2497   CpvAccess(_reduce_msg_list)[CpvAccess(_reduce_received)++] = msg;
2498   if (CpvAccess(_reduce_received) == CpvAccess(_reduce_num_children)) CmiSendReduce();
2499   / *else CmiPrintf("CmiHandleReductionMessage(%d): %d - %d\n",CmiMyPe(),CpvAccess(_reduce_received),CpvAccess(_reduce_num_children));*/
2500 }
2501
2502 void CmiReductionsInit() {
2503   int i;
2504   CpvInitialize(int, CmiReductionMessageHandler);
2505   CpvAccess(CmiReductionMessageHandler) = CmiRegisterHandler((CmiHandler)CmiHandleReductionMessage);
2506   CpvInitialize(int, CmiReductionDynamicRequestHandler);
2507   CpvAccess(CmiReductionDynamicRequestHandler) = CmiRegisterHandler((CmiHandler)CmiReductionHandleDynamicRequest);
2508   CpvInitialize(CmiUInt2, _reduce_seqID_global);
2509   CpvAccess(_reduce_seqID_global) = CmiReductionID_globalOffset;
2510   CpvInitialize(CmiUInt2, _reduce_seqID_request);
2511   CpvAccess(_reduce_seqID_request) = CmiReductionID_requestOffset;
2512   CpvInitialize(CmiUInt2, _reduce_seqID_dynamic);
2513   CpvAccess(_reduce_seqID_dynamic) = CmiReductionID_dynamicOffset;
2514   CpvInitialize(int, _reduce_info_size);
2515   CpvAccess(_reduce_info_size) = 4;
2516   CpvInitialize(CmiReduction**, _reduce_info);
2517   CpvAccess(_reduce_info) = malloc(16*sizeof(CmiReduction*));
2518   for (i=0; i<16; ++i) CpvAccess(_reduce_info)[i] = NULL;
2519 }
2520
2521 /*****************************************************************************
2522  *
2523  * Multicast groups
2524  *
2525  ****************************************************************************/
2526
2527 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
2528
2529 typedef struct GroupDef
2530 {
2531   union {
2532     char core[CmiMsgHeaderSizeBytes];
2533     struct GroupDef *next;
2534   } core;
2535   CmiGroup group;
2536   int npes;
2537   int pes[1];
2538 }
2539 *GroupDef;
2540
2541 #define GROUPTAB_SIZE 101
2542
2543 CpvStaticDeclare(int, CmiGroupHandlerIndex);
2544 CpvStaticDeclare(int, CmiGroupCounter);
2545 CpvStaticDeclare(GroupDef *, CmiGroupTable);
2546
2547 void CmiGroupHandler(GroupDef def)
2548 {
2549   /* receive group definition, insert into group table */
2550   GroupDef *table = CpvAccess(CmiGroupTable);
2551   unsigned int hashval, bucket;
2552   hashval = (def->group.id ^ def->group.pe);
2553   bucket = hashval % GROUPTAB_SIZE;
2554   def->core.next = table[bucket];
2555   table[bucket] = def;
2556 }
2557
2558 CmiGroup CmiEstablishGroup(int npes, int *pes)
2559 {
2560   /* build new group definition, broadcast it */
2561   CmiGroup grp; GroupDef def; int len, i;
2562   grp.id = CpvAccess(CmiGroupCounter)++;
2563   grp.pe = CmiMyPe();
2564   len = sizeof(struct GroupDef)+(npes*sizeof(int));
2565   def = (GroupDef)CmiAlloc(len);
2566   def->group = grp;
2567   def->npes = npes;
2568   for (i=0; i<npes; i++)
2569     def->pes[i] = pes[i];
2570   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
2571   CmiSyncBroadcastAllAndFree(len, def);
2572   return grp;
2573 }
2574
2575 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
2576 {
2577   unsigned int hashval, bucket;  GroupDef def;
2578   GroupDef *table = CpvAccess(CmiGroupTable);
2579   hashval = (grp.id ^ grp.pe);
2580   bucket = hashval % GROUPTAB_SIZE;
2581   for (def=table[bucket]; def; def=def->core.next) {
2582     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
2583       *npes = def->npes;
2584       *pes = def->pes;
2585       return;
2586     }
2587   }
2588   *npes = 0; *pes = 0;
2589 }
2590
2591 void CmiGroupInit()
2592 {
2593   CpvInitialize(int, CmiGroupHandlerIndex);
2594   CpvInitialize(int, CmiGroupCounter);
2595   CpvInitialize(GroupDef *, CmiGroupTable);
2596   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
2597   CpvAccess(CmiGroupCounter) = 0;
2598   CpvAccess(CmiGroupTable) =
2599     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
2600   if (CpvAccess(CmiGroupTable) == 0)
2601     CmiAbort("Memory Allocation Error");
2602 }
2603
2604 #endif
2605
2606 /*****************************************************************************
2607  *
2608  * Common List-Cast and Multicast Code
2609  *
2610  ****************************************************************************/
2611
2612 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
2613
2614 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
2615 {
2616   int i;
2617   for(i=0;i<npes;i++) {
2618     CmiSyncSend(pes[i], len, msg);
2619   }
2620 }
2621
2622 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
2623 {
2624   /* A better asynchronous implementation may be wanted, but at least it works */
2625   CmiSyncListSendFn(npes, pes, len, msg);
2626   return (CmiCommHandle) 0;
2627 }
2628
2629 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
2630 {
2631   int i;
2632   for(i=0;i<npes-1;i++) {
2633     CmiSyncSend(pes[i], len, msg);
2634   }
2635   if (npes>0)
2636     CmiSyncSendAndFree(pes[npes-1], len, msg);
2637   else 
2638     CmiFree(msg);
2639 }
2640
2641 #endif
2642
2643 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
2644
2645 typedef struct MultiMsg
2646 {
2647   char core[CmiMsgHeaderSizeBytes];
2648   CmiGroup group;
2649   int pos;
2650   int origlen;
2651 }
2652 *MultiMsg;
2653
2654
2655 CpvDeclare(int, CmiMulticastHandlerIndex);
2656
2657 void CmiMulticastDeliver(MultiMsg msg)
2658 {
2659   int npes, *pes; int olen, nlen, pos, child1, child2;
2660   olen = msg->origlen;
2661   nlen = olen + sizeof(struct MultiMsg);
2662   CmiLookupGroup(msg->group, &npes, &pes);
2663   if (pes==0) {
2664     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
2665     return;
2666   }
2667   if (npes==0) {
2668     CmiFree(msg);
2669     return;
2670   }
2671   if (msg->pos == -1) {
2672     msg->pos=0;
2673     CmiSyncSendAndFree(pes[0], nlen, msg);
2674     return;
2675   }
2676   pos = msg->pos;
2677   child1 = ((pos+1)<<1);
2678   child2 = child1-1;
2679   if (child1 < npes) {
2680     msg->pos = child1;
2681     CmiSyncSend(pes[child1], nlen, msg);
2682   }
2683   if (child2 < npes) {
2684     msg->pos = child2;
2685     CmiSyncSend(pes[child2], nlen, msg);
2686   }
2687   if(olen < sizeof(struct MultiMsg)) {
2688     memcpy(msg, msg+1, olen);
2689   } else {
2690     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
2691   }
2692   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
2693 }
2694
2695 void CmiMulticastHandler(MultiMsg msg)
2696 {
2697   CmiMulticastDeliver(msg);
2698 }
2699
2700 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
2701 {
2702   int newlen; MultiMsg newmsg;
2703   newlen = len + sizeof(struct MultiMsg);
2704   newmsg = (MultiMsg)CmiAlloc(newlen);
2705   if(len < sizeof(struct MultiMsg)) {
2706     memcpy(newmsg+1, msg, len);
2707   } else {
2708     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
2709     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
2710   }
2711   newmsg->group = grp;
2712   newmsg->origlen = len;
2713   newmsg->pos = -1;
2714   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
2715   CmiMulticastDeliver(newmsg);
2716 }
2717
2718 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
2719 {
2720   CmiSyncMulticastFn(grp, len, msg);
2721   CmiFree(msg);
2722 }
2723
2724 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
2725 {
2726   CmiError("Async Multicast not implemented.");
2727   return (CmiCommHandle) 0;
2728 }
2729
2730 void CmiMulticastInit()
2731 {
2732   CpvInitialize(int, CmiMulticastHandlerIndex);
2733   CpvAccess(CmiMulticastHandlerIndex) =
2734     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
2735 }
2736
2737 #endif
2738
2739 #if CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2740 extern void *arena_malloc(int size);
2741 extern void arena_free(void *blockPtr);
2742 #endif
2743
2744 /***************************************************************************
2745  *
2746  * Memory Allocation routines 
2747  *
2748  * A block of memory can consist of multiple chunks.  Each chunk has
2749  * a sizefield and a refcount.  The first chunk's refcount is a reference
2750  * count.  That's how many CmiFrees it takes to free the message.
2751  * Subsequent chunks have a refcount which is less than zero.  This is
2752  * the offset back to the start of the first chunk.
2753  *
2754  * Each chunk has a CmiChunkHeader before the user data, with the fields:
2755  *
2756  *  size: The user-allocated size of the chunk, in bytes.
2757  *
2758  *  ref: A magic reference count object. Ordinary blocks start with
2759  *     reference count 1.  When the reference count reaches zero,
2760  *     the block is deleted.  To support nested buffers, the 
2761  *     reference count can also be negative, which means it is 
2762  *     a byte offset to the enclosing buffer's reference count.
2763  *
2764  ***************************************************************************/
2765
2766
2767 void *CmiAlloc(int size)
2768 {
2769
2770   char *res;
2771
2772 #if CONVERSE_VERSION_ELAN
2773   res = (char *) elan_CmiAlloc(size+sizeof(CmiChunkHeader));
2774 #elif CONVERSE_VERSION_VMI
2775   res = (char *) CMI_VMI_CmiAlloc(size+sizeof(CmiChunkHeader));
2776 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2777   res = (char*) arena_malloc(size+sizeof(CmiChunkHeader));
2778 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2779   res = (char *) infi_CmiAlloc(size+sizeof(CmiChunkHeader));
2780 #elif CMK_CONVERSE_GEMINI_UGNI
2781   res =(char *) LrtsAlloc(size, sizeof(CmiChunkHeader));
2782 #elif CONVERSE_POOL
2783   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
2784 #else
2785   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
2786 #endif
2787
2788   _MEMCHECK(res);
2789
2790 #ifdef MEMMONITOR
2791   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
2792   CpvAccess(AllocCount)++;
2793   CpvAccess(BlocksAllocated)++;
2794   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
2795     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
2796   }
2797   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
2798     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2799             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2800             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2801     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
2802   }
2803   if ((CpvAccess(AllocCount) % 1000) == 0) {
2804     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
2805             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
2806             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
2807   }
2808 #endif
2809
2810   res+=sizeof(CmiChunkHeader);
2811   SIZEFIELD(res)=size;
2812   REFFIELD(res)=1;
2813   return (void *)res;
2814 }
2815
2816 /** Follow the header links out to the most enclosing block */
2817 static void *CmiAllocFindEnclosing(void *blk) {
2818   int refCount = REFFIELD(blk);
2819   while (refCount < 0) {
2820     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
2821     refCount = REFFIELD(blk);
2822   }
2823   return blk;
2824 }
2825
2826 /** Increment the reference count for this block's owner.
2827     This call must be matched by an equivalent CmiFree. */
2828 void CmiReference(void *blk)
2829 {
2830   REFFIELD(CmiAllocFindEnclosing(blk))++;
2831 }
2832
2833 /** Return the size of the user portion of this block. */
2834 int CmiSize(void *blk)
2835 {
2836   return SIZEFIELD(blk);
2837 }
2838
2839 /** Decrement the reference count for this block. */
2840 void CmiFree(void *blk)
2841 {
2842   void *parentBlk=CmiAllocFindEnclosing(blk);
2843   int refCount=REFFIELD(parentBlk);
2844 #if CMK_ERROR_CHECKING
2845   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
2846     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
2847 #endif
2848   refCount--;
2849   REFFIELD(parentBlk) = refCount;
2850   if(refCount==0) { /* This was the last reference to the block-- free it */
2851 #ifdef MEMMONITOR
2852     int size=SIZEFIELD(parentBlk);
2853     if (size > 1000000000) /* Absurdly large size field-- warning */
2854       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
2855     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader));
2856     CpvAccess(BlocksAllocated)--;
2857 #endif
2858
2859 #if CONVERSE_VERSION_ELAN
2860     elan_CmiFree(BLKSTART(parentBlk));
2861 #elif CONVERSE_VERSION_VMI
2862     CMI_VMI_CmiFree(BLKSTART(parentBlk));
2863 #elif CONVERSE_VERSION_SHMEM && CMK_ARENA_MALLOC
2864     arena_free(BLKSTART(parentBlk));
2865 #elif CMK_USE_IBVERBS | CMK_USE_IBUD
2866     /* is this message the head of a MultipleSend that we received?
2867        Then the parts with INFIMULTIPOOL have metadata which must be 
2868        unregistered and freed.  */
2869 #ifdef CMK_IBVERS_CLEAN_MULTIPLESEND
2870     if(CmiGetHandler(parentBlk)==CpvAccess(CmiMainHandlerIDP))
2871       {
2872         infi_freeMultipleSend(parentBlk);
2873       }
2874 #endif
2875     infi_CmiFree(BLKSTART(parentBlk));
2876 #elif CMK_CONVERSE_GEMINI_UGNI
2877     LrtsFree(BLKSTART(parentBlk));
2878 #elif CONVERSE_POOL
2879     CmiPoolFree(BLKSTART(parentBlk));
2880 #else
2881     free_nomigrate(BLKSTART(parentBlk));
2882 #endif
2883   }
2884 }
2885
2886
2887 /***************************************************************************
2888  *
2889  * Temporary-memory Allocation routines 
2890  *
2891  *  This buffer augments the storage available on the regular machine stack
2892  * for fairly large temporary buffers, which allows us to use smaller machine
2893  * stacks.
2894  *
2895  ***************************************************************************/
2896
2897 #define CMI_TMP_BUF_MAX 128*1024 /* Allow this much temporary storage. */
2898
2899 typedef struct {
2900   char *buf; /* Start of temporary buffer */
2901   int cur; /* First unused location in temporary buffer */
2902   int max; /* Length of temporary buffer */
2903 } CmiTmpBuf_t;
2904 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
2905
2906 static void CmiTmpSetup(CmiTmpBuf_t *b) {
2907   b->buf=malloc(CMI_TMP_BUF_MAX);
2908   b->cur=0;
2909   b->max=CMI_TMP_BUF_MAX;
2910 }
2911
2912 void *CmiTmpAlloc(int size) {
2913   if (!CpvInitialized(CmiTmpBuf)) {
2914     return malloc(size);
2915   }
2916   else { /* regular case */
2917     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
2918     void *t;
2919     if (b->cur+size>b->max) {
2920       if (b->max==0) /* We're just uninitialized */
2921         CmiTmpSetup(b);
2922       else /* We're really out of space! */
2923         CmiAbort("CmiTmpAlloc: asked for too much temporary buffer space");
2924     }
2925     t=b->buf+b->cur;
2926     b->cur+=size;
2927     return t;
2928   }
2929 }
2930 void CmiTmpFree(void *t) {
2931   if (!CpvInitialized(CmiTmpBuf)) {
2932     free(t);
2933   }
2934   else { /* regular case */
2935     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
2936     /* t should point into our temporary buffer: figure out where */
2937     int cur=((const char *)t)-b->buf;
2938 #if CMK_ERROR_CHECKING
2939     if (cur<0 || cur>b->max)
2940       CmiAbort("CmiTmpFree: called with an invalid pointer");
2941 #endif
2942     b->cur=cur;
2943   }
2944 }
2945
2946 void CmiTmpInit(char **argv) {
2947   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
2948   /* Set up this processor's temporary buffer */
2949   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
2950 }
2951
2952 /******************************************************************************
2953
2954   Cross-platform directory creation
2955
2956   ****************************************************************************/
2957 #ifdef _MSC_VER
2958 /* Windows directory creation: */
2959 #include <windows.h>
2960
2961 void CmiMkdir(const char *dirName) {
2962         CreateDirectory(dirName,NULL);
2963 }
2964
2965 #else /* !_MSC_VER */
2966 /* UNIX directory creation */
2967 #include <unistd.h> 
2968 #include <sys/stat.h> /* from "mkdir" man page */
2969 #include <sys/types.h>
2970
2971 void CmiMkdir(const char *dirName) {
2972 #ifndef __MINGW_H
2973         mkdir(dirName,0777);
2974 #else
2975         mkdir(dirName);
2976 #endif
2977 }
2978
2979 #endif
2980
2981
2982 /******************************************************************************
2983
2984   Multiple Send function                               
2985
2986   ****************************************************************************/
2987
2988
2989
2990
2991
2992 /****************************************************************************
2993 * DESCRIPTION : This function call allows the user to send multiple messages
2994 *               from one processor to another, all intended for differnet 
2995 *               handlers.
2996 *
2997 *               Parameters :
2998 *
2999 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
3000 *
3001 ****************************************************************************/
3002 /* Round up message size to the message granularity. 
3003    Does this by adding, then truncating.
3004 */
3005 static int roundUpSize(unsigned int s) {
3006   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
3007 }
3008 /* Return the amount of message padding required for a message
3009    with this many user bytes. 
3010  */
3011 static int paddingSize(unsigned int s) {
3012   return roundUpSize(s)-s;
3013 }
3014
3015 /* Message header for a bundle of multiple-sent messages */
3016 typedef struct {
3017   char convHeader[CmiMsgHeaderSizeBytes];
3018   int nMessages; /* Number of distinct messages bundled below. */
3019   double pad; /* To align the first message, which follows this header */
3020 } CmiMultipleSendHeader;
3021
3022 #if CMK_USE_IBVERBS | CMK_USE_IBUD
3023 /* given a pointer to a multisend message clean up the metadata */
3024
3025 void infi_freeMultipleSend(void *msgWhole)
3026 {
3027   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3028   double pad=((CmiMultipleSendHeader *)msgWhole)->pad;
3029   int offset=sizeof(CmiMultipleSendHeader);
3030   int m;
3031   void *thisMsg=NULL;
3032   if (pad != 1234567.89) return;
3033   for(m=0;m<len;m++)
3034     {
3035       /*unreg meta, free meta, move the ptr */
3036       /* note these weird little things are not pooled */
3037       /* do NOT free the message here, we are only a part of this buffer*/
3038       infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3039       char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3040       int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3041       infi_unregAndFreeMeta(ch->metaData);
3042       offset+= sizeof(infiCmiChunkHeader) + msgSize;
3043     }
3044 }
3045 #endif
3046
3047
3048 static void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
3049 {
3050   CmiMultipleSendHeader header;
3051   int m; /* Outgoing message */
3052
3053 #if CMK_USE_IBVERBS
3054   infiCmiChunkHeader *msgHdr;
3055 #else
3056   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
3057 #endif
3058         
3059   double pad = 0; /* padding required */
3060   int vecLen; /* Number of pieces in outgoing message vector */
3061   int *vecSizes; /* Sizes of each piece we're sending out. */
3062   char **vecPtrs; /* Pointers to each piece we're sending out. */
3063   int vec; /* Entry we're currently filling out in above array */
3064         
3065 #if CMK_USE_IBVERBS
3066   msgHdr = (infiCmiChunkHeader *)CmiTmpAlloc(len * sizeof(infiCmiChunkHeader));
3067 #else
3068   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
3069 #endif
3070         
3071   /* Allocate memory for the outgoing vector*/
3072   vecLen=1+3*len; /* Header and 3 parts per message */
3073   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
3074   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
3075   vec=0;
3076   
3077   /* Build the header */
3078   header.nMessages=len;
3079   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
3080   header.pad = 1234567.89;
3081 #if CMK_IMMEDIATE_MSG
3082   if (immed) CmiBecomeImmediate(&header);
3083 #endif
3084   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
3085   vec++;
3086
3087   /* Build an entry for each message: 
3088          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
3089   */
3090   for (m=0;m<len;m++) {
3091 #if CMK_USE_IBVERBS
3092     msgHdr[m].chunkHeader.size=roundUpSize(sizes[m]); /* Size of message and padding */
3093     msgHdr[m].chunkHeader.ref=0; /* Reference count will be filled out on receive side */
3094     msgHdr[m].metaData=NULL;
3095 #else
3096     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
3097     msgHdr[m].ref=0; /* Reference count will be filled out on receive side */
3098 #endif          
3099     
3100     /* First send the message's CmiChunkHeader (for use on receive side) */
3101 #if CMK_USE_IBVERBS
3102     vecSizes[vec]=sizeof(infiCmiChunkHeader);
3103 #else
3104     vecSizes[vec]=sizeof(CmiChunkHeader); 
3105 #endif          
3106                 vecPtrs[vec]=(char *)&msgHdr[m];
3107     vec++;
3108     
3109     /* Now send the actual message data */
3110     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
3111     vec++;
3112     
3113     /* Now send padding to align the next message on a double-boundary */
3114     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
3115     vec++;
3116   }
3117   CmiAssert(vec==vecLen);
3118   
3119   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
3120   
3121   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
3122   CmiTmpFree(vecSizes);
3123   CmiTmpFree(msgHdr);
3124 }
3125
3126 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3127 {
3128   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
3129 }
3130
3131 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
3132 {
3133   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
3134 }
3135
3136 /****************************************************************************
3137 * DESCRIPTION : This function initializes the main handler required for the
3138 *               CmiMultipleSend() function to work. 
3139 *               
3140 *               This function should be called once in any Converse program
3141 *               that uses CmiMultipleSend()
3142 *
3143 ****************************************************************************/
3144
3145 static void CmiMultiMsgHandler(char *msgWhole);
3146
3147 void CmiInitMultipleSend(void)
3148 {
3149   CpvInitialize(int,CmiMainHandlerIDP); 
3150   CpvAccess(CmiMainHandlerIDP) =
3151     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
3152 }
3153
3154 /****************************************************************************
3155 * DESCRIPTION : This function is the main handler that splits up the messages
3156 *               CmiMultipleSend() pastes together. 
3157 *
3158 ****************************************************************************/
3159
3160 static void CmiMultiMsgHandler(char *msgWhole)
3161 {
3162   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
3163   int offset=sizeof(CmiMultipleSendHeader);
3164   int m;
3165   for (m=0;m<len;m++) {
3166 #if CMK_USE_IBVERBS
3167     infiCmiChunkHeader *ch=(infiCmiChunkHeader *)(msgWhole+offset);
3168     char *msg=(msgWhole+offset+sizeof(infiCmiChunkHeader));
3169     int msgSize=ch->chunkHeader.size; /* Size of user portion of message (plus padding at end) */
3170     ch->chunkHeader.ref=msgWhole-msg; 
3171     ch->metaData =  registerMultiSendMesg(msg,msgSize);
3172 #else
3173     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
3174     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
3175     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
3176     ch->ref=msgWhole-msg; 
3177 #endif          
3178     /* Link new message to owner via a negative ref pointer */
3179     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
3180     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
3181 #if CMK_USE_IBVERBS
3182     offset+= sizeof(infiCmiChunkHeader) + msgSize;
3183 #else
3184     offset+= sizeof(CmiChunkHeader) + msgSize;
3185 #endif          
3186   }
3187   /* Release our reference to the whole message.  The message will
3188      only actually be deleted once all its sub-messages are free'd as well. */
3189   CmiFree(msgWhole);
3190 }
3191
3192 /****************************************************************************
3193 * Hypercube broadcast message passing.
3194 ****************************************************************************/
3195
3196 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
3197   int num_pes = 0;
3198   for ( ; k>=0; --k) {
3199     /* add the processor destination at level k if it exist */
3200     dest_pes[num_pes] = mype ^ (1<<k);
3201     if (dest_pes[num_pes] >= total_pes) {
3202       /* find the first proc in the other part of the current dimention */
3203       dest_pes[num_pes] &= (-1)<<k;
3204       /* if the first proc there is over CmiNumPes() then there is no other
3205          dimension, otherwise if it is valid compute my correspondent in such
3206          a way to minimize the load for every processor */
3207       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((-1)<<k))) % (total_pes - dest_pes[num_pes]);
3208       }
3209     if (dest_pes[num_pes] < total_pes) {
3210       /* if the destination is in the acceptable range increment num_pes */
3211       ++num_pes;
3212     }
3213   }
3214   return num_pes;
3215 }
3216
3217
3218 /****************************************************************************
3219 * DESCRIPTION : This function initializes the main handler required for the
3220 *               Immediate message
3221 *               
3222 *               This function should be called once in any Converse program
3223 *
3224 ****************************************************************************/
3225
3226 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
3227 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
3228
3229 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
3230
3231 /* xdl is the real handler */
3232 static void CmiImmediateMsgHandler(char *msg)
3233 {
3234   CmiSetHandler(msg, CmiGetXHandler(msg));
3235   CmiHandleMessage(msg);
3236 }
3237
3238 void CmiInitImmediateMsg(void)
3239 {
3240   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3241   CpvAccess(CmiImmediateMsgHandlerIdx) =
3242     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
3243 }
3244
3245 /*#if !CMK_IMMEDIATE_MSG
3246 #if !CMK_MACHINE_PROGRESS_DEFINED
3247 void CmiProbeImmediateMsg()
3248 {
3249 }
3250 #endif
3251 #endif*/
3252
3253 /******** Idle timeout module (+idletimeout=30) *********/
3254
3255 typedef struct {
3256   int idle_timeout;/*Milliseconds to wait idle before aborting*/
3257   int is_idle;/*Boolean currently-idle flag*/
3258   int call_count;/*Number of timeout calls currently in flight*/
3259 } cmi_cpu_idlerec;
3260
3261 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
3262 {
3263   rec->call_count--;
3264   if(rec->call_count==0 && rec->is_idle==1) {
3265     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
3266     CmiAbort("Exiting.\n");
3267   }
3268 }
3269 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
3270 {
3271   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
3272   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
3273   rec->is_idle = 1;
3274 }
3275 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
3276 {
3277   rec->is_idle = 0;
3278 }
3279 static void CIdleTimeoutInit(char **argv)
3280 {
3281   int idle_timeout=0; /*Seconds to wait*/
3282   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
3283   if(idle_timeout != 0) {
3284     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
3285     _MEMCHECK(rec);
3286     rec->idle_timeout=idle_timeout*1000;
3287     rec->is_idle=0;
3288     rec->call_count=0;
3289     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
3290     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
3291   }
3292 }
3293
3294 /*****************************************************************************
3295  *
3296  * Converse Initialization
3297  *
3298  *****************************************************************************/
3299
3300 extern void CrnInit(void);
3301 extern void CmiIsomallocInit(char **argv);
3302 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3303 void CmiIOInit(char **argv);
3304 #endif
3305
3306 /* defined in cpuaffinity.c */
3307 extern void CmiInitCPUAffinityUtil();
3308
3309 static void CmiProcessPriority(char **argv)
3310 {
3311   int dummy, nicelevel=-100;      /* process priority */
3312   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
3313   /* ignore others */
3314   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
3315   /* call setpriority once on each process to set process's priority */
3316   if (CmiMyRank() == 0 && nicelevel != -100)  {
3317 #ifndef _WIN32
3318     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
3319       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
3320       perror("setpriority");
3321       CmiAbort("setpriority failed.");
3322     }
3323     else
3324       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
3325 #else
3326     HANDLE hProcess = GetCurrentProcess();
3327     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
3328     char *prio_str = "NORMAL_PRIORITY_CLASS";
3329     BOOL status;
3330     /*
3331        <-20:      real time
3332        -20--10:   high 
3333        -10-0:     above normal
3334        0:         normal
3335        0-10:      below normal
3336        10-:       idle
3337     */
3338     if (0) ;
3339 #ifdef BELOW_NORMAL_PRIORITY_CLASS
3340     else if (nicelevel<10 && nicelevel>0) {
3341       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
3342       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
3343     }
3344 #endif
3345     else if (nicelevel>0) {
3346       dwPriorityClass = IDLE_PRIORITY_CLASS;
3347       prio_str = "IDLE_PRIORITY_CLASS";
3348     }
3349     else if (nicelevel<=-20) {
3350       dwPriorityClass = REALTIME_PRIORITY_CLASS;
3351       prio_str = "REALTIME_PRIORITY_CLASS";
3352     }
3353 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
3354     else if (nicelevel>-10 && nicelevel<0) {
3355       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
3356       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
3357     }
3358 #endif
3359     else if (nicelevel<0) {
3360       dwPriorityClass = HIGH_PRIORITY_CLASS;
3361       prio_str = "HIGH_PRIORITY_CLASS";
3362     }
3363     status = SetPriorityClass(hProcess, dwPriorityClass);
3364     if (!status)  {
3365         int err=GetLastError();
3366         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
3367         CmiAbort("SetPriorityClass failed.");
3368     }
3369     else
3370       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
3371 #endif
3372   }
3373 }
3374
3375 void CommunicationServerInit()
3376 {
3377 #if CMK_IMMEDIATE_MSG
3378   CQdCpvInit();
3379   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
3380 #endif
3381 }
3382
3383
3384 static int testEndian(void)
3385 {
3386         int test=0x1c;
3387         unsigned char *c=(unsigned char *)&test;
3388         if (c[sizeof(int)-1]==0x1c)
3389                 /* Macintosh and most workstations are big-endian */
3390                 return 1;   /* Big-endian machine */
3391         if (c[0]==0x1c)
3392                 /* Intel x86 PC's, and DEC VAX are little-endian */
3393                 return 0;  /* Little-endian machine */
3394         return -2;  /*Unknown integer type */
3395 }
3396
3397 int CmiEndianness()
3398 {
3399   static int _cmi_endianness = -1;
3400   if (_cmi_endianness == -1) _cmi_endianness = testEndian();
3401   CmiAssert(_cmi_endianness != -2);
3402   return  _cmi_endianness;
3403 }
3404
3405 /**
3406   Main Converse initialization routine.  This routine is 
3407   called by the machine file (machine.c) to set up Converse.
3408   It's "Common" because it's shared by all the machine.c files. 
3409   
3410   The main task of this routine is to set up all the Cpv's
3411   (message queues, handler tables, etc.) used during main execution.
3412   
3413   On SMP versions, this initialization routine is called by 
3414   *all* processors of a node simultaniously.  It's *also* called
3415   by the communication thread, which is rather strange but needed
3416   for immediate messages.  Each call to this routine expects a 
3417   different copy of the argv arguments, so use CmiCopyArgs(argv).
3418   
3419   Requires:
3420     - A working network layer.
3421     - Working Cpv's and CmiNodeBarrier.
3422     - CthInit to already have been called.  CthInit is called
3423       from the machine layer directly, because some machine layers
3424       (like uth) use Converse threads internally.
3425
3426   Initialization is somewhat subtle, in that various modules
3427   won't work properly until they're initialized.  For example,
3428   nobody can register handlers before calling CmiHandlerInit.
3429 */
3430 void ConverseCommonInit(char **argv)
3431 {
3432
3433 /**
3434  * The reason to initialize this variable here:
3435  * cmiArgDebugFlag is possibly accessed in CmiPrintf/CmiError etc.,
3436  * therefore, we have to initialize this variable before any calls
3437  * to those functions (such as CmiPrintf). Otherwise, we may encounter
3438  * a memory segmentation fault (bad memory access). Note, even
3439  * testing CpvInitialized(cmiArgDebugFlag) doesn't help to solve
3440  * this problem because the variable indicating whether cmiArgDebugFlag is 
3441  * initialized or not is not initialized, thus possibly causing another
3442  * bad memory access. --Chao Mei
3443  */
3444 #if CMK_CCS_AVAILABLE
3445   CpvInitialize(int, cmiArgDebugFlag);
3446   CpvAccess(cmiArgDebugFlag) = 0;
3447 #endif
3448   CpvInitialize(int,charmLibExitFlag);
3449   CpvAccess(charmLibExitFlag) = 0;
3450
3451   CpvInitialize(int,_curRestartPhase);
3452   CpvAccess(_curRestartPhase)=1;
3453   CmiArgInit(argv);
3454   CmiMemoryInit(argv);
3455 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3456   CmiIOInit(argv);
3457 #endif
3458   if (CmiMyPe() == 0)
3459       CmiPrintf("Converse/Charm++ Commit ID: %s\n", CmiCommitID);
3460 /* #if CONVERSE_POOL */
3461   CmiPoolAllocInit(30);  
3462 /* #endif */
3463   CmiTmpInit(argv);
3464   CmiTimerInit(argv);
3465   CstatsInit(argv);
3466   CmiInitCPUAffinityUtil();
3467
3468   CcdModuleInit(argv);
3469   CmiHandlerInit();
3470   CmiReductionsInit();
3471   CIdleTimeoutInit(argv);
3472   
3473 #if CMK_SHARED_VARS_POSIX_THREADS_SMP /*Used by the net-*-smp versions*/
3474   if(CmiGetArgFlagDesc(argv,"+CmiNoProcForComThread","Is there an extra processor for the communication thread on each node(only for net-smp-*) ?")){
3475     if(CmiMyRank() == 0) _Cmi_noprocforcommthread=1;
3476    }
3477 #endif
3478         
3479 #if CMK_TRACE_ENABLED
3480   traceInit(argv);
3481 /*initTraceCore(argv);*/ /* projector */
3482 #endif
3483   CmiProcessPriority(argv);
3484
3485   CmiPersistentInit();
3486   CmiIsomallocInit(argv);
3487   CmiDeliversInit();
3488   CsdInit(argv);
3489 #if CMK_CCS_AVAILABLE
3490   CcsInit(argv);
3491 #endif
3492   CpdInit();
3493   CthSchedInit();
3494   CmiGroupInit();
3495   CmiMulticastInit();
3496   CmiInitMultipleSend();
3497   CQdInit();
3498
3499   CrnInit();
3500   CmiInitImmediateMsg();
3501   CldModuleInit(argv);
3502   
3503 #if CMK_CELL
3504   void CmiInitCell();
3505   CmiInitCell();
3506 #endif
3507
3508 #ifdef CMK_CUDA
3509   initHybridAPI(CmiMyPe()); 
3510 #endif
3511
3512   /* main thread is suspendable */
3513 /*
3514   CthSetSuspendable(CthSelf(), 0);
3515 */
3516
3517 #if CMK_BIGSIM_CHARM
3518    /* have to initialize QD here instead of _initCharm */
3519   extern void initQd(char **argv);
3520   initQd(argv);
3521 #endif
3522 }
3523
3524 void ConverseCommonExit(void)
3525 {
3526   CcsImpl_kill();
3527
3528 #if CMK_TRACE_ENABLED
3529   traceClose();
3530 /*closeTraceCore();*/ /* projector */
3531 #endif
3532
3533 #if CMI_IO_BUFFER_EXPLICIT
3534   CmiFlush(stdout);  /* end of program, always flush */
3535 #endif
3536
3537 #if CMK_CELL
3538   CloseOffloadAPI();
3539 #endif
3540
3541 #if CMK_CUDA
3542   exitHybridAPI(); 
3543 #endif
3544   seedBalancerExit();
3545   EmergencyExit();
3546 }
3547
3548
3549 #if CMK_CELL != 0
3550
3551 extern void register_accel_spe_funcs(void);
3552
3553 void CmiInitCell()
3554 {
3555   // Create a unique string for each PPE to use for the timing
3556   //   data file's name
3557   char fileNameBuf[64];
3558   sprintf(fileNameBuf, "speTiming.%d", CmiMyPe());
3559
3560   InitOffloadAPI(offloadCallback, NULL, NULL, fileNameBuf);
3561   //CcdCallOnConditionKeep(CcdPERIODIC, 
3562   //      (CcdVoidFn) OffloadAPIProgress, NULL);
3563   CcdCallOnConditionKeep(CcdPROCESSOR_STILL_IDLE,
3564       (CcdVoidFn) OffloadAPIProgress, NULL);
3565
3566   // Register accelerated entry methods on the PPE
3567   register_accel_spe_funcs();
3568 }
3569
3570 #include "cell-api.c"
3571
3572 #endif
3573
3574 /****
3575  * CW Lee - 9/14/2005
3576  * Added a mechanism to allow some control over machines with extremely
3577  * inefficient terminal IO mechanisms. Case in point: the XT3 has a
3578  * 20ms flush overhead along with about 25MB/s bandwidth for IO. This,
3579  * coupled with a default setup using unbuffered stdout introduced
3580  * severe overheads (and hence limiting scaling) for applications like 
3581  * NAMD.
3582  */
3583 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3584 void CmiIOInit(char **argv) {
3585   CpvInitialize(int, expIOFlushFlag);
3586 #if CMI_IO_BUFFER_EXPLICIT
3587   /* 
3588      Support for an explicit buffer only makes sense if the machine
3589      layer does not wish to make its own implementation.
3590
3591      Placing this after CmiMemoryInit() means that CmiMemoryInit()
3592      MUST NOT make use of stdout if an explicit buffer is requested.
3593
3594      The setvbuf function may only be used after opening a stream and
3595      before any other operations have been performed on it
3596   */
3597   CpvInitialize(char*, explicitIOBuffer);
3598   CpvInitialize(int, expIOBufferSize);
3599   if (!CmiGetArgIntDesc(argv,"+io_buffer_size", &CpvAccess(expIOBufferSize),
3600                         "Explicit IO Buffer Size")) {
3601     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3602   }
3603   if (CpvAccess(expIOBufferSize) <= 0) {
3604     CpvAccess(expIOBufferSize) = DEFAULT_IO_BUFFER_SIZE;
3605   }
3606   CpvAccess(explicitIOBuffer) = (char*)CmiAlloc(CpvAccess(expIOBufferSize)*
3607                                                 sizeof(char));
3608   if (setvbuf(stdout, CpvAccess(explicitIOBuffer), _IOFBF, 
3609               CpvAccess(expIOBufferSize))) {
3610     CmiAbort("Explicit IO Buffering failed\n");
3611   }
3612 #endif
3613 #if CMI_IO_FLUSH_USER
3614   /* system default to have user control flushing of IO */
3615   /* Now look for user override */
3616   CpvAccess(expIOFlushFlag) = !CmiGetArgFlagDesc(argv,"+io_flush_system",
3617                                                  "System Controls IO Flush");
3618 #else
3619   /* system default to have system handle IO flushing */
3620   /* Now look for user override */
3621   CpvAccess(expIOFlushFlag) = CmiGetArgFlagDesc(argv,"+io_flush_user",
3622                                                 "User Controls IO Flush");
3623 #endif
3624 }
3625 #endif
3626
3627 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
3628
3629 void CmiPrintf(const char *format, ...)
3630 {
3631   CpdSystemEnter();
3632   {
3633   va_list args;
3634   va_start(args,format);
3635   vfprintf(stdout,format, args);
3636   if (CpvInitialized(expIOFlushFlag) && !CpvAccess(expIOFlushFlag)) {
3637     CmiFlush(stdout);
3638   }
3639   va_end(args);
3640 #if CMK_CCS_AVAILABLE
3641   if (CpvAccess(cmiArgDebugFlag)) {
3642     va_start(args,format);
3643     print_node0(format, args);
3644     va_end(args);
3645   }
3646 #endif
3647   }
3648   CpdSystemExit();
3649 }
3650
3651 void CmiError(const char *format, ...)
3652 {
3653   CpdSystemEnter();
3654   {
3655   va_list args;
3656   va_start(args,format);
3657   vfprintf(stderr,format, args);
3658   CmiFlush(stderr);  /* stderr is always flushed */
3659   va_end(args);
3660 #if CMK_CCS_AVAILABLE
3661   if (CpvAccess(cmiArgDebugFlag)) {
3662     va_start(args,format);
3663     print_node0(format, args);
3664     va_end(args);
3665   }
3666 #endif
3667   }
3668   CpdSystemExit();
3669 }
3670
3671 #endif
3672
3673 void __cmi_assert(const char *expr, const char *file, int line)
3674 {
3675   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
3676       CmiMyPe(), expr, file, line);
3677   CmiAbort("");
3678 }
3679
3680 char *CmiCopyMsg(char *msg, int len)
3681 {
3682   char *copy = (char *)CmiAlloc(len);
3683   _MEMCHECK(copy);
3684   memcpy(copy, msg, len);
3685   return copy;
3686 }
3687
3688 unsigned char computeCheckSum(unsigned char *data, int len)
3689 {
3690   int i;
3691   unsigned char ret = 0;
3692   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
3693   return ret;
3694 }
3695
3696 /* Flag for bigsim's out-of-core emulation */
3697 int _BgOutOfCoreFlag=0; /*indicate the type of memory operation (in or out) */
3698 int _BgInOutOfCoreMode=0; /*indicate whether the emulation is in the out-of-core emulation mode */
3699
3700 #if !CMK_HAS_LOG2
3701 unsigned int CmiILog2(unsigned int val) {
3702   unsigned int log = 0u;
3703   if ( val != 0u ) {
3704       while ( val > (1u<<log) ) { log++; }
3705   }
3706   return log;
3707 }
3708 double CmiLog2(double x) {
3709   return log(x)/log(2);
3710 }
3711 #endif
3712
3713 /* for bigsim */
3714 int CmiMyRank_()
3715 {
3716   return CmiMyRank();
3717 }
3718
3719 /*@}*/