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