e8c08ceffa576f1725916988a91f5ea31b59a478
[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
77 #if CMK_WHEN_PROCESSOR_IDLE_USLEEP
78 #include <sys/types.h>
79 #include <sys/time.h>
80 #endif
81
82 #if CMK_TIMER_USE_TIMES
83 #include <sys/times.h>
84 #include <limits.h>
85 #include <unistd.h>
86 #endif
87
88 #if CMK_TIMER_USE_GETRUSAGE
89 #include <sys/time.h>
90 #include <sys/resource.h>
91 #endif
92
93 #if CMK_TIMER_USE_RDTSC
94 #include <string.h>
95 #include <unistd.h>
96 #include <time.h>
97 #include <stdio.h>
98 #include <sys/time.h>
99 #include <sys/resource.h>
100 #endif
101
102 #ifdef CMK_TIMER_USE_WIN32API
103 #include <stdlib.h>
104 #include <time.h>
105 #include <sys/types.h>
106 #include <sys/timeb.h>
107 #endif
108
109 #include "quiescence.h"
110
111 int cur_restart_phase = 1;      /* checkpointing/restarting phase counter */
112
113 static int CsdLocalMax = CSD_LOCAL_MAX_DEFAULT;
114
115 /*****************************************************************************
116  *
117  * Unix Stub Functions
118  *
119  ****************************************************************************/
120
121 #ifdef MEMMONITOR
122 typedef unsigned long mmulong;
123 CpvDeclare(mmulong,MemoryUsage);
124 CpvDeclare(mmulong,HiWaterMark);
125 CpvDeclare(mmulong,ReportedHiWaterMark);
126 CpvDeclare(int,AllocCount);
127 CpvDeclare(int,BlocksAllocated);
128 #endif
129
130 #define MAX_HANDLERS 512
131
132 #if CMK_NODE_QUEUE_AVAILABLE
133 void  *CmiGetNonLocalNodeQ();
134 #endif
135
136 CpvDeclare(void*, CsdSchedQueue);
137
138 #if CMK_OUT_OF_CORE
139 /* The Queue where the Prefetch Thread puts the messages from CsdSchedQueue  */
140 CpvDeclare(void*, CsdPrefetchQueue);
141 pthread_mutex_t prefetchLock;
142 #endif
143
144 #if CMK_NODE_QUEUE_AVAILABLE
145 CsvDeclare(void*, CsdNodeQueue);
146 CsvDeclare(CmiNodeLock, CsdNodeQueueLock);
147 #endif
148 CpvDeclare(int,   CsdStopFlag);
149 CpvDeclare(int,   CsdLocalCounter);
150
151 #if CONVERSE_VERSION_VMI
152 void *CMI_VMI_CmiAlloc (int size);
153 void CMI_VMI_CmiFree (void *ptr);
154 #endif
155
156 /*****************************************************************************
157  *
158  * Command-Line Argument (CLA) parsing routines.
159  *
160  *****************************************************************************/
161
162 static int usageChecked=0; /* set when argv has been searched for a usage request */
163 static int printUsage=0; /* if set, print command-line usage information */
164 static const char *CLAformatString="%20s %10s %s\n";
165
166 /* This little list of CLA's holds the argument descriptions until it's
167    safe to print them--it's needed because the net- versions don't have 
168    printf until they're pretty well started.
169  */
170 typedef struct {
171         const char *arg; /* Flag name, like "-foo"*/
172         const char *param; /* Argument's parameter type, like "integer" or "none"*/
173         const char *desc; /* Human-readable description of what it does */
174 } CLA;
175 static int CLAlistLen=0;
176 static int CLAlistMax=0;
177 static CLA *CLAlist=NULL;
178
179 /* Add this CLA */
180 static void CmiAddCLA(const char *arg,const char *param,const char *desc) {
181         int i;
182         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
183         if (desc==NULL) return; /*It's an internal argument*/
184         if (usageChecked) { /* Printf should work now */
185                 if (printUsage)
186                         CmiPrintf(CLAformatString,arg,param,desc);
187         }
188         else { /* Printf doesn't work yet-- just add to the list.
189                 This assumes the const char *'s are static references,
190                 which is probably reasonable. */
191                 i=CLAlistLen++;
192                 if (CLAlistLen>CLAlistMax) { /*Grow the CLA list */
193                         CLAlistMax=16+2*CLAlistLen;
194                         CLAlist=realloc(CLAlist,sizeof(CLA)*CLAlistMax);\
195                 }
196                 CLAlist[i].arg=arg;
197                 CLAlist[i].param=param;
198                 CLAlist[i].desc=desc;
199         }
200 }
201
202 /* Print out the stored list of CLA's */
203 static void CmiPrintCLAs(void) {
204         int i;
205         if (CmiMyPe()!=0) return; /*Don't bother if we're not PE 0*/
206         CmiPrintf("Converse Machine Command-line Parameters:\n ");
207         CmiPrintf(CLAformatString,"Option:","Parameter:","Description:");
208         for (i=0;i<CLAlistLen;i++) {
209                 CLA *c=&CLAlist[i];
210                 CmiPrintf(CLAformatString,c->arg,c->param,c->desc);
211         }
212 }
213
214 /**
215  * Determines if command-line usage information should be printed--
216  * that is, if a "-?", "-h", or "--help" flag is present.
217  * Must be called after printf is setup.
218  */
219 void CmiArgInit(char **argv) {
220         int i;
221         for (i=0;argv[i]!=NULL;i++)
222         {
223                 if (0==strcmp(argv[i],"-?") ||
224                     0==strcmp(argv[i],"-h") ||
225                     0==strcmp(argv[i],"--help")) 
226                 {
227                         printUsage=1;
228                         /* Don't delete arg:  CmiDeleteArgs(&argv[i],1);
229                           Leave it there for user program to see... */
230                         CmiPrintCLAs();
231                 }
232         }
233         if (CmiMyPe()==0) { /* Throw away list of stored CLA's */
234                 CLAlistLen=CLAlistMax=0;
235                 free(CLAlist); CLAlist=NULL;
236         }
237         usageChecked=1;
238 }
239
240 /* Return 1 if we're currently printing command-line usage information. */
241 int CmiArgGivingUsage(void) {
242         return (CmiMyPe()==0) && printUsage;
243 }
244
245 /* Identifies the module that accepts the following command-line parameters */
246 void CmiArgGroup(const char *parentName,const char *groupName) {
247         if (CmiArgGivingUsage()) {
248                 if (groupName==NULL) groupName=parentName; /* Start of a new group */
249                 CmiPrintf("\n%s Command-line Parameters:\n",groupName);
250         }
251 }
252
253 /*Count the number of non-NULL arguments in list*/
254 int CmiGetArgc(char **argv)
255 {
256         int i=0,argc=0;
257         while (argv[i++]!=NULL)
258                 argc++;
259         return argc;
260 }
261
262 /*Return a new, heap-allocated copy of the argv array*/
263 char **CmiCopyArgs(char **argv)
264 {
265         int argc=CmiGetArgc(argv);
266         char **ret=(char **)malloc(sizeof(char *)*(argc+1));
267         int i;
268         for (i=0;i<=argc;i++)
269                 ret[i]=argv[i];
270         return ret;
271 }
272
273 /*Delete the first k argument from the given list, shifting
274 all other arguments down by k spaces.
275 e.g., argv=={"a","b","c","d",NULL}, k==3 modifies
276 argv={"d",NULL,"c","d",NULL}
277 */
278 void CmiDeleteArgs(char **argv,int k)
279 {
280         int i=0;
281         while ((argv[i]=argv[i+k])!=NULL)
282                 i++;
283 }
284
285 /*Find the given argment and string option in argv.
286 If the argument is present, set the string option and
287 delete both from argv.  If not present, return NULL.
288 e.g., arg=="-name" returns "bob" from
289 argv=={"a.out","foo","-name","bob","bar"},
290 and sets argv={"a.out","foo","bar"};
291 */
292 int CmiGetArgStringDesc(char **argv,const char *arg,char **optDest,const char *desc)
293 {
294         int i;
295         CmiAddCLA(arg,"string",desc);
296         for (i=0;argv[i]!=NULL;i++)
297                 if (0==strcmp(argv[i],arg))
298                 {/*We found the argument*/
299                         if (argv[i+1]==NULL) CmiAbort("Argument not complete!");
300                         *optDest=argv[i+1];
301                         CmiDeleteArgs(&argv[i],2);
302                         return 1;
303                 }
304         return 0;/*Didn't find the argument*/
305 }
306 int CmiGetArgString(char **argv,const char *arg,char **optDest) {
307         return CmiGetArgStringDesc(argv,arg,optDest,"");
308 }
309
310 /*Find the given argument and floating-point option in argv.
311 Remove it and return 1; or return 0.
312 */
313 int CmiGetArgDoubleDesc(char **argv,const char *arg,double *optDest,const char *desc) {
314         char *number=NULL;
315         CmiAddCLA(arg,"number",desc);
316         if (!CmiGetArgStringDesc(argv,arg,&number,NULL)) return 0;
317         if (1!=sscanf(number,"%lg",optDest)) return 0;
318         return 1;
319 }
320 int CmiGetArgDouble(char **argv,const char *arg,double *optDest) {
321         return CmiGetArgDoubleDesc(argv,arg,optDest,"");
322 }
323
324 /*Find the given argument and integer option in argv.
325 If the argument is present, parse and set the numeric option,
326 delete both from argv, and return 1. If not present, return 0.
327 e.g., arg=="-pack" matches argv=={...,"-pack","27",...},
328 argv=={...,"-pack0xf8",...}, and argv=={...,"-pack=0777",...};
329 but not argv=={...,"-packsize",...}.
330 */
331 int CmiGetArgIntDesc(char **argv,const char *arg,int *optDest,const char *desc)
332 {
333         int i;
334         int argLen=strlen(arg);
335         CmiAddCLA(arg,"integer",desc);
336         for (i=0;argv[i]!=NULL;i++)
337                 if (0==strncmp(argv[i],arg,argLen))
338                 {/*We *may* have found the argument*/
339                         const char *opt=NULL;
340                         int nDel=0;
341                         switch(argv[i][argLen]) {
342                         case 0: /* like "-p","27" */
343                                 opt=argv[i+1]; nDel=2; break;
344                         case '=': /* like "-p=27" */
345                                 opt=&argv[i][argLen+1]; nDel=1; break;
346                         case '-':case '+':
347                         case '0':case '1':case '2':case '3':case '4':
348                         case '5':case '6':case '7':case '8':case '9':
349                                 /* like "-p27" */
350                                 opt=&argv[i][argLen]; nDel=1; break;
351                         default:
352                                 continue; /*False alarm-- skip it*/
353                         }
354                         if (opt==NULL) continue; /*False alarm*/
355                         if (sscanf(opt,"%i",optDest)<1) {
356                         /*Bad command line argument-- die*/
357                                 fprintf(stderr,"Cannot parse %s option '%s' "
358                                         "as an integer.\n",arg,opt);
359                                 CmiAbort("Bad command-line argument\n");
360                         }
361                         CmiDeleteArgs(&argv[i],nDel);
362                         return 1;
363                 }
364         return 0;/*Didn't find the argument-- dest is unchanged*/       
365 }
366 int CmiGetArgInt(char **argv,const char *arg,int *optDest) {
367         return CmiGetArgIntDesc(argv,arg,optDest,"");
368 }
369
370 /*Find the given argument in argv.  If present, delete
371 it and return 1; if not present, return 0.
372 e.g., arg=="-foo" matches argv=={...,"-foo",...} but not
373 argv={...,"-foobar",...}.
374 */
375 int CmiGetArgFlagDesc(char **argv,const char *arg,const char *desc)
376 {
377         int i;
378         CmiAddCLA(arg,"",desc);
379         for (i=0;argv[i]!=NULL;i++)
380                 if (0==strcmp(argv[i],arg))
381                 {/*We found the argument*/
382                         CmiDeleteArgs(&argv[i],1);
383                         return 1;
384                 }
385         return 0;/*Didn't find the argument*/
386 }
387 int CmiGetArgFlag(char **argv,const char *arg) {
388         return CmiGetArgFlagDesc(argv,arg,"");
389 }
390
391
392 /*****************************************************************************
393  *
394  * Stack tracing routines.
395  *
396  *****************************************************************************/
397 #include "cmibacktrace.c"
398
399 /*
400 Convert "X(Y) Z" to "Y Z"-- remove text prior to first '(', and supress
401 the next parenthesis.  Operates in-place on the character data.
402 */
403 static char *_implTrimParenthesis(char *str) {
404   char *lParen=str, *ret=NULL, *rParen=NULL;
405   while (*lParen!='(') {
406     if (*lParen==0) return str; /* No left parenthesis at all. */
407     lParen++;
408   }
409   /* now *lParen=='(', so trim it*/
410   ret=lParen+1;
411   rParen=ret;
412   while (*rParen!=')') {
413     if (*rParen==0) return ret; /* No right parenthesis at all. */
414     rParen++;
415   }
416   /* now *rParen==')', so trim it*/
417   *rParen=' ';
418   return ret;  
419 }
420
421 /*
422 Return the text description of this trimmed routine name, if 
423 it's a system-generated routine where we should stop printing. 
424 This is probably overkill, but improves the appearance of callbacks.
425 */
426 static const char* _implGetBacktraceSys(const char *name) {
427   if (0==strncmp(name,"_call",5)) 
428   { /*it might be something we're interested in*/
429     if (0==strncmp(name,"_call_",6)) return "Call Entry Method";
430     if (0==strncmp(name,"_callthr_",9)) return "Call Threaded Entry Method";
431   }
432   if (0==strncmp(name,"CthResume",9)) return "Resumed thread";
433   if (0==strncmp(name,"qt_args",7)) return "Converse thread";
434   
435   return 0; /*ordinary user routine-- just print normally*/
436 }
437
438 /** Print out the names of these function pointers. */
439 void CmiBacktracePrint(void **retPtrs,int nLevels) {
440   if (nLevels>0) {
441     int i;
442     char **names=CmiBacktraceLookup(retPtrs,nLevels);
443     if (names==NULL) return;
444     CmiPrintf("Stack Traceback:\n");
445     for (i=0;i<nLevels;i++) {
446       const char *trimmed=_implTrimParenthesis(names[i]);
447       const char *print=trimmed;
448       const char *sys=_implGetBacktraceSys(print);
449       if (sys) {
450           CmiPrintf("  [%d] Charm++ Runtime: %s (%s)\n",i,sys,print);
451           break; /*Stop when we hit Charm++ runtime.*/
452       } else {
453           CmiPrintf("  [%d] %s\n",i,print);
454       }
455     }
456     free(names);
457   }
458 }
459
460 /* Print (to stdout) the names of the functions that have been 
461    called up to this point. nSkip is the number of routines on the
462    top of the stack to *not* print out. */
463 void CmiPrintStackTrace(int nSkip) {
464 #if CMK_USE_BACKTRACE
465         int nLevels=max_stack;
466         void *stackPtrs[max_stack];
467         CmiBacktraceRecord(stackPtrs,1+nSkip,&nLevels);
468         CmiBacktracePrint(stackPtrs,nLevels);
469 #endif
470 }
471
472 /*****************************************************************************
473  *
474  * Statistics: currently, the following statistics are not updated by converse.
475  *
476  *****************************************************************************/
477
478 CpvDeclare(int, CstatsMaxChareQueueLength);
479 CpvDeclare(int, CstatsMaxForChareQueueLength);
480 CpvDeclare(int, CstatsMaxFixedChareQueueLength);
481 CpvStaticDeclare(int, CstatPrintQueueStatsFlag);
482 CpvStaticDeclare(int, CstatPrintMemStatsFlag);
483
484 void CstatsInit(argv)
485 char **argv;
486 {
487
488 #ifdef MEMMONITOR
489   CpvInitialize(mmulong,MemoryUsage);
490   CpvAccess(MemoryUsage) = 0;
491   CpvInitialize(mmulong,HiWaterMark);
492   CpvAccess(HiWaterMark) = 0;
493   CpvInitialize(mmulong,ReportedHiWaterMark);
494   CpvAccess(ReportedHiWaterMark) = 0;
495   CpvInitialize(int,AllocCount);
496   CpvAccess(AllocCount) = 0;
497   CpvInitialize(int,BlocksAllocated);
498   CpvAccess(BlocksAllocated) = 0;
499 #endif
500
501   CpvInitialize(int, CstatsMaxChareQueueLength);
502   CpvInitialize(int, CstatsMaxForChareQueueLength);
503   CpvInitialize(int, CstatsMaxFixedChareQueueLength);
504   CpvInitialize(int, CstatPrintQueueStatsFlag);
505   CpvInitialize(int, CstatPrintMemStatsFlag);
506
507   CpvAccess(CstatsMaxChareQueueLength) = 0;
508   CpvAccess(CstatsMaxForChareQueueLength) = 0;
509   CpvAccess(CstatsMaxFixedChareQueueLength) = 0;
510   CpvAccess(CstatPrintQueueStatsFlag) = 0;
511   CpvAccess(CstatPrintMemStatsFlag) = 0;
512
513 #if 0
514   if (CmiGetArgFlagDesc(argv,"+mems", "Print memory statistics at shutdown"))
515     CpvAccess(CstatPrintMemStatsFlag)=1;
516   if (CmiGetArgFlagDesc(argv,"+qs", "Print queue statistics at shutdown"))
517     CpvAccess(CstatPrintQueueStatsFlag)=1;
518 #endif
519 }
520
521 int CstatMemory(i)
522 int i;
523 {
524   return 0;
525 }
526
527 int CstatPrintQueueStats()
528 {
529   return CpvAccess(CstatPrintQueueStatsFlag);
530 }
531
532 int CstatPrintMemStats()
533 {
534   return CpvAccess(CstatPrintMemStatsFlag);
535 }
536
537 /*****************************************************************************
538  *
539  * Cmi handler registration
540  *
541  *****************************************************************************/
542
543 CpvDeclare(CmiHandlerInfo*, CmiHandlerTable);
544 CpvStaticDeclare(int  , CmiHandlerCount);
545 CpvStaticDeclare(int  , CmiHandlerLocal);
546 CpvStaticDeclare(int  , CmiHandlerGlobal);
547 CpvDeclare(int,         CmiHandlerMax);
548
549 static void CmiExtendHandlerTable(int atLeastLen) {
550     int max = CpvAccess(CmiHandlerMax);
551     int newmax = (atLeastLen+(atLeastLen>>2)+32);
552     int bytes = max*sizeof(CmiHandlerInfo);
553     int newbytes = newmax*sizeof(CmiHandlerInfo);
554     CmiHandlerInfo *nu = (CmiHandlerInfo*)malloc(newbytes);
555     CmiHandlerInfo *tab = CpvAccess(CmiHandlerTable);
556     _MEMCHECK(nu);
557     memcpy(nu, tab, bytes);
558     memset(((char *)nu)+bytes, 0, (newbytes-bytes));
559     free(tab); tab=nu;
560     CpvAccess(CmiHandlerTable) = tab;
561     CpvAccess(CmiHandlerMax) = newmax;
562 }
563
564 void CmiNumberHandler(int n, CmiHandler h)
565 {
566   CmiHandlerInfo *tab;
567   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
568   tab = CpvAccess(CmiHandlerTable);
569   tab[n].hdlr = (CmiHandlerEx)h; /* LIE!  This assumes extra pointer will be ignored!*/
570   tab[n].userPtr = 0;
571 }
572 void CmiNumberHandlerEx(int n, CmiHandlerEx h,void *userPtr) {
573   CmiHandlerInfo *tab;
574   if (n >= CpvAccess(CmiHandlerMax)) CmiExtendHandlerTable(n);
575   tab = CpvAccess(CmiHandlerTable);
576   tab[n].hdlr = h;
577   tab[n].userPtr=userPtr;
578 }
579
580 #if CMI_LOCAL_GLOBAL_AVAILABLE /*Leave room for local and global handlers*/
581 #  define DIST_BETWEEN_HANDLERS 3
582 #else /*No local or global handlers; ordinary handlers are back-to-back*/
583 #  define DIST_BETWEEN_HANDLERS 1
584 #endif
585
586 int CmiRegisterHandler(CmiHandler h)
587 {
588   int Count = CpvAccess(CmiHandlerCount);
589   CmiNumberHandler(Count, h);
590   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
591   return Count;
592 }
593 int CmiRegisterHandlerEx(CmiHandlerEx h,void *userPtr)
594 {
595   int Count = CpvAccess(CmiHandlerCount);
596   CmiNumberHandlerEx(Count, h, userPtr);
597   CpvAccess(CmiHandlerCount) = Count+DIST_BETWEEN_HANDLERS;
598   return Count;
599 }
600
601
602 #if CMI_LOCAL_GLOBAL_AVAILABLE
603 int CmiRegisterHandlerLocal(h)
604 CmiHandler h;
605 {
606   int Local = CpvAccess(CmiHandlerLocal);
607   CmiNumberHandler(Local, h);
608   CpvAccess(CmiHandlerLocal) = Local+3;
609   return Local;
610 }
611
612 int CmiRegisterHandlerGlobal(h)
613 CmiHandler h;
614 {
615   int Global = CpvAccess(CmiHandlerGlobal);
616   if (CmiMyPe()!=0) 
617     CmiError("CmiRegisterHandlerGlobal must only be called on PE 0.\n");
618   CmiNumberHandler(Global, h);
619   CpvAccess(CmiHandlerGlobal) = Global+3;
620   return Global;
621 }
622 #endif
623
624 static void _cmiZeroHandler(void *msg) {
625         CmiAbort("Converse zero handler executed-- was a message corrupted?\n");
626 }
627
628 static void CmiHandlerInit()
629 {
630   CpvInitialize(CmiHandlerInfo *, CmiHandlerTable);
631   CpvInitialize(int         , CmiHandlerCount);
632   CpvInitialize(int         , CmiHandlerLocal);
633   CpvInitialize(int         , CmiHandlerGlobal);
634   CpvInitialize(int         , CmiHandlerMax);
635   CpvAccess(CmiHandlerCount)  = 0;
636   CpvAccess(CmiHandlerLocal)  = 1;
637   CpvAccess(CmiHandlerGlobal) = 2;
638   CpvAccess(CmiHandlerMax) = 0; /* Table will be extended on the first registration*/
639   CpvAccess(CmiHandlerTable) = NULL;
640   CmiRegisterHandler((CmiHandler)_cmiZeroHandler);
641 }
642
643
644 /******************************************************************************
645  *
646  * CmiTimer
647  *
648  * Here are two possible implementations of CmiTimer.  Some machines don't
649  * select either, and define the timer in machine.c instead.
650  *
651  *****************************************************************************/
652
653 #if CMK_TIMER_USE_TIMES
654
655 CpvStaticDeclare(double, clocktick);
656 CpvStaticDeclare(int,inittime_wallclock);
657 CpvStaticDeclare(int,inittime_virtual);
658
659 int CmiTimerIsSynchronized()
660 {
661   return 0;
662 }
663
664 void CmiTimerInit()
665 {
666   struct tms temp;
667   CpvInitialize(double, clocktick);
668   CpvInitialize(int, inittime_wallclock);
669   CpvInitialize(int, inittime_virtual);
670   CpvAccess(inittime_wallclock) = times(&temp);
671   CpvAccess(inittime_virtual) = temp.tms_utime + temp.tms_stime;
672   CpvAccess(clocktick) = 1.0 / (sysconf(_SC_CLK_TCK));
673 }
674
675 double CmiWallTimer()
676 {
677   struct tms temp;
678   double currenttime;
679   int now;
680
681   now = times(&temp);
682   currenttime = (now - CpvAccess(inittime_wallclock)) * CpvAccess(clocktick);
683   return (currenttime);
684 }
685
686 double CmiCpuTimer()
687 {
688   struct tms temp;
689   double currenttime;
690   int now;
691
692   times(&temp);
693   now = temp.tms_stime + temp.tms_utime;
694   currenttime = (now - CpvAccess(inittime_virtual)) * CpvAccess(clocktick);
695   return (currenttime);
696 }
697
698 double CmiTimer()
699 {
700   return CmiCpuTimer();
701 }
702
703 #endif
704
705 #if CMK_TIMER_USE_GETRUSAGE
706
707 static double inittime_wallclock;
708 CpvStaticDeclare(double, inittime_virtual);
709
710 int CmiTimerIsSynchronized()
711 {
712   return 0;
713 }
714
715 void CmiTimerInit()
716 {
717   struct timeval tv;
718   struct rusage ru;
719   CpvInitialize(double, inittime_virtual);
720
721   /* try to synchronize calling barrier */
722   CmiBarrier();
723   CmiBarrier();
724   CmiBarrier();
725
726   gettimeofday(&tv,0);
727   inittime_wallclock = (tv.tv_sec * 1.0) + (tv.tv_usec*0.000001);
728   getrusage(0, &ru); 
729   CpvAccess(inittime_virtual) =
730     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
731     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
732
733   CmiBarrierZero();
734 }
735
736 double CmiCpuTimer()
737 {
738   struct rusage ru;
739   double currenttime;
740
741   getrusage(0, &ru);
742   currenttime =
743     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
744     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
745   return currenttime - CpvAccess(inittime_virtual);
746 }
747
748 double CmiWallTimer()
749 {
750   struct timeval tv;
751   double currenttime;
752
753   gettimeofday(&tv,0);
754   currenttime = (tv.tv_sec * 1.0) + (tv.tv_usec * 0.000001);
755   return currenttime - inittime_wallclock;
756 }
757
758 double CmiTimer()
759 {
760   return CmiCpuTimer();
761 }
762
763 #endif
764
765 #if CMK_TIMER_USE_RDTSC
766
767 static double readMHz(void)
768 {
769   double x;
770   char str[1000];
771   char buf[100];
772   FILE *fp = fopen("/proc/cpuinfo", "r");
773   while(fgets(str, 1000, fp)!=0) {
774     if(sscanf(str, "cpu MHz%[^:]",buf)==1)
775     {
776       char *s = strchr(str, ':'); s=s+1;
777       sscanf(s, "%lf", &x);
778       fclose(fp);
779       return x;
780     }
781   }
782   CmiAbort("Cannot read CPU MHz from /proc/cpuinfo file.");
783   return 0.0;
784 }
785
786 double _cpu_speed_factor;
787 CpvStaticDeclare(double, inittime_virtual);
788 CpvStaticDeclare(double, inittime_walltime);
789
790 double  CmiStartTimer(void)
791 {
792   return CpvAccess(inittime_walltime);
793 }
794
795 void CmiTimerInit()
796 {
797   struct rusage ru;
798
799   CmiBarrier();
800   CmiBarrier();
801
802   _cpu_speed_factor = 1.0/(readMHz()*1.0e6); 
803   rdtsc(); rdtsc(); rdtsc(); rdtsc(); rdtsc();
804   CpvInitialize(double, inittime_walltime);
805   CpvAccess(inittime_walltime) = CmiWallTimer();
806   CpvInitialize(double, inittime_virtual);
807   getrusage(0, &ru); 
808   CpvAccess(inittime_virtual) =
809     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
810     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
811
812   CmiBarrierZero();
813 }
814
815 double CmiCpuTimer()
816 {
817   struct rusage ru;
818   double currenttime;
819
820   getrusage(0, &ru);
821   currenttime =
822     (ru.ru_utime.tv_sec * 1.0)+(ru.ru_utime.tv_usec * 0.000001) +
823     (ru.ru_stime.tv_sec * 1.0)+(ru.ru_stime.tv_usec * 0.000001);
824   return currenttime - CpvAccess(inittime_virtual);
825 }
826
827 #endif
828
829 #if CMK_TIMER_USE_BLUEGENEL
830
831 #include <rts.h>
832
833 #if 0
834 #define SPRN_TBRL 0x10C  // Time Base Read Lower Register (user & sup R/O)
835 #define SPRN_TBRU 0x10D  // Time Base Read Upper Register (user & sup R/O)
836 #define SPRN_PIR  0x11E  // CPU id
837
838 static inline unsigned long long BGLTimebase(void)
839 {
840   unsigned volatile u1, u2, lo;
841   union
842   {
843     struct { unsigned hi, lo; } w;
844     unsigned long long d;
845   } result;
846                                                                                 
847   do {
848     asm volatile ("mfspr %0,%1" : "=r" (u1) : "i" (SPRN_TBRU));
849     asm volatile ("mfspr %0,%1" : "=r" (lo) : "i" (SPRN_TBRL));
850     asm volatile ("mfspr %0,%1" : "=r" (u2) : "i" (SPRN_TBRU));
851   } while (u1!=u2);
852                                                                                 
853   result.w.lo = lo;
854   result.w.hi = u2;
855   return result.d;
856 }
857 #endif
858
859 static unsigned long long inittime_wallclock;
860 CpvStaticDeclare(double, clocktick);
861
862 int CmiTimerIsSynchronized()
863 {
864   return 0;
865 }
866
867 void CmiTimerInit()
868 {
869   BGLPersonality dst;
870   CpvInitialize(double, clocktick);
871   int size = sizeof(BGLPersonality);
872   rts_get_personality(&dst, size);
873   CpvAccess(clocktick) = 1.0 / dst.clockHz;
874
875   /* try to synchronize calling barrier */
876   CmiBarrier();
877   CmiBarrier();
878   CmiBarrier();
879
880   inittime_wallclock = rts_get_timebase();
881 }
882
883 double CmiWallTimer()
884 {
885   unsigned long long currenttime;
886   currenttime = rts_get_timebase();
887   return CpvAccess(clocktick)*(currenttime-inittime_wallclock);
888 }
889
890 double CmiCpuTimer()
891 {
892   return CmiWallTimer();
893 }
894
895 double CmiTimer()
896 {
897   return CmiWallTimer();
898 }
899
900 #endif
901
902 #if CMK_TIMER_USE_WIN32API
903
904 CpvStaticDeclare(double, inittime_wallclock);
905 CpvStaticDeclare(double, inittime_virtual);
906
907 void CmiTimerInit()
908 {
909 #ifdef __CYGWIN__
910         struct timeb tv;
911 #else
912         struct _timeb tv;
913 #endif
914         clock_t       ru;
915
916         CpvInitialize(double, inittime_wallclock);
917         CpvInitialize(double, inittime_virtual);
918         _ftime(&tv);
919         CpvAccess(inittime_wallclock) = tv.time*1.0 + tv.millitm*0.001;
920         ru = clock();
921         CpvAccess(inittime_virtual) = ((double) ru)/CLOCKS_PER_SEC;
922 }
923
924 double CmiCpuTimer()
925 {
926         clock_t ru;
927         double currenttime;
928
929         ru = clock();
930         currenttime = (double) ru/CLOCKS_PER_SEC;
931
932         return currenttime - CpvAccess(inittime_virtual);
933 }
934
935 double CmiWallTimer()
936 {
937 #ifdef __CYGWIN__
938         struct timeb tv;
939 #else
940         struct _timeb tv;
941 #endif
942         double currenttime;
943
944         _ftime(&tv);
945         currenttime = tv.time*1.0 + tv.millitm*0.001;
946
947         return currenttime - CpvAccess(inittime_wallclock);
948 }
949         
950
951 double CmiTimer()
952 {
953         return CmiCpuTimer();
954 }
955
956 #endif
957
958 #if CMK_TIMER_USE_RTC
959
960 #if __crayx1
961  /* For _rtc() on Cray X1 */
962 #include <intrinsics.h>
963 #endif
964
965 static double clocktick;
966 CpvStaticDeclare(long long, inittime_wallclock);
967
968 void CmiTimerInit()
969 {
970   CpvInitialize(long long, inittime_wallclock);
971   CpvAccess(inittime_wallclock) = _rtc();
972   clocktick = 1.0 / (double)(sysconf(_SC_SV2_USER_TIME_RATE));
973 }
974
975 double CmiWallTimer()
976 {
977   long long now;
978
979   now = _rtc();
980   return (clocktick * (now - CpvAccess(inittime_wallclock)));
981 }
982
983 double CmiCpuTimer()
984 {
985   return CmiWallTimer();
986 }
987
988 double CmiTimer()
989 {
990   return CmiCpuTimer();
991 }
992
993 #endif
994
995 #ifndef CMK_USE_SPECIAL_MESSAGE_QUEUE_CHECK
996 /** Return 1 if our outgoing message queue 
997    for this node is longer than this many bytes. */
998 int CmiLongSendQueue(int forNode,int longerThanBytes) {
999   return 0;
1000 }
1001 #endif
1002
1003 #if CMK_SIGNAL_USE_SIGACTION
1004 #include <signal.h>
1005 void CmiSignal(sig1, sig2, sig3, handler)
1006 int sig1, sig2, sig3;
1007 void (*handler)();
1008 {
1009   struct sigaction in, out ;
1010   in.sa_handler = handler;
1011   sigemptyset(&in.sa_mask);
1012   if (sig1) sigaddset(&in.sa_mask, sig1);
1013   if (sig2) sigaddset(&in.sa_mask, sig2);
1014   if (sig3) sigaddset(&in.sa_mask, sig3);
1015   in.sa_flags = 0;
1016   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1017   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1018   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1019 }
1020 #endif
1021
1022 #if CMK_SIGNAL_USE_SIGACTION_WITH_RESTART
1023 #include <signal.h>
1024 void CmiSignal(sig1, sig2, sig3, handler)
1025 int sig1, sig2, sig3;
1026 void (*handler)();
1027 {
1028   struct sigaction in, out ;
1029   in.sa_handler = handler;
1030   sigemptyset(&in.sa_mask);
1031   if (sig1) sigaddset(&in.sa_mask, sig1);
1032   if (sig2) sigaddset(&in.sa_mask, sig2);
1033   if (sig3) sigaddset(&in.sa_mask, sig3);
1034   in.sa_flags = SA_RESTART;
1035   if (sig1) if (sigaction(sig1, &in, &out)<0) exit(1);
1036   if (sig2) if (sigaction(sig2, &in, &out)<0) exit(1);
1037   if (sig3) if (sigaction(sig3, &in, &out)<0) exit(1);
1038 }
1039 #endif
1040
1041 /*****************************************************************************
1042  *
1043  * The following is the CsdScheduler function.  A common
1044  * implementation is provided below.  The machine layer can provide an
1045  * alternate implementation if it so desires.
1046  *
1047  * void CmiDeliversInit()
1048  *
1049  *      - CmiInit promises to call this before calling CmiDeliverMsgs
1050  *        or any of the other functions in this section.
1051  *
1052  * int CmiDeliverMsgs(int maxmsgs)
1053  *
1054  *      - CmiDeliverMsgs will retrieve up to maxmsgs that were transmitted
1055  *        with the Cmi, and will invoke their handlers.  It does not wait
1056  *        if no message is unavailable.  Instead, it returns the quantity
1057  *        (maxmsgs-delivered), where delivered is the number of messages it
1058  *        delivered.
1059  *
1060  * void CmiDeliverSpecificMsg(int handlerno)
1061  *
1062  *      - Waits for a message with the specified handler to show up, then
1063  *        invokes the message's handler.  Note that unlike CmiDeliverMsgs,
1064  *        This function _does_ wait.
1065  *
1066  * For this common implementation to work, the machine layer must provide the
1067  * following:
1068  *
1069  * void *CmiGetNonLocal()
1070  *
1071  *      - returns a message just retrieved from some other PE, not from
1072  *        local.  If no such message exists, returns 0.
1073  *
1074  * CpvExtern(CdsFifo, CmiLocalQueue);
1075  *
1076  *      - a FIFO queue containing all messages from the local processor.
1077  *
1078  *****************************************************************************/
1079
1080 void CsdBeginIdle(void)
1081 {
1082   CcdCallBacks();
1083   _LOG_E_PROC_IDLE();   /* projector */
1084   CcdRaiseCondition(CcdPROCESSOR_BEGIN_IDLE) ;
1085 }
1086
1087 void CsdStillIdle(void)
1088 {
1089   CcdRaiseCondition(CcdPROCESSOR_STILL_IDLE);
1090 }
1091
1092 void CsdEndIdle(void)
1093 {
1094   _LOG_E_PROC_BUSY();   /* projector */
1095   CcdRaiseCondition(CcdPROCESSOR_BEGIN_BUSY) ;
1096 }
1097
1098 #if CMK_MEM_CHECKPOINT
1099 #define MESSAGE_PHASE_CHECK     \
1100         {       \
1101           int phase = CmiGetRestartPhase(msg);  \
1102           if (phase < cur_restart_phase) {      \
1103             /*CmiPrintf("[%d] discard message of phase %d cur_restart_phase:%d handler:%d. \n", CmiMyPe(), phase, cur_restart_phase, handler);*/        \
1104             CmiFree(msg);       \
1105             return;     \
1106           }     \
1107         }
1108 #else
1109 #define MESSAGE_PHASE_CHECK
1110 #endif
1111
1112 void CmiHandleMessage(void *msg)
1113 {
1114 /* this is wrong because it counts the Charm++ messages in sched queue
1115         CpvAccess(cQdState)->mProcessed++;
1116 */
1117         CmiHandlerInfo *h;
1118 #ifndef CMK_OPTIMIZE
1119         CmiUInt2 handler=CmiGetHandler(msg); /* Save handler for use after msg is gone */
1120         _LOG_E_HANDLER_BEGIN(handler); /* projector */
1121 #endif
1122
1123         MESSAGE_PHASE_CHECK
1124
1125         h=&CmiGetHandlerInfo(msg);
1126         (h->hdlr)(msg,h->userPtr);
1127 #ifndef CMK_OPTIMIZE
1128         _LOG_E_HANDLER_END(handler);    /* projector */
1129 #endif
1130 }
1131
1132 #if CMK_CMIDELIVERS_USE_COMMON_CODE
1133
1134 void CmiDeliversInit()
1135 {
1136 }
1137
1138 int CmiDeliverMsgs(int maxmsgs)
1139 {
1140   return CsdScheduler(maxmsgs);
1141 }
1142
1143 #if CMK_OBJECT_QUEUE_AVAILABLE
1144 CpvDeclare(void *, CsdObjQueue);
1145 #endif
1146
1147 void CsdSchedulerState_new(CsdSchedulerState_t *s)
1148 {
1149 #if CMK_OBJECT_QUEUE_AVAILABLE
1150         s->objQ=CpvAccess(CsdObjQueue);
1151 #endif
1152         s->localQ=CpvAccess(CmiLocalQueue);
1153         s->schedQ=CpvAccess(CsdSchedQueue);
1154         s->localCounter=&(CpvAccess(CsdLocalCounter));
1155 #if CMK_NODE_QUEUE_AVAILABLE
1156         s->nodeQ=CsvAccess(CsdNodeQueue);
1157         s->nodeLock=CsvAccess(CsdNodeQueueLock);
1158 #endif
1159         
1160 }
1161
1162 void *CsdNextMessage(CsdSchedulerState_t *s) {
1163         void *msg;
1164         if((*(s->localCounter))-- >0)
1165           {
1166               /* This avoids a race condition with migration detected by megatest*/
1167               msg=CdsFifo_Dequeue(s->localQ);
1168               if (msg!=NULL)
1169                 {
1170                   CpvAccess(cQdState)->mProcessed++;
1171                   return msg;       
1172                 }
1173               CqsDequeue(s->schedQ,(void **)&msg);
1174               if (msg!=NULL) return msg;
1175           }
1176         
1177         *(s->localCounter)=CsdLocalMax;
1178         if ( NULL!=(msg=CmiGetNonLocal()) || 
1179              NULL!=(msg=CdsFifo_Dequeue(s->localQ)) ) {
1180             CpvAccess(cQdState)->mProcessed++;
1181             return msg;
1182         }
1183 #if CMK_NODE_QUEUE_AVAILABLE
1184         if (NULL!=(msg=CmiGetNonLocalNodeQ())) return msg;
1185         if (!CqsEmpty(s->nodeQ)
1186          && !CqsPrioGT(CqsGetPriority(s->nodeQ),
1187                        CqsGetPriority(s->schedQ))) {
1188           CmiLock(s->nodeLock);
1189           CqsDequeue(s->nodeQ,(void **)&msg);
1190           CmiUnlock(s->nodeLock);
1191           if (msg!=NULL) return msg;
1192         }
1193 #endif
1194 #if CMK_OBJECT_QUEUE_AVAILABLE
1195         if (NULL!=(msg=CdsFifo_Dequeue(s->objQ))) {
1196           return msg;
1197         }
1198 #endif
1199         if(!CsdLocalMax) {
1200           CqsDequeue(s->schedQ,(void **)&msg);
1201             if (msg!=NULL) return msg;      
1202         }
1203
1204         return NULL;
1205
1206 }
1207
1208 int CsdScheduler(int maxmsgs)
1209 {
1210         if (maxmsgs<0) CsdScheduleForever();    
1211         else if (maxmsgs==0)
1212                 CsdSchedulePoll();
1213         else /*(maxmsgs>0)*/ 
1214                 return CsdScheduleCount(maxmsgs);
1215         return 0;
1216 }
1217
1218 /*Declare the standard scheduler housekeeping*/
1219 #define SCHEDULE_TOP \
1220       void *msg;\
1221       int cycle = CpvAccess(CsdStopFlag); \
1222       CsdSchedulerState_t state;\
1223       CsdSchedulerState_new(&state);\
1224
1225 /*A message is available-- process it*/
1226 #define SCHEDULE_MESSAGE \
1227       CmiHandleMessage(msg);\
1228       if (CpvAccess(CsdStopFlag) != cycle) break;\
1229
1230 /*No message available-- go (or remain) idle*/
1231 #define SCHEDULE_IDLE \
1232       if (!isIdle) {isIdle=1;CsdBeginIdle();}\
1233       else CsdStillIdle();\
1234       if (CpvAccess(CsdStopFlag) != cycle) {\
1235         CsdEndIdle();\
1236         break;\
1237       }\
1238
1239 void CsdScheduleForever(void)
1240 {
1241   int isIdle=0;
1242   SCHEDULE_TOP
1243   while (1) {
1244     msg = CsdNextMessage(&state);
1245     if (msg) { /*A message is available-- process it*/
1246       if (isIdle) {isIdle=0;CsdEndIdle();}
1247       SCHEDULE_MESSAGE
1248     } else { /*No message available-- go (or remain) idle*/
1249       SCHEDULE_IDLE
1250     }
1251     CsdPeriodic();
1252   }
1253 }
1254 int CsdScheduleCount(int maxmsgs)
1255 {
1256   int isIdle=0;
1257   SCHEDULE_TOP
1258   while (1) {
1259     msg = CsdNextMessage(&state);
1260     if (msg) { /*A message is available-- process it*/
1261       if (isIdle) {isIdle=0;CsdEndIdle();}
1262       maxmsgs--; 
1263       SCHEDULE_MESSAGE
1264       if (maxmsgs==0) break;
1265     } else { /*No message available-- go (or remain) idle*/
1266       SCHEDULE_IDLE
1267     }
1268     CsdPeriodic();
1269   }
1270   return maxmsgs;
1271 }
1272
1273 void CsdSchedulePoll(void)
1274 {
1275   SCHEDULE_TOP
1276   while (1)
1277   {
1278         CsdPeriodic();
1279         if (NULL!=(msg = CsdNextMessage(&state)))
1280         {
1281              SCHEDULE_MESSAGE 
1282         }
1283         else break;
1284   }
1285 }
1286
1287 void CmiDeliverSpecificMsg(handler)
1288 int handler;
1289 {
1290   int *msg; int side;
1291   void *localqueue = CpvAccess(CmiLocalQueue);
1292  
1293   side = 0;
1294   while (1) {
1295     CsdPeriodic();
1296     side ^= 1;
1297     if (side) msg = CmiGetNonLocal();
1298     else      msg = CdsFifo_Dequeue(localqueue);
1299     if (msg) {
1300       if (CmiGetHandler(msg)==handler) {
1301         CpvAccess(cQdState)->mProcessed++;
1302         CmiHandleMessage(msg);
1303         return;
1304       } else {
1305         CdsFifo_Enqueue(localqueue, msg);
1306       }
1307     }
1308   }
1309 }
1310  
1311 #endif /* CMK_CMIDELIVERS_USE_COMMON_CODE */
1312
1313 /***************************************************************************
1314  *
1315  * Standin Schedulers.
1316  *
1317  * We use the following strategy to make sure somebody's always running
1318  * the scheduler (CsdScheduler).  Initially, we assume the main thread
1319  * is responsible for this.  If the main thread blocks, we create a
1320  * "standin scheduler" thread to replace it.  If the standin scheduler
1321  * blocks, we create another standin scheduler to replace that one,
1322  * ad infinitum.  Collectively, the main thread and all the standin
1323  * schedulers are called "scheduling threads".
1324  *
1325  * Suppose the main thread is blocked waiting for data, and a standin
1326  * scheduler is running instead.  Suppose, then, that the data shows
1327  * up and the main thread is CthAwakened.  This causes a token to be
1328  * pushed into the queue.  When the standin pulls the token from the
1329  * queue and handles it, the standin goes to sleep, and control shifts
1330  * back to the main thread.  In this way, unnecessary standins are put
1331  * back to sleep.  These sleeping standins are stored on the
1332  * CthSleepingStandins list.
1333  *
1334  ***************************************************************************/
1335
1336 CpvStaticDeclare(CthThread, CthMainThread);
1337 CpvStaticDeclare(CthThread, CthSchedulingThread);
1338 CpvStaticDeclare(CthThread, CthSleepingStandins);
1339 CpvStaticDeclare(int      , CthResumeNormalThreadIdx);
1340 CpvStaticDeclare(int      , CthResumeSchedulingThreadIdx);
1341
1342
1343 void CthStandinCode()
1344 {
1345   while (1) CsdScheduler(0);
1346 }
1347
1348 CthThread CthSuspendNormalThread()
1349 {
1350   return CpvAccess(CthSchedulingThread);
1351 }
1352
1353 void CthEnqueueSchedulingThread(CthThread t, int, int, unsigned int*);
1354 CthThread CthSuspendSchedulingThread();
1355
1356 CthThread CthSuspendSchedulingThread()
1357 {
1358   CthThread succ = CpvAccess(CthSleepingStandins);
1359
1360   if (succ) {
1361     CpvAccess(CthSleepingStandins) = CthGetNext(succ);
1362   } else {
1363     succ = CthCreate(CthStandinCode, 0, 256000);
1364     CthSetStrategy(succ,
1365                    CthEnqueueSchedulingThread,
1366                    CthSuspendSchedulingThread);
1367   }
1368   
1369   CpvAccess(CthSchedulingThread) = succ;
1370   return succ;
1371 }
1372
1373 void CthResumeNormalThread(CthThread t)
1374 {
1375 #ifndef CMK_OPTIMIZE
1376 #if ! CMK_TRACE_IN_CHARM
1377   if(CpvAccess(traceOn))
1378     CthTraceResume(t);
1379 /*    if(CpvAccess(_traceCoreOn)) 
1380                 resumeTraceCore();*/
1381 #endif
1382 #endif
1383     
1384   CthResume(t);
1385 }
1386
1387 void CthResumeSchedulingThread(CthThread t)
1388 {
1389   CthThread me = CthSelf();
1390   if (me == CpvAccess(CthMainThread)) {
1391     CthEnqueueSchedulingThread(me,CQS_QUEUEING_FIFO, 0, 0);
1392   } else {
1393     CthSetNext(me, CpvAccess(CthSleepingStandins));
1394     CpvAccess(CthSleepingStandins) = me;
1395   }
1396   CpvAccess(CthSchedulingThread) = t;
1397 #ifndef CMK_OPTIMIZE
1398 #if ! CMK_TRACE_IN_CHARM
1399   if(CpvAccess(traceOn))
1400     CthTraceResume(t);
1401 /*    if(CpvAccess(_traceCoreOn)) 
1402                 resumeTraceCore();*/
1403 #endif
1404 #endif
1405   CthResume(t);
1406 }
1407
1408 void CthEnqueueNormalThread(CthThread t, int s, 
1409                                    int pb,unsigned int *prio)
1410 {
1411   CmiSetHandler(t, CpvAccess(CthResumeNormalThreadIdx));
1412   CsdEnqueueGeneral(t, s, pb, prio);
1413 }
1414
1415 void CthEnqueueSchedulingThread(CthThread t, int s, 
1416                                        int pb,unsigned int *prio)
1417 {
1418   CmiSetHandler(t, CpvAccess(CthResumeSchedulingThreadIdx));
1419   CsdEnqueueGeneral(t, s, pb, prio);
1420 }
1421
1422 void CthSetStrategyDefault(CthThread t)
1423 {
1424   CthSetStrategy(t,
1425                  CthEnqueueNormalThread,
1426                  CthSuspendNormalThread);
1427 }
1428
1429 void CthSchedInit()
1430 {
1431   CpvInitialize(CthThread, CthMainThread);
1432   CpvInitialize(CthThread, CthSchedulingThread);
1433   CpvInitialize(CthThread, CthSleepingStandins);
1434   CpvInitialize(int      , CthResumeNormalThreadIdx);
1435   CpvInitialize(int      , CthResumeSchedulingThreadIdx);
1436
1437   CpvAccess(CthMainThread) = CthSelf();
1438   CpvAccess(CthSchedulingThread) = CthSelf();
1439   CpvAccess(CthSleepingStandins) = 0;
1440   CpvAccess(CthResumeNormalThreadIdx) =
1441     CmiRegisterHandler((CmiHandler)CthResumeNormalThread);
1442   CpvAccess(CthResumeSchedulingThreadIdx) =
1443     CmiRegisterHandler((CmiHandler)CthResumeSchedulingThread);
1444   CthSetStrategy(CthSelf(),
1445                  CthEnqueueSchedulingThread,
1446                  CthSuspendSchedulingThread);
1447 }
1448
1449 void CsdInit(argv)
1450   char **argv;
1451 {
1452   CpvInitialize(void *, CsdSchedQueue);
1453   CpvInitialize(int,   CsdStopFlag);
1454   CpvInitialize(int,   CsdLocalCounter);
1455   if(!CmiGetArgIntDesc(argv,"+csdLocalMax",&CsdLocalMax,"Set the max number of local messages to process before forcing a check for remote messages."))
1456     {
1457       CsdLocalMax= CSD_LOCAL_MAX_DEFAULT;
1458     }
1459   CpvAccess(CsdLocalCounter) = CsdLocalMax;
1460   CpvAccess(CsdSchedQueue) = (void *)CqsCreate();
1461
1462 #if CMK_OBJECT_QUEUE_AVAILABLE
1463   CpvInitialize(void *,CsdObjQueue);
1464   CpvAccess(CsdObjQueue) = CdsFifo_Create();
1465 #endif
1466
1467 #if CMK_NODE_QUEUE_AVAILABLE
1468   CsvInitialize(CmiLock, CsdNodeQueueLock);
1469   CsvInitialize(void *, CsdNodeQueue);
1470   if (CmiMyRank() ==0) {
1471         CsvAccess(CsdNodeQueueLock) = CmiCreateLock();
1472         CsvAccess(CsdNodeQueue) = (void *)CqsCreate();
1473   }
1474   CmiNodeAllBarrier();
1475 #endif
1476
1477   CpvAccess(CsdStopFlag)  = 0;
1478 }
1479
1480
1481 /*****************************************************************************
1482  *
1483  * Vector Send
1484  *
1485  ****************************************************************************/
1486
1487 #if CMK_VECTOR_SEND_USES_COMMON_CODE
1488
1489 void CmiSyncVectorSend(destPE, n, sizes, msgs)
1490 int destPE, n;
1491 int *sizes;
1492 char **msgs;
1493 {
1494   int i, total;
1495   char *mesg, *tmp;
1496   
1497   for(i=0,total=0;i<n;i++) total += sizes[i];
1498   mesg = (char *) CmiAlloc(total);
1499   for(i=0,tmp=mesg;i<n;i++) {
1500     memcpy(tmp, msgs[i],sizes[i]);
1501     tmp += sizes[i];
1502   }
1503   CmiSyncSendAndFree(destPE, total, mesg);
1504 }
1505
1506 CmiCommHandle CmiAsyncVectorSend(destPE, n, sizes, msgs)
1507 int destPE, n;
1508 int *sizes;
1509 char **msgs;
1510 {
1511   CmiSyncVectorSend(destPE,n,sizes,msgs);
1512   return NULL;
1513 }
1514
1515 void CmiSyncVectorSendAndFree(destPE, n, sizes, msgs)
1516 int destPE, n;
1517 int *sizes;
1518 char **msgs;
1519 {
1520   int i;
1521
1522   CmiSyncVectorSend(destPE,n,sizes,msgs);
1523   for(i=0;i<n;i++) CmiFree(msgs[i]);
1524   CmiFree(sizes);
1525   CmiFree(msgs);
1526 }
1527
1528 #endif
1529
1530 /*****************************************************************************
1531  *
1532  * Multicast groups
1533  *
1534  ****************************************************************************/
1535
1536 #if CMK_MULTICAST_DEF_USE_COMMON_CODE
1537
1538 typedef struct GroupDef
1539 {
1540   union {
1541     char core[CmiMsgHeaderSizeBytes];
1542     struct GroupDef *next;
1543   } core;
1544   CmiGroup group;
1545   int npes;
1546   int pes[1];
1547 }
1548 *GroupDef;
1549
1550 #define GROUPTAB_SIZE 101
1551
1552 CpvStaticDeclare(int, CmiGroupHandlerIndex);
1553 CpvStaticDeclare(int, CmiGroupCounter);
1554 CpvStaticDeclare(GroupDef *, CmiGroupTable);
1555
1556 void CmiGroupHandler(GroupDef def)
1557 {
1558   /* receive group definition, insert into group table */
1559   GroupDef *table = CpvAccess(CmiGroupTable);
1560   unsigned int hashval, bucket;
1561   hashval = (def->group.id ^ def->group.pe);
1562   bucket = hashval % GROUPTAB_SIZE;
1563   def->core.next = table[bucket];
1564   table[bucket] = def;
1565 }
1566
1567 CmiGroup CmiEstablishGroup(int npes, int *pes)
1568 {
1569   /* build new group definition, broadcast it */
1570   CmiGroup grp; GroupDef def; int len, i;
1571   grp.id = CpvAccess(CmiGroupCounter)++;
1572   grp.pe = CmiMyPe();
1573   len = sizeof(struct GroupDef)+(npes*sizeof(int));
1574   def = (GroupDef)CmiAlloc(len);
1575   def->group = grp;
1576   def->npes = npes;
1577   for (i=0; i<npes; i++)
1578     def->pes[i] = pes[i];
1579   CmiSetHandler(def, CpvAccess(CmiGroupHandlerIndex));
1580   CmiSyncBroadcastAllAndFree(len, def);
1581   return grp;
1582 }
1583
1584 void CmiLookupGroup(CmiGroup grp, int *npes, int **pes)
1585 {
1586   unsigned int hashval, bucket;  GroupDef def;
1587   GroupDef *table = CpvAccess(CmiGroupTable);
1588   hashval = (grp.id ^ grp.pe);
1589   bucket = hashval % GROUPTAB_SIZE;
1590   for (def=table[bucket]; def; def=def->core.next) {
1591     if ((def->group.id == grp.id)&&(def->group.pe == grp.pe)) {
1592       *npes = def->npes;
1593       *pes = def->pes;
1594       return;
1595     }
1596   }
1597   *npes = 0; *pes = 0;
1598 }
1599
1600 void CmiGroupInit()
1601 {
1602   CpvInitialize(int, CmiGroupHandlerIndex);
1603   CpvInitialize(int, CmiGroupCounter);
1604   CpvInitialize(GroupDef *, CmiGroupTable);
1605   CpvAccess(CmiGroupHandlerIndex) = CmiRegisterHandler((CmiHandler)CmiGroupHandler);
1606   CpvAccess(CmiGroupCounter) = 0;
1607   CpvAccess(CmiGroupTable) =
1608     (GroupDef*)calloc(GROUPTAB_SIZE, sizeof(GroupDef));
1609   if (CpvAccess(CmiGroupTable) == 0)
1610     CmiAbort("Memory Allocation Error");
1611 }
1612
1613 #endif
1614
1615 /*****************************************************************************
1616  *
1617  * Common List-Cast and Multicast Code
1618  *
1619  ****************************************************************************/
1620
1621 #if CMK_MULTICAST_LIST_USE_COMMON_CODE
1622
1623 void CmiSyncListSendFn(int npes, int *pes, int len, char *msg)
1624 {
1625   int i;
1626   for(i=0;i<npes;i++) {
1627     CmiSyncSend(pes[i], len, msg);
1628   }
1629 }
1630
1631 CmiCommHandle CmiAsyncListSendFn(int npes, int *pes, int len, char *msg)
1632 {
1633   /* A better asynchronous implementation may be wanted, but at least it works */
1634   CmiSyncListSendFn(npes, pes, len, msg);
1635   return (CmiCommHandle) 0;
1636 }
1637
1638 void CmiFreeListSendFn(int npes, int *pes, int len, char *msg)
1639 {
1640   int i;
1641   for(i=0;i<npes-1;i++) {
1642     CmiSyncSend(pes[i], len, msg);
1643   }
1644   if (npes)
1645     CmiSyncSendAndFree(pes[npes-1], len, msg);
1646   else 
1647     CmiFree(msg);
1648 }
1649
1650 #endif
1651
1652 #if CMK_MULTICAST_GROUP_USE_COMMON_CODE
1653
1654 typedef struct MultiMsg
1655 {
1656   char core[CmiMsgHeaderSizeBytes];
1657   CmiGroup group;
1658   int pos;
1659   int origlen;
1660 }
1661 *MultiMsg;
1662
1663 CpvDeclare(int, CmiMulticastHandlerIndex);
1664
1665 void CmiMulticastDeliver(MultiMsg msg)
1666 {
1667   int npes, *pes; int olen, nlen, pos, child1, child2;
1668   olen = msg->origlen;
1669   nlen = olen + sizeof(struct MultiMsg);
1670   CmiLookupGroup(msg->group, &npes, &pes);
1671   if (pes==0) {
1672     CmiSyncSendAndFree(CmiMyPe(), nlen, msg);
1673     return;
1674   }
1675   if (npes==0) {
1676     CmiFree(msg);
1677     return;
1678   }
1679   if (msg->pos == -1) {
1680     msg->pos=0;
1681     CmiSyncSendAndFree(pes[0], nlen, msg);
1682     return;
1683   }
1684   pos = msg->pos;
1685   child1 = ((pos+1)<<1);
1686   child2 = child1-1;
1687   if (child1 < npes) {
1688     msg->pos = child1;
1689     CmiSyncSend(pes[child1], nlen, msg);
1690   }
1691   if (child2 < npes) {
1692     msg->pos = child2;
1693     CmiSyncSend(pes[child2], nlen, msg);
1694   }
1695   if(olen < sizeof(struct MultiMsg)) {
1696     memcpy(msg, msg+1, olen);
1697   } else {
1698     memcpy(msg, (((char*)msg)+olen), sizeof(struct MultiMsg));
1699   }
1700   CmiSyncSendAndFree(CmiMyPe(), olen, msg);
1701 }
1702
1703 void CmiMulticastHandler(MultiMsg msg)
1704 {
1705   CmiMulticastDeliver(msg);
1706 }
1707
1708 void CmiSyncMulticastFn(CmiGroup grp, int len, char *msg)
1709 {
1710   int newlen; MultiMsg newmsg;
1711   newlen = len + sizeof(struct MultiMsg);
1712   newmsg = (MultiMsg)CmiAlloc(newlen);
1713   if(len < sizeof(struct MultiMsg)) {
1714     memcpy(newmsg+1, msg, len);
1715   } else {
1716     memcpy(newmsg+1, msg+sizeof(struct MultiMsg), len-sizeof(struct MultiMsg));
1717     memcpy(((char *)newmsg+len), msg, sizeof(struct MultiMsg));
1718   }
1719   newmsg->group = grp;
1720   newmsg->origlen = len;
1721   newmsg->pos = -1;
1722   CmiSetHandler(newmsg, CpvAccess(CmiMulticastHandlerIndex));
1723   CmiMulticastDeliver(newmsg);
1724 }
1725
1726 void CmiFreeMulticastFn(CmiGroup grp, int len, char *msg)
1727 {
1728   CmiSyncMulticastFn(grp, len, msg);
1729   CmiFree(msg);
1730 }
1731
1732 CmiCommHandle CmiAsyncMulticastFn(CmiGroup grp, int len, char *msg)
1733 {
1734   CmiError("Async Multicast not implemented.");
1735   return (CmiCommHandle) 0;
1736 }
1737
1738 void CmiMulticastInit()
1739 {
1740   CpvInitialize(int, CmiMulticastHandlerIndex);
1741   CpvAccess(CmiMulticastHandlerIndex) =
1742     CmiRegisterHandler((CmiHandler)CmiMulticastHandler);
1743 }
1744
1745 #endif
1746
1747 /***************************************************************************
1748  *
1749  * Memory Allocation routines 
1750  *
1751  * A block of memory can consist of multiple chunks.  Each chunk has
1752  * a sizefield and a refcount.  The first chunk's refcount is a reference
1753  * count.  That's how many CmiFrees it takes to free the message.
1754  * Subsequent chunks have a refcount which is less than zero.  This is
1755  * the offset back to the start of the first chunk.
1756  *
1757  * Each chunk has a CmiChunkHeader before the user data, with the fields:
1758  *
1759  *  size: The user-allocated size of the chunk, in bytes.
1760  *
1761  *  ref: A magic reference count object. Ordinary blocks start with
1762  *     reference count 1.  When the reference count reaches zero,
1763  *     the block is deleted.  To support nested buffers, the 
1764  *     reference count can also be negative, which means it is 
1765  *     a byte offset to the enclosing buffer's reference count.
1766  *
1767  ***************************************************************************/
1768
1769
1770 /* Given a user chunk m, extract the enclosing chunk header fields: */
1771 #define SIZEFIELD(m) (((CmiChunkHeader *)(m))[-1].size)
1772 #define REFFIELD(m) (((CmiChunkHeader *)(m))[-1].ref)
1773 #define BLKSTART(m) (((CmiChunkHeader *)(m))-1)
1774
1775 void *CmiAlloc(int size)
1776 {
1777   char *res;
1778
1779 #if CONVERSE_VERSION_ELAN
1780   res = (char *) elan_CmiAlloc(size+sizeof(CmiChunkHeader));
1781 #elif CONVERSE_VERSION_VMI
1782   res = (char *) CMI_VMI_CmiAlloc(size+sizeof(CmiChunkHeader));
1783 #elif CONVERSE_POOL
1784   res =(char *) CmiPoolAlloc(size+sizeof(CmiChunkHeader));
1785 #else
1786   res =(char *) malloc_nomigrate(size+sizeof(CmiChunkHeader));
1787 #endif
1788
1789   _MEMCHECK(res);
1790
1791 #ifdef MEMMONITOR
1792   CpvAccess(MemoryUsage) += size+sizeof(CmiChunkHeader);
1793   CpvAccess(AllocCount)++;
1794   CpvAccess(BlocksAllocated)++;
1795   if (CpvAccess(MemoryUsage) > CpvAccess(HiWaterMark)) {
1796     CpvAccess(HiWaterMark) = CpvAccess(MemoryUsage);
1797   }
1798   if (CpvAccess(MemoryUsage) > 1.1 * CpvAccess(ReportedHiWaterMark)) {
1799     CmiPrintf("HIMEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
1800             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
1801             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
1802     CpvAccess(ReportedHiWaterMark) = CpvAccess(MemoryUsage);
1803   }
1804   if ((CpvAccess(AllocCount) % 1000) == 0) {
1805     CmiPrintf("MEM STAT PE%d: %d Allocs, %d blocks, %lu K, Max %lu K\n",
1806             CmiMyPe(), CpvAccess(AllocCount), CpvAccess(BlocksAllocated),
1807             CpvAccess(MemoryUsage)/1024, CpvAccess(HiWaterMark)/1024);
1808   }
1809 #endif
1810
1811   res+=sizeof(CmiChunkHeader);
1812   SIZEFIELD(res)=size;
1813   REFFIELD(res)=1;
1814   return (void *)res;
1815 }
1816
1817 /** Follow the header links out to the most enclosing block */
1818 static void *CmiAllocFindEnclosing(void *blk) {
1819   int refCount = REFFIELD(blk);
1820   while (refCount < 0) {
1821     blk = (void *)((char*)blk+refCount); /* Jump to enclosing block */
1822     refCount = REFFIELD(blk);
1823   }
1824   return blk;
1825 }
1826
1827 /** Increment the reference count for this block's owner.
1828     This call must be matched by an equivalent CmiFree. */
1829 void CmiReference(void *blk)
1830 {
1831   REFFIELD(CmiAllocFindEnclosing(blk))++;
1832 }
1833
1834 /** Return the size of the user portion of this block. */
1835 int CmiSize(void *blk)
1836 {
1837   return SIZEFIELD(blk);
1838 }
1839
1840 /** Decrement the reference count for this block. */
1841 void CmiFree(void *blk)
1842 {
1843   void *parentBlk=CmiAllocFindEnclosing(blk);
1844   int refCount=REFFIELD(parentBlk);
1845 #ifndef CMK_OPTIMIZE
1846   if(refCount==0) /* Logic error: reference count shouldn't already have been zero */
1847     CmiAbort("CmiFree reference count was zero-- is this a duplicate free?");
1848 #endif
1849   refCount--;
1850   REFFIELD(parentBlk) = refCount;
1851   if(refCount==0) { /* This was the last reference to the block-- free it */
1852 #ifdef MEMMONITOR
1853     int size=SIZEFIELD(parentBlk);
1854     if (size > 1000000000) /* Absurdly large size field-- warning */
1855       CmiPrintf("MEMSTAT Uh-oh -- SIZEFIELD=%d\n",size);
1856     CpvAccess(MemoryUsage) -= (size + sizeof(CmiChunkHeader);
1857     CpvAccess(BlocksAllocated)--;
1858 #endif
1859
1860 #if CONVERSE_VERSION_ELAN
1861     elan_CmiFree(BLKSTART(parentBlk));
1862 #elif CONVERSE_VERSION_VMI
1863     CMI_VMI_CmiFree(BLKSTART(parentBlk));
1864 #elif CONVERSE_POOL
1865     CmiPoolFree(BLKSTART(parentBlk));
1866 #else
1867     free_nomigrate(BLKSTART(parentBlk));
1868 #endif
1869   }
1870 }
1871
1872
1873 /***************************************************************************
1874  *
1875  * Temporary-memory Allocation routines 
1876  *
1877  *  This buffer augments the storage available on the regular machine stack
1878  * for fairly large temporary buffers, which allows us to use smaller machine
1879  * stacks.
1880  *
1881  ***************************************************************************/
1882
1883 #define CMI_TMP_BUF_MAX 128*1024 /* Allow this much temporary storage. */
1884
1885 typedef struct {
1886   char *buf; /* Start of temporary buffer */
1887   int cur; /* First unused location in temporary buffer */
1888   int max; /* Length of temporary buffer */
1889 } CmiTmpBuf_t;
1890 CpvDeclare(CmiTmpBuf_t,CmiTmpBuf); /* One temporary buffer per PE */
1891
1892 static void CmiTmpSetup(CmiTmpBuf_t *b) {
1893   b->buf=malloc(CMI_TMP_BUF_MAX);
1894   b->cur=0;
1895   b->max=CMI_TMP_BUF_MAX;
1896 }
1897
1898 void *CmiTmpAlloc(int size) {
1899   if (!CpvInitialized(CmiTmpBuf)) {
1900     return malloc(size);
1901   }
1902   else { /* regular case */
1903     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
1904     void *t;
1905     if (b->cur+size>b->max) {
1906       if (b->max==0) /* We're just uninitialized */
1907         CmiTmpSetup(b);
1908       else /* We're really out of space! */
1909         CmiAbort("CmiTmpAlloc: asked for too much temporary buffer space");
1910     }
1911     t=b->buf+b->cur;
1912     b->cur+=size;
1913     return t;
1914   }
1915 }
1916 void CmiTmpFree(void *t) {
1917   if (!CpvInitialized(CmiTmpBuf)) {
1918     free(t);
1919   }
1920   else { /* regular case */
1921     CmiTmpBuf_t *b=&CpvAccess(CmiTmpBuf);
1922     /* t should point into our temporary buffer: figure out where */
1923     int cur=((const char *)t)-b->buf;
1924 #ifndef CMK_OPTIMIZE
1925     if (cur<0 || cur>b->max)
1926       CmiAbort("CmiTmpFree: called with an invalid pointer");
1927 #endif
1928     b->cur=cur;
1929   }
1930 }
1931
1932 void CmiTmpInit(char **argv) {
1933   CpvInitialize(CmiTmpBuf_t,CmiTmpBuf);
1934   /* Set up this processor's temporary buffer */
1935   CmiTmpSetup(&CpvAccess(CmiTmpBuf));
1936 }
1937
1938 /******************************************************************************
1939
1940   Cross-platform directory creation
1941
1942   ****************************************************************************/
1943 #ifdef _MSC_VER
1944 /* Windows directory creation: */
1945 #include <windows.h>
1946
1947 void CmiMkdir(const char *dirName) {
1948         CreateDirectory(dirName,NULL);
1949 }
1950
1951 #else /* !_MSC_VER */
1952 /* UNIX directory creation */
1953 #include <unistd.h> 
1954 #include <sys/stat.h> /* from "mkdir" man page */
1955 #include <sys/types.h>
1956
1957 void CmiMkdir(const char *dirName) {
1958         mkdir(dirName,0777);
1959 }
1960
1961 #endif
1962
1963
1964 /******************************************************************************
1965
1966   Multiple Send function                               
1967
1968   ****************************************************************************/
1969
1970 CpvDeclare(int, CmiMainHandlerIDP); /* Main handler that is run on every node */
1971
1972 /****************************************************************************
1973 * DESCRIPTION : This function call allows the user to send multiple messages
1974 *               from one processor to another, all intended for differnet 
1975 *               handlers.
1976 *
1977 *               Parameters :
1978 *
1979 *               destPE, len, int sizes[0..len-1], char *messages[0..len-1]
1980 *
1981 ****************************************************************************/
1982 /* Round up message size to the message granularity. 
1983    Does this by adding, then truncating.
1984 */
1985 static int roundUpSize(unsigned int s) {
1986   return (int)((s+sizeof(double)-1)&~(sizeof(double)-1));
1987 }
1988 /* Return the amount of message padding required for a message
1989    with this many user bytes. 
1990  */
1991 static int paddingSize(unsigned int s) {
1992   return roundUpSize(s)-s;
1993 }
1994
1995 /* Message header for a bundle of multiple-sent messages */
1996 typedef struct {
1997   char convHeader[CmiMsgHeaderSizeBytes];
1998   int nMessages; /* Number of distinct messages bundled below. */
1999   double pad; /* To align the first message, which follows this header */
2000 } CmiMultipleSendHeader;
2001
2002 void _CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[], int immed)
2003 {
2004   CmiMultipleSendHeader header;
2005   int m; /* Outgoing message */
2006   CmiChunkHeader *msgHdr; /* Chunk headers for each message */
2007   double pad = 0; /* padding required */
2008   int vecLen; /* Number of pieces in outgoing message vector */
2009   int *vecSizes; /* Sizes of each piece we're sending out. */
2010   char **vecPtrs; /* Pointers to each piece we're sending out. */
2011   int vec; /* Entry we're currently filling out in above array */
2012
2013   msgHdr = (CmiChunkHeader *)CmiTmpAlloc(len * sizeof(CmiChunkHeader));
2014   /* Allocate memory for the outgoing vector*/
2015   vecLen=1+3*len; /* Header and 3 parts per message */
2016   vecSizes = (int *)CmiTmpAlloc(vecLen * sizeof(int));
2017   vecPtrs = (char **)CmiTmpAlloc(vecLen * sizeof(char *));
2018   vec=0;
2019   
2020   /* Build the header */
2021   header.nMessages=len;
2022   CmiSetHandler(&header, CpvAccess(CmiMainHandlerIDP));
2023 #if CMK_IMMEDIATE_MSG
2024   if (immed) CmiBecomeImmediate(&header);
2025 #endif
2026   vecSizes[vec]=sizeof(header); vecPtrs[vec]=(char *)&header;
2027   vec++;
2028
2029   /* Build an entry for each message: 
2030          | CmiChunkHeader | Message data | Message padding | ...next message entry ...
2031   */
2032   for (m=0;m<len;m++) {
2033     msgHdr[m].size=roundUpSize(sizes[m]); /* Size of message and padding */
2034     msgHdr[m].ref=0; /* Reference count will be filled out on receive side */
2035     
2036     /* First send the message's CmiChunkHeader (for use on receive side) */
2037     vecSizes[vec]=sizeof(CmiChunkHeader); vecPtrs[vec]=(char *)&msgHdr[m];
2038     vec++;
2039     
2040     /* Now send the actual message data */
2041     vecSizes[vec]=sizes[m]; vecPtrs[vec]=msgComps[m];
2042     vec++;
2043     
2044     /* Now send padding to align the next message on a double-boundary */
2045     vecSizes[vec]=paddingSize(sizes[m]); vecPtrs[vec]=(char *)&pad;
2046     vec++;
2047   }
2048   CmiAssert(vec==vecLen);
2049   
2050   CmiSyncVectorSend(destPE, vecLen, vecSizes, vecPtrs);
2051   
2052   CmiTmpFree(vecPtrs); /* CmiTmp: Be sure to throw away in opposite order of allocation */
2053   CmiTmpFree(vecSizes);
2054   CmiTmpFree(msgHdr);
2055 }
2056
2057 void CmiMultipleSend(unsigned int destPE, int len, int sizes[], char *msgComps[])
2058 {
2059   _CmiMultipleSend(destPE, len, sizes, msgComps, 0);
2060 }
2061
2062 void CmiMultipleIsend(unsigned int destPE, int len, int sizes[], char *msgComps[])
2063 {
2064   _CmiMultipleSend(destPE, len, sizes, msgComps, 1);
2065 }
2066
2067 /****************************************************************************
2068 * DESCRIPTION : This function initializes the main handler required for the
2069 *               CmiMultipleSend() function to work. 
2070 *               
2071 *               This function should be called once in any Converse program
2072 *               that uses CmiMultipleSend()
2073 *
2074 ****************************************************************************/
2075
2076 static void CmiMultiMsgHandler(char *msgWhole);
2077
2078 void CmiInitMultipleSend(void)
2079 {
2080   CpvInitialize(int,CmiMainHandlerIDP); 
2081   CpvAccess(CmiMainHandlerIDP) =
2082     CmiRegisterHandler((CmiHandler)CmiMultiMsgHandler);
2083 }
2084
2085 /****************************************************************************
2086 * DESCRIPTION : This function is the main handler that splits up the messages
2087 *               CmiMultipleSend() pastes together. 
2088 *
2089 ****************************************************************************/
2090
2091 static void CmiMultiMsgHandler(char *msgWhole)
2092 {
2093   int len=((CmiMultipleSendHeader *)msgWhole)->nMessages;
2094   int offset=sizeof(CmiMultipleSendHeader);
2095   int m;
2096   for (m=0;m<len;m++) {
2097     CmiChunkHeader *ch=(CmiChunkHeader *)(msgWhole+offset);
2098     char *msg=(msgWhole+offset+sizeof(CmiChunkHeader));
2099     int msgSize=ch->size; /* Size of user portion of message (plus padding at end) */
2100     /* Link new message to owner via a negative ref pointer */
2101     ch->ref=msgWhole-msg; 
2102     CmiReference(msg); /* Follows link & increases reference count of *msgWhole* */
2103     CmiSyncSendAndFree(CmiMyPe(), msgSize, msg);
2104     offset+= sizeof(CmiChunkHeader) + msgSize;
2105   }
2106   /* Release our reference to the whole message.  The message will
2107      only actually be deleted once all its sub-messages are free'd as well. */
2108   CmiFree(msgWhole);
2109 }
2110
2111 /****************************************************************************
2112 * Hypercube broadcast message passing.
2113 ****************************************************************************/
2114
2115 int HypercubeGetBcastDestinations(int mype, int total_pes, int k, int *dest_pes) {
2116   int num_pes = 0;
2117   for ( ; k>=0; --k) {
2118     /* add the processor destination at level k if it exist */
2119     dest_pes[num_pes] = mype ^ (1<<k);
2120     if (dest_pes[num_pes] >= total_pes) {
2121       /* find the first proc in the other part of the current dimention */
2122       dest_pes[num_pes] &= (-1)<<k;
2123       /* if the first proc there is over CmiNumPes() then there is no other
2124          dimension, otherwise if it is valid compute my correspondent in such
2125          a way to minimize the load for every processor */
2126       if (total_pes>dest_pes[num_pes]) dest_pes[num_pes] += (mype - (mype & ((-1)<<k))) % (total_pes - dest_pes[num_pes]);
2127       }
2128     if (dest_pes[num_pes] < total_pes) {
2129       /* if the destination is in the acceptable range increment num_pes */
2130       ++num_pes;
2131     }
2132   }
2133   return num_pes;
2134 }
2135
2136
2137 /****************************************************************************
2138 * DESCRIPTION : This function initializes the main handler required for the
2139 *               Immediate message
2140 *               
2141 *               This function should be called once in any Converse program
2142 *
2143 ****************************************************************************/
2144
2145 int _immediateLock = 0; /* if locked, all immediate message handling will be delayed. */
2146 int _immediateFlag = 0; /* if set, there is delayed immediate message. */
2147
2148 CpvDeclare(int, CmiImmediateMsgHandlerIdx); /* Main handler that is run on every node */
2149
2150 /* xdl is the real handler */
2151 static void CmiImmediateMsgHandler(char *msg)
2152 {
2153   CmiSetHandler(msg, CmiGetXHandler(msg));
2154   CmiHandleMessage(msg);
2155 }
2156
2157 void CmiInitImmediateMsg(void)
2158 {
2159   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
2160   CpvAccess(CmiImmediateMsgHandlerIdx) =
2161     CmiRegisterHandler((CmiHandler)CmiImmediateMsgHandler);
2162 }
2163
2164 #if !CMK_IMMEDIATE_MSG
2165 #if !CMK_MACHINE_PROGRESS_DEFINED
2166 void CmiProbeImmediateMsg()
2167 {
2168 }
2169 #endif
2170 #endif 
2171
2172 /******** Idle timeout module (+idletimeout=30) *********/
2173
2174 typedef struct {
2175   int idle_timeout;/*Milliseconds to wait idle before aborting*/
2176   int is_idle;/*Boolean currently-idle flag*/
2177   int call_count;/*Number of timeout calls currently in flight*/
2178 } cmi_cpu_idlerec;
2179
2180 static void on_timeout(cmi_cpu_idlerec *rec,double curWallTime)
2181 {
2182   rec->call_count--;
2183   if(rec->call_count==0 && rec->is_idle==1) {
2184     CmiError("Idle time on PE %d exceeded specified timeout.\n", CmiMyPe());
2185     CmiAbort("Exiting.\n");
2186   }
2187 }
2188 static void on_idle(cmi_cpu_idlerec *rec,double curWallTime)
2189 {
2190   CcdCallFnAfter((CcdVoidFn)on_timeout, rec, rec->idle_timeout);
2191   rec->call_count++; /*Keeps track of overlapping timeout calls.*/  
2192   rec->is_idle = 1;
2193 }
2194 static void on_busy(cmi_cpu_idlerec *rec,double curWallTime)
2195 {
2196   rec->is_idle = 0;
2197 }
2198 static void CIdleTimeoutInit(char **argv)
2199 {
2200   int idle_timeout=0; /*Seconds to wait*/
2201   CmiGetArgIntDesc(argv,"+idle-timeout",&idle_timeout,"Abort if idle for this many seconds");
2202   if(idle_timeout != 0) {
2203     cmi_cpu_idlerec *rec=(cmi_cpu_idlerec *)malloc(sizeof(cmi_cpu_idlerec));
2204     _MEMCHECK(rec);
2205     rec->idle_timeout=idle_timeout*1000;
2206     rec->is_idle=0;
2207     rec->call_count=0;
2208     CcdCallOnCondition(CcdPROCESSOR_BEGIN_IDLE, (CcdVoidFn)on_idle, rec);
2209     CcdCallOnCondition(CcdPROCESSOR_BEGIN_BUSY, (CcdVoidFn)on_busy, rec);
2210   }
2211 }
2212
2213 /*****************************************************************************
2214  *
2215  * Converse Initialization
2216  *
2217  *****************************************************************************/
2218
2219 extern void CrnInit(void);
2220 extern void CmiIsomallocInit(char **argv);
2221
2222 static void CmiProcessPriority(char **argv)
2223 {
2224   int dummy, nicelevel=-100;      /* process priority */
2225   CmiGetArgIntDesc(argv,"+nice",&nicelevel,"Set the process priority level");
2226   /* ignore others */
2227   while (CmiGetArgIntDesc(argv,"+nice",&dummy,"Set the process priority level"));
2228   /* call setpriority once on each process to set process's priority */
2229   if (CmiMyRank() == 0 && nicelevel != -100)  {
2230 #ifndef _WIN32
2231     if (0!=setpriority(PRIO_PROCESS, 0, nicelevel))  {
2232       CmiPrintf("[%d] setpriority failed with value %d. \n", CmiMyPe(), nicelevel);
2233       perror("setpriority");
2234       CmiAbort("setpriority failed.");
2235     }
2236     else
2237       CmiPrintf("[%d] Charm++: setpriority %d\n", CmiMyPe(), nicelevel);
2238 #else
2239     HANDLE hProcess = GetCurrentProcess();
2240     DWORD dwPriorityClass = NORMAL_PRIORITY_CLASS;
2241     char *prio_str = "NORMAL_PRIORITY_CLASS";
2242     BOOL status;
2243     /*
2244        <-20:      real time
2245        -20--10:   high 
2246        -10-0:     above normal
2247        0:         normal
2248        0-10:      below normal
2249        10-:       idle
2250     */
2251     if (0) ;
2252 #ifdef BELOW_NORMAL_PRIORITY_CLASS
2253     else if (nicelevel<10 && nicelevel>0) {
2254       dwPriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
2255       prio_str = "BELOW_NORMAL_PRIORITY_CLASS";
2256     }
2257 #endif
2258     else if (nicelevel>0) {
2259       dwPriorityClass = IDLE_PRIORITY_CLASS;
2260       prio_str = "IDLE_PRIORITY_CLASS";
2261     }
2262     else if (nicelevel<=-20) {
2263       dwPriorityClass = REALTIME_PRIORITY_CLASS;
2264       prio_str = "REALTIME_PRIORITY_CLASS";
2265     }
2266 #ifdef ABOVE_NORMAL_PRIORITY_CLASS
2267     else if (nicelevel>-10 && nicelevel<0) {
2268       dwPriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
2269       prio_str = "ABOVE_NORMAL_PRIORITY_CLASS";
2270     }
2271 #endif
2272     else if (nicelevel<0) {
2273       dwPriorityClass = HIGH_PRIORITY_CLASS;
2274       prio_str = "HIGH_PRIORITY_CLASS";
2275     }
2276     status = SetPriorityClass(hProcess, dwPriorityClass);
2277     if (!status)  {
2278         int err=GetLastError();
2279         CmiPrintf("SetPriorityClass failed errno=%d, WSAerr=%d\n",errno, err);
2280         CmiAbort("SetPriorityClass failed.");
2281     }
2282     else
2283       CmiPrintf("[%d] Charm++: setpriority %s\n", CmiMyPe(), prio_str);
2284 #endif
2285   }
2286 }
2287
2288 void CommunicationServerInit()
2289 {
2290 #if CMK_IMMEDIATE_MSG
2291   CQdCpvInit();
2292   CpvInitialize(int,CmiImmediateMsgHandlerIdx); 
2293 #endif
2294 }
2295
2296 /**
2297   Main Converse initialization routine.  This routine is 
2298   called by the machine file (machine.c) to set up Converse.
2299   It's "Common" because it's shared by all the machine.c files. 
2300   
2301   The main task of this routine is to set up all the Cpv's
2302   (message queues, handler tables, etc.) used during main execution.
2303   
2304   On SMP versions, this initialization routine is called by 
2305   *all* processors of a node simultaniously.  It's *also* called
2306   by the communication thread, which is rather strange but needed
2307   for immediate messages.  Each call to this routine expects a 
2308   different copy of the argv arguments, so use CmiCopyArgs(argv).
2309   
2310   Requires:
2311     - A working network layer.
2312     - Working Cpv's and CmiNodeBarrier.
2313     - CthInit to already have been called.  CthInit is called
2314       from the machine layer directly, because some machine layers
2315       (like uth) use Converse threads internally.
2316
2317   Initialization is somewhat subtle, in that various modules
2318   won't work properly until they're initialized.  For example,
2319   nobody can register handlers before calling CmiHandlerInit.
2320 */
2321 void ConverseCommonInit(char **argv)
2322 {
2323   CmiArgInit(argv);
2324   CmiMemoryInit(argv);
2325 #if CONVERSE_POOL
2326   CmiPoolAllocInit(30);  
2327 #endif
2328   CmiTmpInit(argv);
2329   CmiTimerInit();
2330   CstatsInit(argv);
2331
2332   CcdModuleInit(argv);
2333   CmiHandlerInit();
2334   CIdleTimeoutInit(argv);
2335   
2336 #ifndef CMK_OPTIMIZE
2337   traceInit(argv);
2338 /*initTraceCore(argv);*/ /* projector */
2339 #endif
2340   CmiProcessPriority(argv);
2341
2342 #if CMK_CCS_AVAILABLE
2343   CcsInit(argv);
2344 #endif
2345   CmiPersistentInit();
2346   CmiIsomallocInit(argv);
2347   CpdInit();
2348   CmiDeliversInit();
2349   CsdInit(argv);
2350   CthSchedInit();
2351   CmiGroupInit();
2352   CmiMulticastInit();
2353   CmiInitMultipleSend();
2354   CQdInit();
2355
2356   CrnInit();
2357   CmiInitImmediateMsg();
2358   CldModuleInit(argv);
2359   
2360   /* main thread is suspendable */
2361 /*
2362   CthSetSuspendable(CthSelf(), 0);
2363 */
2364 }
2365
2366 void ConverseCommonExit(void)
2367 {
2368   CcsImpl_kill();
2369
2370 #ifndef CMK_OPTIMIZE
2371   traceClose();
2372 /*closeTraceCore();*/ /* projector */
2373 #endif
2374
2375 }
2376
2377 #if ! CMK_CMIPRINTF_IS_A_BUILTIN
2378
2379 void CmiPrintf(const char *format, ...)
2380 {
2381   va_list args;
2382   va_start(args,format);
2383   vprintf(format, args);
2384   fflush(stdout);
2385   va_end(args);
2386 }
2387
2388 void CmiError(const char *format, ...)
2389 {
2390   va_list args;
2391   va_start(args,format);
2392   vfprintf(stderr,format, args);
2393   fflush(stderr);
2394   va_end(args);
2395 }
2396
2397 #endif
2398
2399 void __cmi_assert(const char *expr, const char *file, int line)
2400 {
2401   CmiError("[%d] Assertion \"%s\" failed in file %s line %d.\n",
2402       CmiMyPe(), expr, file, line);
2403   CmiAbort("");
2404 }
2405
2406 char *CmiCopyMsg(char *msg, int len)
2407 {
2408   char *copy = (char *)CmiAlloc(len);
2409   _MEMCHECK(copy);
2410   memcpy(copy, msg, len);
2411   return copy;
2412 }
2413
2414 unsigned char computeCheckSum(unsigned char *data, int len)
2415 {
2416   int i;
2417   unsigned char ret = 0;
2418   for (i=0; i<len; i++) ret ^= (unsigned char)data[i];
2419   return ret;
2420 }
2421
2422 /*@}*/