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