gpu: Actually fix PE to GPU mapping
[charm.git] / src / ck-core / init.C
1 /**
2 \addtogroup CkInit
3 \brief Controls the Charm++ startup process.
4
5 This file runs the entire Charm++ startup process.
6
7 The process begins with every processor finishing the 
8 Converse startup process and calling _initCharm.
9 This routine runs almost the entire Charm++ setup process.
10 It begins by setting up various Cpvs and subsystems.
11
12 The rank 0 processor of each node then does
13 the Charm++ registration, by calling the various _register
14 routines.  
15
16 Now processor 0:
17 <ol>
18 <li>Creates each mainchare, by allocating the chares
19  and calling their constructors with argc/argv.
20  This typically results in a number of chare/group creations.
21 <li>Sends off all readonly data to the other processors.
22 </ol>
23 After _initCharm, processor 0 immediately begins work.
24
25 The other processors, however, must wait until they recieve 
26 the readonly data and all group creations.  They do this by 
27 setting the _charmHandlerIdx to a special "_bufferHandler"
28 which simply saves all normal messages into a special queue.  
29
30 As the startup data (readonlies and group creations) streams
31 into _initHandler, it counts messages until it is fully 
32 initialized, then calls _initDone to clean out the queues 
33 and resume normal operation.  
34
35 Upon resume of normal operation, the user code is guaranteed that
36 all readonlies (both data and messages) have been set consistently
37 on all processors, and that the constructors for all nodegroups
38 and groups allocated from a mainchare have been called.
39
40 It is not guaranteed the order in which (node)groups allocated
41 outside of a mainchare are constructed, nor that the construction
42 will happen before other messages have been delivered by the scheduler.
43
44 Even though not exposed to the final users, the creation order of
45 groups and nodegroups allocated in mainchares is deterministic and
46 respects the following points:
47 <ul>
48 <li>On all processors, there is no guarantee of the order of creation
49 between (node)groups allocated from different mainchares;
50 <li>On processor zero, within a mainchare, all (node)groups are created
51 in the order specified by the source code (strictly), including array
52 allocation of initial elements;
53 <li>On processors other than zero, within a mainchare, the order
54 specified by the source code is maintained between different nodegroups
55 and between different groups;
56 <li>On processors other than zero, the ordering between groups and
57 nodegroups is NOT maintained, as all nodegroups are created before any
58 group is created.
59 </ul>
60
61 This process should not have race conditions, but it can
62 never be excluded...
63 */
64 /*@{*/
65
66 #include "ckcheckpoint.h"
67 #include "ck.h"
68 #include "trace.h"
69 #include "ckrdma.h"
70 #include "CkCheckpoint.decl.h"
71 #include "ckmulticast.h"
72 #include <sstream>
73 #include <limits.h>
74 #include "spanningTree.h"
75 #if CMK_CHARMPY
76 #include "GreedyRefineLB.h"
77 #endif
78
79 #if CMK_CUDA
80 #include "hapi_impl.h"
81 #endif
82
83 void CkRestartMain(const char* dirname, CkArgMsg* args);
84
85 #define  DEBUGF(x)     //CmiPrintf x;
86
87 #define CMK_WITH_WARNINGS 0
88
89 #include "TopoManager.h"
90
91 UChar _defaultQueueing = CK_QUEUEING_FIFO;
92
93 UInt  _printCS = 0;
94 UInt  _printSS = 0;
95
96 /**
97  * This value has the number of total initialization message a processor awaits.
98  * It is received on nodes other than zero together with the ROData message.
99  * Even though it is shared by all processors it is ok: it doesn't matter when and
100  * by who it is set, provided that it becomes equal to the number of awaited messages
101  * (which is always at least one ---the readonly data message).
102  */
103 UInt  _numExpectInitMsgs = 0;
104 /**
105  * This number is used only by processor zero to count how many messages it will
106  * send out for the initialization process. After the readonly data message is sent
107  * (containing this counter), its value becomes irrelevant.
108  */
109 UInt  _numInitMsgs = 0;
110 /**
111  * Count the number of nodegroups that have been created in mainchares.
112  * Since the nodegroup creation is executed by a single processor in a
113  * given node, this value must be seen by all processors in a node.
114  */
115 CksvDeclare(UInt,_numInitNodeMsgs);
116 int   _infoIdx;
117 int   _charmHandlerIdx;
118 int   _initHandlerIdx;
119 int   _roRestartHandlerIdx;
120 int   _bocHandlerIdx;
121 int   _qdHandlerIdx;
122 int   _qdCommHandlerIdx;
123 int   _triggerHandlerIdx;
124 bool  _mainDone = false;
125 CksvDeclare(bool, _triggersSent);
126
127 CkOutStream ckout;
128 CkErrStream ckerr;
129 CkInStream  ckin;
130
131 CkpvDeclare(void*,       _currentChare);
132 CkpvDeclare(int,         _currentChareType);
133 CkpvDeclare(CkGroupID,   _currentGroup);
134 CkpvDeclare(void*,       _currentNodeGroupObj);
135 CkpvDeclare(CkGroupID,   _currentGroupRednMgr);
136 CkpvDeclare(GroupTable*, _groupTable);
137 CkpvDeclare(GroupIDTable*, _groupIDTable);
138 CkpvDeclare(CmiImmediateLockType, _groupTableImmLock);
139 CkpvDeclare(UInt, _numGroups);
140
141 CkpvDeclare(CkCoreState *, _coreState);
142
143 CksvDeclare(UInt, _numNodeGroups);
144 CksvDeclare(GroupTable*, _nodeGroupTable);
145 CksvDeclare(GroupIDTable, _nodeGroupIDTable);
146 CksvDeclare(CmiImmediateLockType, _nodeGroupTableImmLock);
147 CksvDeclare(CmiNodeLock, _nodeLock);
148 CksvStaticDeclare(PtrVec*,_nodeBocInitVec);
149 CkpvDeclare(int, _charmEpoch);
150
151 CkpvDeclare(bool, _destroyingNodeGroup);
152
153
154 CkpvDeclare(Stats*, _myStats);
155 CkpvDeclare(MsgPool*, _msgPool);
156
157 CkpvDeclare(_CkOutStream*, _ckout);
158 CkpvDeclare(_CkErrStream*, _ckerr);
159
160 CkpvStaticDeclare(int,  _numInitsRecd);
161 CkpvStaticDeclare(bool,  _initdone);
162 CkpvStaticDeclare(PtrQ*, _buffQ);
163 CkpvStaticDeclare(PtrVec*, _bocInitVec);
164
165 //for interoperability
166 extern void _libExitHandler(envelope *env);
167 extern int _libExitHandlerIdx;
168 CpvCExtern(int,interopExitFlag);
169
170 #if CMK_SHRINK_EXPAND
171 //for shrink expand cleanup
172 int _ROGroupRestartHandlerIdx;
173 const char* _shrinkexpand_basedir;
174 #endif
175
176 #if CMK_FAULT_EVAC
177 CpvExtern(char *, _validProcessors);
178 CkpvDeclare(char ,startedEvac);
179 #endif
180
181 int    _exitHandlerIdx;
182
183 #if CMK_WITH_STATS
184 static Stats** _allStats = 0;
185 #endif
186 static bool   _exitStarted = false;
187 static int _exitcode;
188
189 static InitCallTable _initCallTable;
190
191 #if CMK_WITH_STATS
192 #define _STATS_ON(x) (x) = 1
193 #else
194 #define _STATS_ON(x) \
195           if (CkMyPe()==0) CmiPrintf("stats unavailable in optimized version. ignoring...\n");
196 #endif
197
198 // fault tolerance
199 typedef void (*CkFtFn)(const char *, CkArgMsg *);
200 static CkFtFn  faultFunc = NULL;
201 static char* _restartDir;
202
203 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
204 int teamSize=1;
205 int chkptPeriod=1000;
206 bool fastRecovery = false;
207 int parallelRecovery = 1;
208 extern int BUFFER_TIME; //time spent waiting for buffered messages
209 #endif
210
211 // flag for killing processes 
212 extern bool killFlag;
213 // file specifying the processes to be killed
214 extern char *killFile;
215 // function for reading the kill file
216 void readKillFile();
217 #if CMK_MESSAGE_LOGGING
218 // flag for disk checkpoint
219 extern bool diskCkptFlag;
220 #endif
221
222 int _defaultObjectQ = 0;            // for obejct queue
223 bool _ringexit = 0;                 // for charm exit
224 int _ringtoken = 8;
225 extern int _messageBufferingThreshold;
226
227 #if CMK_FAULT_EVAC
228 static bool _raiseEvac=0; // whether or not to trigger the processor shutdowns
229 static char *_raiseEvacFile;
230 void processRaiseEvacFile(char *raiseEvacFile);
231 #endif
232
233 extern bool useNodeBlkMapping;
234
235 CMI_EXTERNC_VARIABLE int quietMode;
236 CMI_EXTERNC_VARIABLE int quietModeRequested;
237
238 // Modules are required to register command line opts they will parse. These
239 // options are stored in the _optSet, and then when parsing command line opts
240 // users will be warned about options starting with a '+' that are not in this
241 // table. This usually implies that they are attempting to use a Charm++ option
242 // without having compiled Charm++ to use the module that options belongs to.
243 std::set<std::string> _optSet;
244 void _registerCommandLineOpt(const char* opt) {
245   // The command line options are only checked during init on PE0, so this makes
246   // thread safety easy.
247   if (CkMyPe() == 0) {
248     _optSet.insert(opt);
249   }
250 }
251
252 static inline void _parseCommandLineOpts(char **argv)
253 {
254   if (CmiGetArgFlagDesc(argv,"+cs", "Print extensive statistics at shutdown"))
255       _STATS_ON(_printCS);
256   if (CmiGetArgFlagDesc(argv,"+ss", "Print summary statistics at shutdown"))
257       _STATS_ON(_printSS);
258   if (CmiGetArgFlagDesc(argv,"+fifo", "Default to FIFO queuing"))
259       _defaultQueueing = CK_QUEUEING_FIFO;
260   if (CmiGetArgFlagDesc(argv,"+lifo", "Default to LIFO queuing"))
261       _defaultQueueing = CK_QUEUEING_LIFO;
262   if (CmiGetArgFlagDesc(argv,"+ififo", "Default to integer-prioritized FIFO queuing"))
263       _defaultQueueing = CK_QUEUEING_IFIFO;
264   if (CmiGetArgFlagDesc(argv,"+ilifo", "Default to integer-prioritized LIFO queuing"))
265       _defaultQueueing = CK_QUEUEING_ILIFO;
266   if (CmiGetArgFlagDesc(argv,"+bfifo", "Default to bitvector-prioritized FIFO queuing"))
267       _defaultQueueing = CK_QUEUEING_BFIFO;
268   if (CmiGetArgFlagDesc(argv,"+blifo", "Default to bitvector-prioritized LIFO queuing"))
269       _defaultQueueing = CK_QUEUEING_BLIFO;
270   if (CmiGetArgFlagDesc(argv,"+objq", "Default to use object queue for every obejct"))
271   {
272 #if CMK_OBJECT_QUEUE_AVAILABLE
273       _defaultObjectQ = 1;
274       if (CkMyPe()==0)
275         CmiPrintf("Charm++> Create object queue for every Charm object.\n");
276 #else
277       CmiAbort("Charm++> Object queue not enabled, recompile Charm++ with CMK_OBJECT_QUEUE_AVAILABLE defined to 1.");
278 #endif
279   }
280
281 #if CMK_SHRINK_EXPAND
282   if (!CmiGetArgStringDesc(argv, "+shrinkexpand_basedir", (char **)&_shrinkexpand_basedir,
283                            "Checkpoint directory used for shrink-expand (defaults to /dev/shm)"))
284 # if defined __APPLE__
285       _shrinkexpand_basedir = "/tmp";
286 # else
287       _shrinkexpand_basedir = "/dev/shm";
288 # endif
289 #endif
290
291   if(CmiGetArgString(argv,"+restart",&_restartDir))
292       faultFunc = CkRestartMain;
293 #if __FAULT__
294   if (CmiGetArgIntDesc(argv,"+restartaftercrash",&CpvAccess(_curRestartPhase),"restarting this processor after a crash")){      
295 # if CMK_MEM_CHECKPOINT
296       faultFunc = CkMemRestart;
297 # endif
298 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
299       faultFunc = CkMlogRestart;
300 #endif
301       CmiPrintf("[%d] Restarting after crash \n",CmiMyPe());
302   }
303 #if CMK_MESSAGE_LOGGING
304         // reading +ftc_disk flag
305         if (CmiGetArgFlagDesc(argv, "+ftc_disk", "Disk Checkpointing")) {
306                 diskCkptFlag = true;
307     }
308 #endif
309   // reading the killFile
310   if(CmiGetArgStringDesc(argv,"+killFile", &killFile,"Generates SIGKILL on specified processors")){
311     if(faultFunc == NULL){
312       //do not read the killfile if this is a restarting processor
313       killFlag = true;
314       if(CmiMyPe() == 0){
315         printf("[%d] killFlag set to true for file %s\n",CkMyPe(),killFile);
316       }
317     }
318   }
319 #endif
320
321   // shut down program in ring fashion to allow projections output w/o IO error
322   if (CmiGetArgIntDesc(argv,"+ringexit",&_ringtoken, "Program exits in a ring fashion")) 
323   {
324     _ringexit = true;
325     if (CkMyPe()==0)
326       CkPrintf("Charm++> Program shutdown in token ring (%d).\n", _ringtoken);
327     if (_ringtoken > CkNumPes())  _ringtoken = CkNumPes();
328   }
329 #if CMK_FAULT_EVAC
330   // if the argument +raiseevac is present then cause faults
331         if(CmiGetArgStringDesc(argv,"+raiseevac", &_raiseEvacFile,"Generates processor evacuation on random processors")){
332                 _raiseEvac = 1;
333         }
334 #endif
335 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
336         if(!CmiGetArgIntDesc(argv,"+teamSize",&teamSize,"Set the team size for message logging")){
337         teamSize = 1;
338     }
339     if(!CmiGetArgIntDesc(argv,"+chkptPeriod",&chkptPeriod,"Set the checkpoint period for the message logging fault tolerance algorithm in seconds")){
340         chkptPeriod = 100;
341     }
342         if(CmiGetArgIntDesc(argv,"+fastRecovery", &parallelRecovery, "Parallel recovery with message logging protocol")){
343         fastRecovery = true;
344     }
345 #endif
346
347         if (!CmiGetArgIntDesc(argv, "+messageBufferingThreshold",
348                               &_messageBufferingThreshold,
349                               "Message size above which the runtime will buffer messages directed at unlocated array elements")) {
350           _messageBufferingThreshold = INT_MAX;
351         }
352
353         /* Anytime migration flag */
354         _isAnytimeMigration = true;
355         if (CmiGetArgFlagDesc(argv,"+noAnytimeMigration","The program does not require support for anytime migration")) {
356           _isAnytimeMigration = false;
357         }
358         
359         _isNotifyChildInRed = true;
360         if (CmiGetArgFlagDesc(argv,"+noNotifyChildInReduction","The program has at least one element per processor for each charm array created")) {
361           _isNotifyChildInRed = false;
362         }
363
364         _isStaticInsertion = false;
365         if (CmiGetArgFlagDesc(argv,"+staticInsertion","Array elements are only inserted at construction")) {
366           _isStaticInsertion = true;
367         }
368
369         useNodeBlkMapping = false;
370         if (CmiGetArgFlagDesc(argv,"+useNodeBlkMapping","Array elements are block-mapped in SMP-node level")) {
371           useNodeBlkMapping = true;
372         }
373
374 #if ! CMK_WITH_CONTROLPOINT
375         // Display a warning if charm++ wasn't compiled with control point support but user is expecting it
376         if( CmiGetArgFlag(argv,"+CPSamplePeriod") || 
377             CmiGetArgFlag(argv,"+CPSamplePeriodMs") || 
378             CmiGetArgFlag(argv,"+CPSchemeRandom") || 
379             CmiGetArgFlag(argv,"+CPExhaustiveSearch") || 
380             CmiGetArgFlag(argv,"+CPAlwaysUseDefaults") || 
381             CmiGetArgFlag(argv,"+CPSimulAnneal") || 
382             CmiGetArgFlag(argv,"+CPCriticalPathPrio") || 
383             CmiGetArgFlag(argv,"+CPBestKnown") || 
384             CmiGetArgFlag(argv,"+CPSteering") || 
385             CmiGetArgFlag(argv,"+CPMemoryAware") || 
386             CmiGetArgFlag(argv,"+CPSimplex") || 
387             CmiGetArgFlag(argv,"+CPDivideConquer") || 
388             CmiGetArgFlag(argv,"+CPLDBPeriod") || 
389             CmiGetArgFlag(argv,"+CPLDBPeriodLinear") || 
390             CmiGetArgFlag(argv,"+CPLDBPeriodQuadratic") || 
391             CmiGetArgFlag(argv,"+CPLDBPeriodOptimal") || 
392             CmiGetArgFlag(argv,"+CPDefaultValues") || 
393             CmiGetArgFlag(argv,"+CPGatherAll") || 
394             CmiGetArgFlag(argv,"+CPGatherMemoryUsage") || 
395             CmiGetArgFlag(argv,"+CPGatherUtilization") || 
396             CmiGetArgFlag(argv,"+CPSaveData") || 
397             CmiGetArgFlag(argv,"+CPNoFilterData") || 
398             CmiGetArgFlag(argv,"+CPLoadData") || 
399             CmiGetArgFlag(argv,"+CPDataFilename")    )
400           {         
401             CkAbort("You specified a control point command line argument, but compiled charm++ without control point support.\n");
402           }
403 #endif
404        
405 }
406
407 static void _bufferHandler(void *msg)
408 {
409   DEBUGF(("[%d] _bufferHandler called.\n", CkMyPe()));
410   CkpvAccess(_buffQ)->enq(msg);
411 }
412
413 static void _discardHandler(envelope *env)
414 {
415 //  MESSAGE_PHASE_CHECK(env);
416
417   DEBUGF(("[%d] _discardHandler called.\n", CkMyPe()));
418 #if CMK_MEM_CHECKPOINT
419   //CkPrintf("[%d] _discardHandler called!\n", CkMyPe());
420   if (CkInRestarting()) CpvAccess(_qd)->process();
421 #endif
422   CmiFree(env);
423 }
424
425 #if CMK_WITH_STATS
426 static inline void _printStats(void)
427 {
428   DEBUGF(("[%d] _printStats\n", CkMyPe()));
429   int i;
430   if(_printSS || _printCS) {
431     Stats *total = new Stats();
432     _MEMCHECK(total);
433     for(i=0;i<CkNumPes();i++)
434       total->combine(_allStats[i]);
435     CkPrintf("Charm Kernel Summary Statistics:\n");
436     for(i=0;i<CkNumPes();i++) {
437       CkPrintf("Proc %d: [%d created, %d processed]\n", i,
438                _allStats[i]->getCharesCreated(),
439                _allStats[i]->getCharesProcessed());
440     }
441     CkPrintf("Total Chares: [%d created, %d processed]\n",
442              total->getCharesCreated(), total->getCharesProcessed());
443   }
444   if(_printCS) {
445     CkPrintf("Charm Kernel Detailed Statistics (R=requested P=processed):\n\n");
446
447     CkPrintf("         Create    Mesgs     Create    Mesgs     Create    Mesgs\n");
448     CkPrintf("         Chare     for       Group     for       Nodegroup for\n");
449     CkPrintf("PE   R/P Mesgs     Chares    Mesgs     Groups    Mesgs     Nodegroups\n");
450     CkPrintf("---- --- --------- --------- --------- --------- --------- ----------\n");
451
452     for(i=0;i<CkNumPes();i++) {
453       CkPrintf("%4d  R  %9d %9d %9d %9d %9d %9d\n      P  %9d %9d %9d %9d %9d %9d\n",i,
454                _allStats[i]->getCharesCreated(),
455                _allStats[i]->getForCharesCreated(),
456                _allStats[i]->getGroupsCreated(),
457                _allStats[i]->getGroupMsgsCreated(),
458                _allStats[i]->getNodeGroupsCreated(),
459                _allStats[i]->getNodeGroupMsgsCreated(),
460                _allStats[i]->getCharesProcessed(),
461                _allStats[i]->getForCharesProcessed(),
462                _allStats[i]->getGroupsProcessed(),
463                _allStats[i]->getGroupMsgsProcessed(),
464                _allStats[i]->getNodeGroupsProcessed(),
465                _allStats[i]->getNodeGroupMsgsProcessed());
466     }
467   }
468 }
469 #else
470 static inline void _printStats(void) {}
471 #endif
472
473 typedef struct _statsHeader
474 {
475   int n;
476 } statsHeader;
477
478 static void * mergeStats(int *size, void *data, void **remote, int count)
479 {
480   envelope *newData;
481   statsHeader *dataMsg = (statsHeader*)EnvToUsr((envelope*) data), *newDataMsg;
482   int nPes = dataMsg->n, currentIndex = 0;
483
484   for (int i = 0; i < count; ++i)
485   {
486     nPes += ((statsHeader *)EnvToUsr((envelope *)remote[i]))->n;
487   }
488
489   newData = _allocEnv(StatMsg, sizeof(statsHeader) + sizeof(Stats)*nPes);
490   *size = newData->getTotalsize();
491   newDataMsg = (statsHeader *)EnvToUsr(newData);
492   newDataMsg->n = nPes;
493
494   statsHeader *current = dataMsg;
495   Stats *currentStats = (Stats*)(current + 1), *destination = (Stats*)(newDataMsg + 1);
496   memcpy(destination + currentIndex, currentStats, sizeof(Stats) * current->n);
497   currentIndex += current->n;
498
499   for (int i = 0; i < count; ++i)
500   {
501     current = ((statsHeader *)EnvToUsr((envelope *)remote[i]));
502     currentStats = (Stats *)(current + 1);
503     memcpy(destination + currentIndex, currentStats, sizeof(Stats) * current->n);
504     currentIndex += current->n;
505   }
506
507   CmiFree(data);
508   return newData;
509 }
510
511 static inline void _sendStats(void)
512 {
513   DEBUGF(("[%d] _sendStats\n", CkMyPe()));
514   envelope *env = _allocEnv(StatMsg, sizeof(statsHeader) + sizeof(Stats));
515   statsHeader* msg = (statsHeader*)EnvToUsr(env);
516   msg->n = 1;
517   memcpy(msg+1, CkpvAccess(_myStats), sizeof(Stats));
518   CmiSetHandler(env, _exitHandlerIdx);
519   CmiReduce(env, env->getTotalsize(), mergeStats);
520 }
521
522 #if CMK_LOCKLESS_QUEUE
523 typedef struct _WarningMsg{
524   int queue_overflow_count;
525 } WarningMsg;
526
527 /* General purpose handler for runtime warnings post-execution */
528 static void *mergeWarningMsg(int * size, void * data, void ** remote, int count){
529   int i;
530
531   WarningMsg *msg = (WarningMsg*)EnvToUsr((envelope*) data), *m;
532
533   /* Reduction on warning information gained from children */
534   for(i = 0; i < count; ++i)
535   {
536     m = (WarningMsg*)EnvToUsr((envelope*) remote[i]);
537     msg->queue_overflow_count += m->queue_overflow_count;
538   }
539
540   return data;
541 }
542
543 /* Initializes the reduction, called on each processor */
544 extern int messageQueueOverflow;
545 static inline void _sendWarnings(void)
546 {
547   DEBUGF(("[%d] _sendWarnings\n", CkMyPe()));
548
549   envelope *env = _allocEnv(WarnMsg, sizeof(WarningMsg));
550   WarningMsg* msg = (WarningMsg*)EnvToUsr(env);
551
552   /* Set processor specific warning information here */
553   msg->queue_overflow_count = messageQueueOverflow;
554
555   CmiSetHandler(env, _exitHandlerIdx);
556   CmiReduce(env, env->getTotalsize(), mergeWarningMsg);
557 }
558
559 /* Reporting warnings to the user */
560 static inline void ReportWarnings(WarningMsg * msg)
561 {
562   if(msg->queue_overflow_count > 0)
563   {
564     CmiPrintf("WARNING: Message queues overflowed during execution, this can negatively impact performance.\n");
565     CmiPrintf("\tModify the size of the message queues using: +MessageQueueNodes and +MessageQueueNodeSize\n");
566   }
567 }
568 #endif /* CMK_LOCKLESS_QUEUE */
569
570 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
571 extern void _messageLoggingExit();
572 #endif
573
574 #if __FAULT__
575 //CpvExtern(int, CldHandlerIndex);
576 //extern "C" void CldHandler(char *);
577 extern int index_skipCldHandler;
578 extern void _skipCldHandler(void *converseMsg);
579
580 void _discard_charm_message()
581 {
582   CkNumberHandler(_charmHandlerIdx,_discardHandler);
583 //  CkNumberHandler(CpvAccess(CldHandlerIndex), _discardHandler);
584   CkNumberHandler(index_skipCldHandler, _discardHandler);
585 }
586
587 void _resume_charm_message()
588 {
589   CkNumberHandlerEx(_charmHandlerIdx, _processHandler, CkpvAccess(_coreState));
590 //  CkNumberHandler(CpvAccess(CldHandlerIndex), CldHandler);
591   CkNumberHandler(index_skipCldHandler, _skipCldHandler);
592 }
593 #endif
594
595 static void _exitHandler(envelope *env)
596 {
597   DEBUGF(("exitHandler called on %d msgtype: %d\n", CkMyPe(), env->getMsgtype()));
598   switch(env->getMsgtype()) {
599     case StartExitMsg: // Exit sequence trigger message
600       CkAssert(CkMyPe()==0);
601       if(_exitStarted) {
602         CmiFree(env);
603         return;
604       }
605       _exitStarted = true;
606
607       // else fall through
608     case ExitMsg: // Exit sequence trigger message using user registered exit function
609       CkAssert(CkMyPe()==0);
610       if (!_CkExitFnVec.isEmpty()) {
611         CmiFree(env);
612         CkExitFn fn = _CkExitFnVec.deq();
613         fn();
614         break;
615       }
616
617       CkNumberHandler(_charmHandlerIdx,_discardHandler);
618       CkNumberHandler(_bocHandlerIdx, _discardHandler);
619 #if !CMK_BIGSIM_THREAD
620       env->setMsgtype(ReqStatMsg);
621       env->setSrcPe(CkMyPe());
622       // if exit in ring, instead of broadcasting, send in ring
623       if (_ringexit){
624         DEBUGF(("[%d] Ring Exit \n",CkMyPe()));
625         const int stride = CkNumPes()/_ringtoken;
626         int pe = 0;
627         while (pe<CkNumPes()) {
628           CmiSyncSend(pe, env->getTotalsize(), (char *)env);
629           pe += stride;
630         }
631         CmiFree(env);
632       }else{
633         CmiSyncBroadcastAllAndFree(env->getTotalsize(), (char *)env);
634       }
635 #else
636       CmiFree(env);
637       ConverseExit(_exitcode);
638 #endif
639       break;
640     case ReqStatMsg: // Request stats and warnings message
641 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
642       _messageLoggingExit();
643 #endif
644       DEBUGF(("ReqStatMsg on %d\n", CkMyPe()));
645       CkNumberHandler(_charmHandlerIdx,_discardHandler);
646       CkNumberHandler(_bocHandlerIdx, _discardHandler);
647 #if CMK_FAULT_EVAC
648       if(CmiNodeAlive(CkMyPe()))
649 #endif
650       {
651 #if CMK_WITH_STATS
652          _sendStats();
653 #endif
654 #if CMK_WITH_WARNINGS
655          _sendWarnings();
656 #endif
657       _mainDone = true; // This is needed because the destructors for
658                         // readonly variables will be called when the program
659                         // exits. If the destructor is called while _mainDone
660                         // is false, it will assume that the readonly variable was
661                         // declared locally. On all processors other than 0,
662                         // _mainDone is never set to true before the program exits.
663 #if CMK_TRACE_ENABLED
664       if (_ringexit) traceClose();
665 #endif
666     }
667       if (_ringexit) {
668         int stride = CkNumPes()/_ringtoken;
669         int pe = CkMyPe()+1;
670         if (pe < CkNumPes() && pe % stride != 0)
671           CmiSyncSendAndFree(pe, env->getTotalsize(), (char *)env);
672         else
673           CmiFree(env);
674       }
675       else
676         CmiFree(env);
677 #if CMK_SHRINK_EXPAND
678       ConverseCleanup();
679 #endif
680       //everyone exits here - there may be issues with leftover messages in the queue
681 #if !CMK_WITH_STATS && !CMK_WITH_WARNINGS
682       DEBUGF(("[%d] Calling converse exit from ReqStatMsg \n",CkMyPe()));
683       ConverseExit(_exitcode);
684       if(CharmLibInterOperate)
685         CpvAccess(interopExitFlag) = 1;
686 #endif
687       break;
688 #if CMK_WITH_STATS
689     case StatMsg: // Stats data message (in response to ReqStatMsg)
690     {
691       CkAssert(CkMyPe()==0);
692       statsHeader* header = (statsHeader*)EnvToUsr(env);
693       int n = header->n;
694       Stats* currentStats = (Stats*)(header + 1);
695       for (int i = 0; i < n; ++i)
696       {
697         _allStats[currentStats->getPe()] = currentStats;
698         currentStats++;
699       }
700       DEBUGF(("StatMsg on %d with %d\n", CkMyPe(), n));
701       _printStats();
702       // broadcast to all others that they can now exit
703       envelope* env = _allocEnv(StatDoneMsg);
704       CmiSetHandler(env, _exitHandlerIdx);
705       CmiSyncBroadcastAllAndFree(env->getTotalsize(), (char*)env);
706     }
707     break;
708
709     case StatDoneMsg: // Indicates completion of stats reduction
710       DEBUGF(("[%d] Calling converse exit from StatDoneMsg \n",CkMyPe()));
711       ConverseExit(_exitcode);
712       if (CharmLibInterOperate)
713         CpvAccess(interopExitFlag) = 1;
714       break;
715 #endif
716 #if CMK_WITH_WARNINGS
717     case WarnMsg: // Warnings data message (in reponse to ReqStatMsg)
718     {
719       CkAssert(CkMyPe()==0);
720       WarningMsg* msg = (WarningMsg*)EnvToUsr(env);
721       ReportWarnings(msg);
722
723       envelope* env = _allocEnv(WarnDoneMsg);
724       CmiSetHandler(env, _exitHandlerIdx);
725       CmiSyncBroadcastAllAndFree(env->getTotalsize(), (char*)env);
726       break;
727     }
728     case WarnDoneMsg: // Indicates completion of warnings reduction
729       DEBUGF(("[%d] Calling converse exit from WarnDoneMsg \n",CkMyPe()));
730       ConverseExit(_exitcode);
731       if (CharmLibInterOperate)
732         CpvAccess(interopExitFlag) = 1;
733       break;
734 #endif
735     default:
736       CmiAbort("Internal Error(_exitHandler): Unknown-msg-type. Contact Developers.\n");
737   }
738 }
739
740 #if CMK_SHRINK_EXPAND
741 void _ROGroupRestartHandler(void * msg){
742   CkResumeRestartMain((char *)msg);
743 }
744 #endif
745
746 /**
747  * Create all groups in this processor (not called on processor zero).
748  * Notice that only groups created in mainchares are processed here;
749  * groups created later are processed as regular messages.
750  */
751 static inline void _processBufferedBocInits(void)
752 {
753   CkCoreState *ck = CkpvAccess(_coreState);
754   CkNumberHandlerEx(_bocHandlerIdx,_processHandler, ck);
755   PtrVec &inits=*CkpvAccess(_bocInitVec);
756   int len = inits.size();
757   for(int i=1; i<len; i++) {
758     envelope *env = inits[i];
759     if(env==0) {
760 #if CMK_SHRINK_EXPAND
761       if(_inrestart){
762         CkPrintf("_processBufferedBocInits: empty message in restart, ignoring\n");
763         break;
764       }
765       else
766         CkAbort("_processBufferedBocInits: empty message");
767 #else
768       CkAbort("_processBufferedBocInits: empty message");
769 #endif
770     }
771     if(env->isPacked())
772       CkUnpackMessage(&env);
773     _processBocInitMsg(ck,env);
774   }
775   delete &inits;
776 }
777
778 /**
779  * Create all nodegroups in this node (called only by rank zero, and never on node zero).
780  * Notice that only nodegroups created in mainchares are processed here;
781  * nodegroups created later are processed as regular messages.
782  */
783 static inline void _processBufferedNodeBocInits(void)
784 {
785   CkCoreState *ck = CkpvAccess(_coreState);
786   PtrVec &inits=*CksvAccess(_nodeBocInitVec);
787   int len = inits.size();
788   for(int i=1; i<len; i++) {
789     envelope *env = inits[i];
790     if(env==0) CkAbort("_processBufferedNodeBocInits: empty message");
791     if(env->isPacked())
792       CkUnpackMessage(&env);
793     _processNodeBocInitMsg(ck,env);
794   }
795   delete &inits;
796 }
797
798 static inline void _processBufferedMsgs(void)
799 {
800   CkNumberHandlerEx(_charmHandlerIdx, _processHandler, CkpvAccess(_coreState));
801   envelope *env;
802   while(NULL!=(env=(envelope*)CkpvAccess(_buffQ)->deq())) {
803     if(env->getMsgtype()==NewChareMsg || env->getMsgtype()==NewVChareMsg) {
804       if(env->isForAnyPE())
805         _CldEnqueue(CLD_ANYWHERE, env, _infoIdx);
806       else
807         _processHandler((void *)env, CkpvAccess(_coreState));
808     } else {
809       _processHandler((void *)env, CkpvAccess(_coreState));
810     }
811   }
812 }
813
814 static int _charmLoadEstimator(void)
815 {
816   return CkpvAccess(_buffQ)->length();
817 }
818
819 /**
820  * This function is used to send other processors on the same node a signal so
821  * they can check if their _initDone can be called: the reason for this is that
822  * the check at the end of _initHandler can fail due to a missing message containing
823  * a Nodegroup creation. When that message arrives only one processor will receive
824  * it, and thus if no notification is sent to the other processors in the node, they
825  * will never proceed.
826  */
827 static void _sendTriggers(void)
828 {
829   int i, num, first;
830   CmiImmediateLock(CksvAccess(_nodeGroupTableImmLock));
831   if (!CksvAccess(_triggersSent))
832   {
833     CksvAccess(_triggersSent) = true;
834     num = CmiMyNodeSize();
835     envelope *env = _allocEnv(RODataMsg); // Notice that the type here is irrelevant
836     env->setSrcPe(CkMyPe());
837     CmiSetHandler(env, _triggerHandlerIdx);
838     first = CmiNodeFirst(CmiMyNode());
839     for (i=0; i < num; i++)
840       if(first+i != CkMyPe())
841         CmiSyncSend(first+i, env->getTotalsize(), (char *)env);
842     CmiFree(env);
843   }
844   CmiImmediateUnlock(CksvAccess(_nodeGroupTableImmLock));
845 }
846
847 /**
848  * This function (not a handler) is called once and only once per processor.
849  * It signals the processor that the initialization is done and regular messages
850  * can be processed.
851  *
852  * On processor zero it is called by _initCharm, on all other processors either
853  * by _initHandler or _triggerHandler (cannot be both).
854  * When fault-tolerance is active, it is called by the fault-tolerance scheme itself.
855  */
856 void _initDone(void)
857 {
858   if (CkpvAccess(_initdone)) return;
859   CkpvAccess(_initdone) = true;
860   DEBUGF(("[%d] _initDone.\n", CkMyPe()));
861   if (!CksvAccess(_triggersSent)) _sendTriggers();
862   CkNumberHandler(_triggerHandlerIdx, _discardHandler);
863   CmiNodeBarrier();
864   if(CkMyRank() == 0) {
865     _processBufferedNodeBocInits();
866     quietMode = 0; // re-enable CmiPrintf's if they were disabled
867   }
868   CmiNodeBarrier(); // wait for all nodegroups to be created
869   _processBufferedBocInits();
870   DEBUGF(("Reached CmiNodeBarrier(), pe = %d, rank = %d\n", CkMyPe(), CkMyRank()));
871   CmiNodeBarrier();
872   DEBUGF(("Crossed CmiNodeBarrier(), pe = %d, rank = %d\n", CkMyPe(), CkMyRank()));
873   _processBufferedMsgs();
874   CkpvAccess(_charmEpoch)=1;
875 }
876
877 /**
878  * Converse handler receiving a signal from another processors in the same node.
879  * (On _sendTrigger there is the explanation of why this is necessary)
880  * Simply check if with the NodeGroup processed by another processor we reached
881  * the expected count. Notice that it can only be called before _initDone: after
882  * _initDone, a message destined for this handler will go instead to the _discardHandler.
883  */
884 static void _triggerHandler(envelope *env)
885 {
886   if (_numExpectInitMsgs && CkpvAccess(_numInitsRecd) + CksvAccess(_numInitNodeMsgs) == _numExpectInitMsgs)
887   {
888     DEBUGF(("Calling Init Done from _triggerHandler\n"));
889     _initDone();
890   }
891   if (env!=NULL) CmiFree(env);
892 }
893
894 static inline void _processROMsgMsg(envelope *env)
895 {
896   if(!CmiMyRank()) {
897     *((char **)(_readonlyMsgs[env->getRoIdx()]->pMsg))=(char *)EnvToUsr(env);
898   }
899 }
900
901 static inline void _processRODataMsg(envelope *env)
902 {
903   //Unpack each readonly:
904   if(!CmiMyRank()) {
905     PUP::fromMem pu((char *)EnvToUsr(env));
906     for(size_t i=0;i<_readonlyTable.size();i++) {
907       _readonlyTable[i]->pupData(pu);
908     }
909   }
910   CmiFree(env);
911 }
912
913 /**
914  * This is similar to the _initHandler, only that the Groups and Nodegroups are
915  * initialized from disk, so only one single message is expected.
916  *
917  * It is unclear how Readonly Messages are treated during restart... (if at all considered)
918  */
919 static void _roRestartHandler(void *msg)
920 {
921   CkAssert(CkMyPe()!=0);
922   envelope *env = (envelope *) msg;
923   CkpvAccess(_numInitsRecd)++;
924   _numExpectInitMsgs = env->getCount();
925   _processRODataMsg(env);
926   // in SMP, potentially there us a race condition between rank0 calling
927   // initDone, which sendTriggers, and PE 0 calls bdcastRO which broadcast
928   // readonlys
929   // if this readonly message arrives later, we need to call trigger again
930   // to trigger initDone() on all ranks
931   // we therefore needs to make sure initDone() is exactly 
932   _triggerHandler(NULL);
933 }
934
935 /**
936  * This handler is used only during initialization. It receives messages from
937  * processor zero regarding Readonly Data (in one single message), Readonly Messages,
938  * Groups, and Nodegroups.
939  * The Readonly Data message also contains the total number of messages expected
940  * during the initialization phase.
941  * For Groups and Nodegroups, only messages with epoch=0 (meaning created from within
942  * a mainchare) are buffered for special creation, the other messages are buffered
943  * together with all the other regular messages by _bufferHandler (and will be flushed
944  * after all the initialization messages have been processed).
945  */
946 static void _initHandler(void *msg, CkCoreState *ck)
947 {
948   CkAssert(CkMyPe()!=0);
949   envelope *env = (envelope *) msg;
950   
951   if (ck->watcher!=NULL) {
952     if (!ck->watcher->processMessage(&env,ck)) return;
953   }
954   
955   switch (env->getMsgtype()) {
956     case BocInitMsg: // Group creation message
957       if (env->getGroupEpoch()==0) {
958         CkpvAccess(_numInitsRecd)++;
959         // _qd->process() or ck->process() to update QD counters is called inside _processBocInitMsg
960         if (CkpvAccess(_bocInitVec)->size() < env->getGroupNum().idx + 1) {
961           CkpvAccess(_bocInitVec)->resize(env->getGroupNum().idx + 1);
962         }
963         (*CkpvAccess(_bocInitVec))[env->getGroupNum().idx] = env;
964       } else _bufferHandler(msg);
965       break;
966     case NodeBocInitMsg: // Nodegroup creation message
967       if (env->getGroupEpoch()==0) {
968         CmiImmediateLock(CksvAccess(_nodeGroupTableImmLock));
969         CksvAccess(_numInitNodeMsgs)++;
970         if (CksvAccess(_nodeBocInitVec)->size() < env->getGroupNum().idx + 1) {
971           CksvAccess(_nodeBocInitVec)->resize(env->getGroupNum().idx + 1);
972         }
973         (*CksvAccess(_nodeBocInitVec))[env->getGroupNum().idx] = env;
974         CmiImmediateUnlock(CksvAccess(_nodeGroupTableImmLock));
975         // _qd->process() or ck->process() to update QD counters is called inside _processNodeBocInitMsg
976       } else _bufferHandler(msg);
977       break;
978     case ROMsgMsg: // Readonly Message (for user declared readonly messages)
979       CkpvAccess(_numInitsRecd)++;
980       CpvAccess(_qd)->process();
981       if(env->isPacked()) CkUnpackMessage(&env);
982       _processROMsgMsg(env);
983       break;
984     case RODataMsg: // Readonly Data Message (for user declared readonly variables)
985       CkpvAccess(_numInitsRecd)++;
986       CpvAccess(_qd)->process();
987       _numExpectInitMsgs = env->getCount();
988       _processRODataMsg(env);
989       break;
990     default:
991       CmiAbort("Internal Error: Unknown-msg-type. Contact Developers.\n");
992   }
993   DEBUGF(("[%d,%.6lf] _numExpectInitMsgs %d CkpvAccess(_numInitsRecd)+CksvAccess(_numInitNodeMsgs) %d+%d\n",CmiMyPe(),CmiWallTimer(),_numExpectInitMsgs,CkpvAccess(_numInitsRecd),CksvAccess(_numInitNodeMsgs)));
994   if(_numExpectInitMsgs&&(CkpvAccess(_numInitsRecd)+CksvAccess(_numInitNodeMsgs)==_numExpectInitMsgs)) {
995     _initDone();
996   }
997 }
998
999 #if CMK_SHRINK_EXPAND
1000 extern "C"
1001 void CkCleanup()
1002 {
1003         // always send to PE 0
1004         envelope *env = _allocEnv(StartExitMsg);
1005         env->setSrcPe(CkMyPe());
1006         CmiSetHandler(env, _exitHandlerIdx);
1007         CmiSyncSendAndFree(0, env->getTotalsize(), (char *)env);
1008 }
1009 #endif
1010
1011 CkQ<CkExitFn> _CkExitFnVec;
1012
1013 // Trigger exit on PE 0,
1014 // which traverses _CkExitFnVec to call every registered user exit function.
1015 // Every user exit function should end with CkExit() to continue the chain.
1016 void CkExit(int exitcode)
1017 {
1018   DEBUGF(("[%d] CkExit called \n",CkMyPe()));
1019     // always send to PE 0
1020
1021   // Store exit code for use in ConverseExit
1022   _exitcode = exitcode;
1023   envelope *env = _allocEnv(StartExitMsg);
1024   env->setSrcPe(CkMyPe());
1025   CmiSetHandler(env, _exitHandlerIdx);
1026   CmiSyncSendAndFree(0, env->getTotalsize(), (char *)env);
1027
1028 #if ! CMK_BIGSIM_THREAD
1029   _TRACE_END_EXECUTE();
1030   //Wait for stats, which will call ConverseExit when finished:
1031         if(!CharmLibInterOperate)
1032   CsdScheduler(-1);
1033 #endif
1034 }
1035
1036 void CkContinueExit()
1037 {
1038   envelope *env = _allocEnv(ExitMsg);
1039   env->setSrcPe(CkMyPe());
1040   CmiSetHandler(env, _exitHandlerIdx);
1041   CmiSyncSendAndFree(0, env->getTotalsize(), (char *)env);
1042 }
1043
1044 /* This is a routine called in case the application is closing due to a signal.
1045    Tear down structures that must be cleaned up even when unclean exit happens.
1046    It is called by the machine layer whenever some problem occurs (it is thus up
1047    to the machine layer to call this function). */
1048 extern "C"
1049 void EmergencyExit(void) {
1050 #ifndef __BIGSIM__
1051   /* Delete _coreState to force any CkMessageWatcher to close down. */
1052   if (CkpvAccess(_coreState) != NULL) {
1053     delete CkpvAccess(_coreState);
1054     CkpvAccess(_coreState) = NULL;
1055   }
1056 #endif
1057 }
1058
1059 static void _nullFn(void *, void *)
1060 {
1061   CmiAbort("Null-Method Called. Program may have Unregistered Module!!\n");
1062 }
1063
1064 extern void _registerLBDatabase(void);
1065 extern void _registerMetaBalancer(void);
1066 extern void _registerPathHistory(void);
1067 #if CMK_WITH_CONTROLPOINT
1068 extern void _registerControlPoints(void);
1069 #endif
1070 extern void _registerTraceControlPoints();
1071 extern void _registerExternalModules(char **argv);
1072 extern void _ckModuleInit(void);
1073 extern void _loadbalancerInit();
1074 extern void _metabalancerInit();
1075 #if CMK_SMP && CMK_TASKQUEUE
1076 extern void _taskqInit();
1077 #endif
1078 #if CMK_SMP
1079 extern void LBTopoInit();
1080 #endif
1081 extern void _initChareTables();
1082 #if CMK_MEM_CHECKPOINT
1083 extern void init_memcheckpt(char **argv);
1084 #endif
1085 extern "C" void initCharmProjections();
1086 extern "C" void CmiInitCPUTopology(char **argv);
1087 extern "C" void CmiCheckAffinity();
1088 extern "C" void CmiInitMemAffinity(char **argv);
1089 extern "C" void CmiInitPxshm(char **argv);
1090
1091 //extern "C" void CldCallback();
1092
1093 void _registerInitCall(CkInitCallFn fn, int isNodeCall)
1094 {
1095   if (isNodeCall) _initCallTable.initNodeCalls.enq(fn);
1096   else _initCallTable.initProcCalls.enq(fn);
1097 }
1098
1099 void InitCallTable::enumerateInitCalls()
1100 {
1101   int i;
1102 #ifdef __BIGSIM__
1103   if(BgNodeRank()==0)        // called only once on an emulating node
1104 #else
1105   if(CkMyRank()==0) 
1106 #endif
1107   {
1108     for (i=0; i<initNodeCalls.length(); i++) initNodeCalls[i]();
1109   }
1110   // initproc may depend on initnode calls.
1111   CmiNodeAllBarrier();
1112   for (i=0; i<initProcCalls.length(); i++) initProcCalls[i]();
1113 }
1114
1115 CpvCExtern(int, cpdSuspendStartup);
1116 extern "C" void CpdFreeze(void);
1117
1118 extern int _dummy_dq;
1119
1120 extern "C" void initQd(char **argv)
1121 {
1122         CpvInitialize(QdState*, _qd);
1123         CpvAccess(_qd) = new QdState();
1124         if (CmiMyRank() == 0) {
1125 #if !defined(CMK_CPV_IS_SMP) && !CMK_SHARED_VARS_UNIPROCESSOR
1126         CpvAccessOther(_qd, 1) = new QdState(); // for i/o interrupt
1127 #endif
1128         }
1129         CmiAssignOnce(&_qdHandlerIdx, CmiRegisterHandler((CmiHandler)_qdHandler));
1130         CmiAssignOnce(&_qdCommHandlerIdx, CmiRegisterHandler((CmiHandler)_qdCommHandler));
1131         if (CmiGetArgIntDesc(argv,"+qd",&_dummy_dq, "QD time in seconds")) {
1132           if (CmiMyPe()==0)
1133             CmiPrintf("Charm++> Fake QD using %d seconds.\n", _dummy_dq);
1134         }
1135 }
1136
1137 #if CMK_BIGSIM_CHARM && CMK_CHARMDEBUG
1138 void CpdBgInit();
1139 #endif
1140 void CpdBreakPointInit();
1141
1142 extern void (*CkRegisterMainModuleCallback)();
1143
1144 /**
1145   This is the main charm setup routine.  It's called
1146   on all processors after Converse initialization.
1147   This routine gets passed to Converse from "main.C".
1148   
1149   The main purpose of this routine is to set up the objects
1150   and Ckpv's used during a regular Charm run.  See the comment
1151   at the top of the file for overall flow.
1152 */
1153 void _initCharm(int unused_argc, char **argv)
1154
1155         int inCommThread = (CmiMyRank() == CmiMyNodeSize());
1156
1157         DEBUGF(("[%d,%.6lf ] _initCharm started\n",CmiMyPe(),CmiWallTimer()));
1158         std::set_terminate([](){ CkAbort("Unhandled C++ exception in user code.\n");});
1159
1160         CkpvInitialize(size_t *, _offsets);
1161         CkpvAccess(_offsets) = new size_t[32];
1162         CkpvInitialize(PtrQ*,_buffQ);
1163         CkpvInitialize(PtrVec*,_bocInitVec);
1164         CkpvInitialize(void*, _currentChare);
1165         CkpvInitialize(int,   _currentChareType);
1166         CkpvInitialize(CkGroupID, _currentGroup);
1167         CkpvInitialize(void *, _currentNodeGroupObj);
1168         CkpvInitialize(CkGroupID, _currentGroupRednMgr);
1169         CkpvInitialize(GroupTable*, _groupTable);
1170         CkpvInitialize(GroupIDTable*, _groupIDTable);
1171         CkpvInitialize(CmiImmediateLockType, _groupTableImmLock);
1172         CkpvInitialize(bool, _destroyingNodeGroup);
1173         CkpvAccess(_destroyingNodeGroup) = false;
1174         CkpvInitialize(UInt, _numGroups);
1175         CkpvInitialize(int, _numInitsRecd);
1176         CkpvInitialize(bool, _initdone);
1177         CkpvInitialize(char**, Ck_argv); CkpvAccess(Ck_argv)=argv;
1178         CkpvInitialize(MsgPool*, _msgPool);
1179         CkpvInitialize(CkCoreState *, _coreState);
1180
1181 #if CMK_FAULT_EVAC
1182 #ifndef __BIGSIM__
1183         CpvInitialize(char *,_validProcessors);
1184 #endif
1185         CkpvInitialize(char ,startedEvac);
1186 #endif
1187         CpvInitialize(int,serializer);
1188
1189         _initChareTables();            // for checkpointable plain chares
1190
1191         CksvInitialize(UInt, _numNodeGroups);
1192         CksvInitialize(GroupTable*, _nodeGroupTable);
1193         CksvInitialize(GroupIDTable, _nodeGroupIDTable);
1194         CksvInitialize(CmiImmediateLockType, _nodeGroupTableImmLock);
1195         CksvInitialize(CmiNodeLock, _nodeLock);
1196         CksvInitialize(PtrVec*,_nodeBocInitVec);
1197         CksvInitialize(UInt,_numInitNodeMsgs);
1198         CkpvInitialize(int,_charmEpoch);
1199         CkpvAccess(_charmEpoch)=0;
1200         CksvInitialize(bool, _triggersSent);
1201         CksvAccess(_triggersSent) = false;
1202
1203         CkpvInitialize(_CkOutStream*, _ckout);
1204         CkpvInitialize(_CkErrStream*, _ckerr);
1205         CkpvInitialize(Stats*, _myStats);
1206
1207         CkpvAccess(_groupIDTable) = new GroupIDTable(0);
1208         CkpvAccess(_groupTable) = new GroupTable;
1209         CkpvAccess(_groupTable)->init();
1210         CkpvAccess(_groupTableImmLock) = CmiCreateImmediateLock();
1211         CkpvAccess(_numGroups) = 1; // make 0 an invalid group number
1212         CkpvAccess(_buffQ) = new PtrQ();
1213         CkpvAccess(_bocInitVec) = new PtrVec();
1214
1215         CkpvAccess(_currentNodeGroupObj) = NULL;
1216
1217         if(CkMyRank()==0)
1218         {
1219                 CksvAccess(_numNodeGroups) = 1; //make 0 an invalid group number
1220                 CksvAccess(_numInitNodeMsgs) = 0;
1221                 CksvAccess(_nodeLock) = CmiCreateLock();
1222                 CksvAccess(_nodeGroupTable) = new GroupTable();
1223                 CksvAccess(_nodeGroupTable)->init();
1224                 CksvAccess(_nodeGroupTableImmLock) = CmiCreateImmediateLock();
1225                 CksvAccess(_nodeBocInitVec) = new PtrVec();
1226         }
1227
1228         CkCallbackInit();
1229         
1230         CmiNodeAllBarrier();
1231
1232 #if ! CMK_BIGSIM_CHARM
1233         initQd(argv);         // bigsim calls it in ConverseCommonInit
1234 #endif
1235
1236         CkpvAccess(_coreState)=new CkCoreState();
1237
1238         CkpvAccess(_numInitsRecd) = 0;
1239         CkpvAccess(_initdone) = false;
1240
1241         CkpvAccess(_ckout) = new _CkOutStream();
1242         CkpvAccess(_ckerr) = new _CkErrStream();
1243
1244         CmiAssignOnce(&_charmHandlerIdx, CkRegisterHandler(_bufferHandler));
1245         CmiAssignOnce(&_initHandlerIdx, CkRegisterHandlerEx(_initHandler, CkpvAccess(_coreState)));
1246         CmiAssignOnce(&_roRestartHandlerIdx, CkRegisterHandler(_roRestartHandler));
1247         CmiAssignOnce(&_exitHandlerIdx, CkRegisterHandler(_exitHandler));
1248         //added for interoperabilitY
1249         CmiAssignOnce(&_libExitHandlerIdx, CkRegisterHandler(_libExitHandler));
1250         CmiAssignOnce(&_bocHandlerIdx, CkRegisterHandlerEx(_initHandler, CkpvAccess(_coreState)));
1251 #if CMK_SHRINK_EXPAND
1252         // for shrink expand cleanup
1253         CmiAssignOnce(&_ROGroupRestartHandlerIdx, CkRegisterHandler(_ROGroupRestartHandler));
1254 #endif
1255
1256 #ifdef __BIGSIM__
1257         if(BgNodeRank()==0) 
1258 #endif
1259         _infoIdx = CldRegisterInfoFn((CldInfoFn)_infoFn);
1260
1261         CmiAssignOnce(&_triggerHandlerIdx, CkRegisterHandler(_triggerHandler));
1262         _ckModuleInit();
1263
1264         CldRegisterEstimator((CldEstimator)_charmLoadEstimator);
1265
1266         _futuresModuleInit(); // part of futures implementation is a converse module
1267         _loadbalancerInit();
1268         _metabalancerInit();
1269
1270 #if CMK_SMP
1271         if (CmiMyRank() == 0) {
1272                 LBTopoInit();
1273         }
1274 #endif
1275 #if CMK_MEM_CHECKPOINT
1276         init_memcheckpt(argv);
1277 #endif
1278
1279         initCharmProjections();
1280 #if CMK_TRACE_IN_CHARM
1281         // initialize trace module in ck
1282         traceCharmInit(argv);
1283 #endif
1284         
1285     CkpvInitialize(int, envelopeEventID);
1286     CkpvAccess(envelopeEventID) = 0;
1287         CkMessageWatcherInit(argv,CkpvAccess(_coreState));
1288         
1289         // Set the ack handler function used for the direct nocopy api and the entry method nocopy api
1290         CmiSetDirectNcpyAckHandler(CkRdmaDirectAckHandler);
1291
1292 #if CMK_ONESIDED_IMPL
1293         CmiSetEMNcpyAckHandler(CkRdmaEMAckHandler);
1294 #endif
1295         /**
1296           The rank-0 processor of each node calls the 
1297           translator-generated "_register" routines. 
1298           
1299           _register routines call the charm.h "CkRegister*" routines,
1300           which record function pointers and class information for
1301           all Charm entities, like Chares, Arrays, and readonlies.
1302           
1303           There's one _register routine generated for each
1304           .ci file.  _register routines *must* be called in the 
1305           same order on every node, and *must not* be called by 
1306           multiple threads simultaniously.
1307         */
1308 #ifdef __BIGSIM__
1309         if(BgNodeRank()==0) 
1310 #else
1311         if(CkMyRank()==0)
1312 #endif
1313         {
1314                 SDAG::registerPUPables();
1315                 CmiArgGroup("Charm++",NULL);
1316                 _parseCommandLineOpts(argv);
1317                 _registerInit();
1318                 CkRegisterMsg("System", 0, 0, CkFreeMsg, sizeof(int));
1319                 CkRegisterChareInCharm(CkRegisterChare("null", 0, TypeChare));
1320                 CkIndex_Chare::__idx=CkRegisterChare("Chare", sizeof(Chare), TypeChare);
1321                 CkRegisterChareInCharm(CkIndex_Chare::__idx);
1322                 CkIndex_Group::__idx=CkRegisterChare("Group", sizeof(Group), TypeGroup);
1323                 CkRegisterChareInCharm(CkIndex_Group::__idx);
1324                 CkRegisterEp("null", (CkCallFnPtr)_nullFn, 0, 0, 0+CK_EP_INTRINSIC);
1325                 
1326                 /**
1327                   These _register calls are for the built-in
1328                   Charm .ci files, like arrays and load balancing.
1329                   If you add a .ci file to charm, you'll have to 
1330                   add a call to the _register routine here, or make
1331                   your library into a "-module".
1332                 */
1333                 _registerCkFutures();
1334                 _registerCkArray();
1335                 _registerLBDatabase();
1336     _registerMetaBalancer();
1337                 _registerCkCallback();
1338                 _registerwaitqd();
1339                 _registerCkCheckpoint();
1340                 _registerCkMulticast();
1341 #if CMK_MEM_CHECKPOINT
1342                 _registerCkMemCheckpoint();
1343 #endif
1344 #if CMK_CHARMPY
1345                 /**
1346                   Load balancers are currently registered in Charm++ through a C file that is generated and
1347                   and compiled by charmc when making an executable. That file contains appropriate calls to
1348                   register whatever load balancers are being linked in.
1349                   Without an executable (charm4py just uses libcharm.so), the load balancers in libcharm.so
1350                   have to somehow be registered during init.
1351                   With the planned load balancing framework, load balancer registration will hopefully go away,
1352                   at least for strategies used in central/hybrid, because they will stop being chares.
1353                 */
1354                 _registerGreedyRefineLB();
1355 #endif
1356
1357                 /**
1358                   CkRegisterMainModule is generated by the (unique)
1359                   "mainmodule" .ci file.  It will include calls to 
1360                   register all the .ci files.
1361                 */
1362 #if !CMK_CHARMPY
1363                 CkRegisterMainModule();
1364 #else
1365                 // CkRegisterMainModule doesn't exist in charm4py because there is no executable.
1366                 // Instead, we go to Python to register user chares from there
1367                 if (CkRegisterMainModuleCallback)
1368                         CkRegisterMainModuleCallback();
1369                 else
1370                         CkAbort("No callback for CkRegisterMainModule");
1371 #endif
1372
1373                 /**
1374                   _registerExternalModules is actually generated by 
1375                   charmc at link time (as "moduleinit<pid>.C").  
1376                   
1377                   This generated routine calls the _register functions
1378                   for the .ci files of libraries linked using "-module".
1379                   This funny initialization is most useful for AMPI/FEM
1380                   programs, which don't have a .ci file and hence have
1381                   no other way to control the _register process.
1382                 */
1383 #if !CMK_CHARMPY
1384                 _registerExternalModules(argv);
1385 #endif
1386         }
1387
1388         /* The following will happen on every virtual processor in BigEmulator, not just on once per real processor */
1389         if (CkMyRank() == 0) {
1390           CpdBreakPointInit();
1391         }
1392         CmiNodeAllBarrier();
1393
1394         // Execute the initcalls registered in modules
1395         _initCallTable.enumerateInitCalls();
1396
1397 #if CMK_CHARMDEBUG
1398         CpdFinishInitialization();
1399 #endif
1400         if (CkMyRank() == 0)
1401           _registerDone();
1402         CmiNodeAllBarrier();
1403
1404         CkpvAccess(_myStats) = new Stats();
1405         CkpvAccess(_msgPool) = new MsgPool();
1406
1407         CmiNodeAllBarrier();
1408
1409 #if !(__FAULT__)
1410         CmiBarrier();
1411         CmiBarrier();
1412         CmiBarrier();
1413 #endif
1414 #if CMK_SMP_TRACE_COMMTHREAD
1415         _TRACE_BEGIN_COMPUTATION();     
1416 #else
1417         if (!inCommThread) {
1418           _TRACE_BEGIN_COMPUTATION();
1419         }
1420 #endif
1421
1422 #ifdef ADAPT_SCHED_MEM
1423     if(CkMyRank()==0){
1424         memCriticalEntries = new int[numMemCriticalEntries];
1425         int memcnt=0;
1426         for(int i=0; i<_entryTable.size(); i++){
1427             if(_entryTable[i]->isMemCritical){
1428                 memCriticalEntries[memcnt++] = i;
1429             }
1430         }
1431     }
1432 #endif
1433
1434 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1435     _messageLoggingInit();
1436 #endif
1437
1438 #if CMK_FAULT_EVAC
1439 #ifndef __BIGSIM__
1440         CpvAccess(_validProcessors) = new char[CkNumPes()];
1441         for(int vProc=0;vProc<CkNumPes();vProc++){
1442                 CpvAccess(_validProcessors)[vProc]=1;
1443         }
1444         CmiAssignOnce(&_ckEvacBcastIdx, CkRegisterHandler(_ckEvacBcast));
1445         CmiAssignOnce(&_ckAckEvacIdx, CkRegisterHandler(_ckAckEvac));
1446 #endif
1447
1448         CkpvAccess(startedEvac) = 0;
1449         evacuate = 0;
1450         CcdCallOnCondition(CcdSIGUSR1,(CcdVoidFn)CkDecideEvacPe,0);
1451 #endif
1452         CpvAccess(serializer) = 0;
1453
1454 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_)) 
1455     CcdCallOnCondition(CcdSIGUSR2,(CcdVoidFn)CkMlogRestart,0);
1456 #endif
1457
1458 #if CMK_FAULT_EVAC
1459         if(_raiseEvac){
1460                 processRaiseEvacFile(_raiseEvacFile);
1461                 /*
1462                 if(CkMyPe() == 2){
1463                 //      CcdCallOnConditionKeep(CcdPERIODIC_10s,(CcdVoidFn)CkDecideEvacPe,0);
1464                         CcdCallFnAfter((CcdVoidFn)CkDecideEvacPe, 0, 10000);
1465                 }
1466                 if(CkMyPe() == 3){
1467                         CcdCallFnAfter((CcdVoidFn)CkDecideEvacPe, 0, 10000);
1468                 }*/
1469         }       
1470 #endif
1471
1472     if (CkMyRank() == 0) {
1473       TopoManager_init();
1474     }
1475     CmiNodeAllBarrier();
1476
1477     if (!_replaySystem) {
1478         CkFtFn  faultFunc_restart = CkRestartMain;
1479         if (faultFunc == NULL || faultFunc == faultFunc_restart) {         // this is not restart from memory
1480             // these two are blocking calls for non-bigsim
1481 #if ! CMK_BIGSIM_CHARM
1482           CmiInitCPUAffinity(argv);
1483           CmiInitMemAffinity(argv);
1484 #endif
1485         }
1486         CmiInitCPUTopology(argv);
1487         if (CkMyRank() == 0) {
1488           TopoManager_reset(); // initialize TopoManager singleton
1489 #if !CMK_BIGSIM_CHARM
1490           _topoTree = ST_RecursivePartition_getTreeInfo(0);
1491 #endif
1492         }
1493         CmiNodeAllBarrier(); // threads wait until _topoTree has been generated
1494 #if CMK_SHARED_VARS_POSIX_THREADS_SMP
1495         if (CmiCpuTopologyEnabled()) {
1496             int *pelist;
1497             int num;
1498             CmiGetPesOnPhysicalNode(0, &pelist, &num);
1499 #if !CMK_MULTICORE && !CMK_SMP_NO_COMMTHD
1500             // Count communication threads, if present
1501             // XXX: Assuming uniformity of node size here
1502             num += num/CmiMyNodeSize();
1503 #endif
1504             if (!_Cmi_forceSpinOnIdle && num > CmiNumCores())
1505             {
1506               if (CmiMyPe() == 0)
1507                 CmiPrintf("\nCharm++> Warning: the number of SMP threads (%d) is greater than the number of physical cores (%d), so threads will sleep while idling. Use +CmiSpinOnIdle or +CmiSleepOnIdle to control this directly.\n\n", num, CmiNumCores());
1508               CmiLock(CksvAccess(_nodeLock));
1509               if (! _Cmi_sleepOnIdle) _Cmi_sleepOnIdle = 1;
1510               CmiUnlock(CksvAccess(_nodeLock));
1511             }
1512         }
1513 #endif
1514     }
1515
1516 #if CMK_CUDA
1517     if (CmiMyRank() == 0) {
1518       initHybridAPI();
1519     }
1520     else /* CmiMyRank() != 0 */ {
1521       setHybridAPIDevice();
1522     }
1523     initEventQueues();
1524
1525     // ensure HAPI is initialized before registering callback functions
1526     if (CmiMyRank() < CmiMyNodeSize()) {
1527       CmiNodeBarrier();
1528     }
1529     hapiRegisterCallbacks();
1530 #endif
1531
1532     if(CmiMyPe() == 0) {
1533         char *topoFilename;
1534         if(CmiGetArgStringDesc(argv,"+printTopo",&topoFilename,"topo file name")) 
1535         {
1536             std::stringstream sstm;
1537             sstm << topoFilename << "." << CmiMyPartition();
1538             std::string result = sstm.str();
1539             FILE *fp;
1540             fp = fopen(result.c_str(), "w");
1541             if (fp == NULL) {
1542               CkPrintf("Error opening %s file, writing to stdout\n", topoFilename);
1543               fp = stdout;
1544             }
1545             TopoManager_printAllocation(fp);
1546             fclose(fp);
1547         }
1548     }
1549
1550 #if CMK_USE_PXSHM && ( CMK_CRAYXE || CMK_CRAYXC ) && CMK_SMP
1551       // for SMP on Cray XE6 (hopper) it seems pxshm has to be initialized
1552       // again after cpuaffinity is done
1553     if (CkMyRank() == 0) {
1554       CmiInitPxshm(argv);
1555     }
1556     CmiNodeAllBarrier();
1557 #endif
1558
1559     //CldCallback();
1560 #if CMK_BIGSIM_CHARM && CMK_CHARMDEBUG
1561       // Register the BG handler for CCS. Notice that this is put into a variable shared by
1562       // the whole real processor. This because converse needs to find it. We check that all
1563       // virtual processors register the same index for this handler.
1564     CpdBgInit();
1565 #endif
1566
1567         if (faultFunc) {
1568 #if CMK_WITH_STATS
1569                 if (CkMyPe()==0) _allStats = new Stats*[CkNumPes()];
1570 #endif
1571                 if (!inCommThread) {
1572                   CkArgMsg *msg = (CkArgMsg *)CkAllocMsg(0, sizeof(CkArgMsg), 0, GroupDepNum{});
1573                   msg->argc = CmiGetArgc(argv);
1574                   msg->argv = argv;
1575                   faultFunc(_restartDir, msg);
1576                   CkFreeMsg(msg);
1577                 }
1578         }else if(CkMyPe()==0){
1579 #if CMK_WITH_STATS
1580                 _allStats = new Stats*[CkNumPes()];
1581 #endif
1582                 size_t i, nMains=_mainTable.size();
1583
1584                 // Check CkArgMsg and warn if it contains any args starting with '+'.
1585                 // These args may be args intended for Charm++ but because of the specific
1586                 // build, were not parsed by the RTS.
1587                 int count = 0;
1588                 int argc = CmiGetArgc(argv);
1589                 for (int i = 1; i < argc; i++) {
1590                         // The +vp option for TCharm is a special case that needs to be checked
1591                         // separately, because the number passed does not need a space after
1592                         // the vp, and the option can be specified with a '+' or a '-'.
1593                         if (strncmp(argv[i],"+vp",3) == 0) {
1594                                 if (_optSet.count("+vp") == 0) {
1595                                         count++;
1596                                         CmiPrintf("WARNING: %s is a TCharm command line argument, but you have not compiled with TCharm\n", argv[i]);
1597                                 }
1598                         } else if (strncmp(argv[i],"-vp",3) == 0) {
1599                                 CmiPrintf("WARNING: %s is no longer valid because -vp has been deprecated. Please use +vp.\n", argv[i]);
1600                         } else if (argv[i][0] == '+' && _optSet.count(argv[i]) == 0) {
1601                                 count++;
1602                                 CmiPrintf("WARNING: %s is a command line argument beginning with a '+' but was not parsed by the RTS.\n", argv[i]);
1603                         } else if (argv[i][0] == '+' && _optSet.count(argv[i]) != 0) {
1604                                 fprintf(stderr,"%s is used more than once. Please remove duplicate arguments.\n", argv[i]);
1605                                 CmiAbort("Bad command-line argument\n");
1606                         }
1607                 }
1608                 if (count) {
1609                         CmiPrintf("If any of the above arguments were intended for the RTS you may need to recompile Charm++ with different options.\n");
1610                 }
1611
1612                 CmiCheckAffinity(); // check for thread oversubscription
1613
1614                 for(i=0;i<nMains;i++)  /* Create all mainchares */
1615                 {
1616                         size_t size = _chareTable[_mainTable[i]->chareIdx]->size;
1617                         void *obj = malloc(size);
1618                         _MEMCHECK(obj);
1619                         _mainTable[i]->setObj(obj);
1620                         CkpvAccess(_currentChare) = obj;
1621                         CkpvAccess(_currentChareType) = _mainTable[i]->chareIdx;
1622                         CkArgMsg *msg = (CkArgMsg *)CkAllocMsg(0, sizeof(CkArgMsg), 0, GroupDepNum{});
1623                         msg->argc = CmiGetArgc(argv);
1624                         msg->argv = argv;
1625       quietMode = 0;  // allow printing any mainchare user messages
1626                         _entryTable[_mainTable[i]->entryIdx]->call(msg, obj);
1627       if (quietModeRequested) quietMode = 1;
1628 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1629             CpvAccess(_currentObj) = (Chare *)obj;
1630 #endif
1631                 }
1632                 _mainDone = true;
1633
1634                 _STATS_RECORD_CREATE_CHARE_N(nMains);
1635                 _STATS_RECORD_PROCESS_CHARE_N(nMains);
1636
1637
1638
1639
1640                 for(i=0;i<_readonlyMsgs.size();i++) /* Send out readonly messages */
1641                 {
1642                         void *roMsg = (void *) *((char **)(_readonlyMsgs[i]->pMsg));
1643                         if(roMsg==0)
1644                                 continue;
1645                         //Pack the message and send it to all other processors
1646                         envelope *env = UsrToEnv(roMsg);
1647                         env->setSrcPe(CkMyPe());
1648                         env->setMsgtype(ROMsgMsg);
1649                         env->setRoIdx(i);
1650                         CmiSetHandler(env, _initHandlerIdx);
1651                         CkPackMessage(&env);
1652                         CmiSyncBroadcast(env->getTotalsize(), (char *)env);
1653                         CpvAccess(_qd)->create(CkNumPes()-1);
1654
1655                         //For processor 0, unpack and re-set the global
1656                         CkUnpackMessage(&env);
1657                         _processROMsgMsg(env);
1658                         _numInitMsgs++;
1659                 }
1660
1661                 //Determine the size of the RODataMessage
1662                 PUP::sizer ps;
1663                 for(i=0;i<_readonlyTable.size();i++) _readonlyTable[i]->pupData(ps);
1664
1665                 //Allocate and fill out the RODataMessage
1666                 envelope *env = _allocEnv(RODataMsg, ps.size());
1667                 PUP::toMem pp((char *)EnvToUsr(env));
1668                 for(i=0;i<_readonlyTable.size();i++) _readonlyTable[i]->pupData(pp);
1669
1670                 env->setCount(++_numInitMsgs);
1671                 env->setSrcPe(CkMyPe());
1672                 CmiSetHandler(env, _initHandlerIdx);
1673                 DEBUGF(("[%d,%.6lf] RODataMsg being sent of size %d \n",CmiMyPe(),CmiWallTimer(),env->getTotalsize()));
1674                 CmiSyncBroadcastAndFree(env->getTotalsize(), (char *)env);
1675                 CpvAccess(_qd)->create(CkNumPes()-1);
1676                 _initDone();
1677         } else {
1678                 // check for thread oversubscription
1679                 CmiCheckAffinity();
1680                 // NOTE: this assumes commthreads will not block from this point on
1681         }
1682
1683         DEBUGF(("[%d,%d%.6lf] inCommThread %d\n",CmiMyPe(),CmiMyRank(),CmiWallTimer(),inCommThread));
1684         // when I am a communication thread, I don't participate initDone.
1685         if (inCommThread) {
1686                 CkNumberHandlerEx(_bocHandlerIdx, _processHandler, CkpvAccess(_coreState));
1687                 CkNumberHandlerEx(_charmHandlerIdx, _processHandler, CkpvAccess(_coreState));
1688                 _processBufferedMsgs();
1689         }
1690
1691 #if CMK_CHARMDEBUG
1692         // Should not use CpdFreeze inside a thread (since this processor is really a user-level thread)
1693        if (CpvAccess(cpdSuspendStartup))
1694        { 
1695           //CmiPrintf("In Parallel Debugging mode .....\n");
1696           CpdFreeze();
1697        }
1698 #endif
1699
1700
1701 #if __FAULT__
1702         if(killFlag){                                                  
1703                 readKillFile();                                        
1704         }
1705 #endif
1706
1707 }
1708
1709 int charm_main(int argc, char **argv)
1710 {
1711   int stack_top=0;
1712   memory_stack_top = &stack_top;
1713
1714   ConverseInit(argc, argv, (CmiStartFn) _initCharm, 0, 0);
1715
1716   return 0;
1717 }
1718
1719 void FTN_NAME(CHARM_MAIN_FORTRAN_WRAPPER, charm_main_fortran_wrapper)(int *argc, char **argv)
1720 {
1721   charm_main(*argc, argv);
1722 }
1723
1724 // user callable function to register an exit function, this function
1725 // will perform task of collecting of info from all pes to pe0, and call
1726 // CkContinueExit() on pe0 again to recursively traverse the registered exitFn.
1727 // see trace-summary for an example.
1728 void registerExitFn(CkExitFn fn)
1729 {
1730 #if CMK_SHRINK_EXPAND
1731   CkAbort("registerExitFn is called when shrink-expand is enabled!");
1732 #else
1733   _CkExitFnVec.enq(fn);
1734 #endif
1735 }
1736
1737 /*@}*/