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