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