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