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