1 #include "mpi-interoperate.h"
2 //#define PERFORM_DEBUG 1
9 int _libExitHandlerIdx;
10 static bool _libExitStarted = false;
12 extern std::atomic<int> ckExitComplete;
13 extern std::atomic<int> _cleanUp;
16 extern MPI_Comm charmComm;
21 extern void LrtsDrainResources(); /* used when exit */
23 extern bool _ringexit; // for charm exit
24 extern int _ringtoken;
25 extern void _initCharm(int unused_argc, char **argv);
26 extern void _sendReadonlies();
27 extern "C" void CommunicationServerThread(int sleepTime);
28 extern int CharmLibInterOperate;
29 extern int userDrivenMode;
31 extern "C" void StartInteropScheduler();
32 extern "C" void StopInteropScheduler();
35 void StartCharmScheduler() {
37 StartInteropScheduler();
41 void StopCharmScheduler() {
42 StopInteropScheduler();
45 // triger LibExit on PE 0,
49 // always send to PE 0
50 envelope *env = _allocEnv(StartExitMsg);
51 env->setSrcPe(CkMyPe());
52 CmiSetHandler(env, _libExitHandlerIdx);
53 CmiSyncSendAndFree(0, env->getTotalsize(), (char *)env);
56 void _libExitHandler(envelope *env)
58 DEBUG(printf("[%d] Exit started for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
59 switch(env->getMsgtype()) {
61 DEBUG(printf("[%d] Exit started for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
62 CkAssert(CkMyPe()==0);
64 CkAssert(CkMyPe()==0);
66 DEBUG(printf("[%d] Duplicate Exit started for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
70 _libExitStarted = true;
71 env->setMsgtype(ReqStatMsg);
72 env->setSrcPe(CkMyPe());
73 // if exit in ring, instead of broadcasting, send in ring
75 const int stride = CkNumPes()/_ringtoken;
77 while (pe<CkNumPes()) {
78 CmiSyncSend(pe, env->getTotalsize(), (char *)env);
83 DEBUG(printf("[%d] Broadcast Exit for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
84 CmiSyncBroadcastAllAndFree(env->getTotalsize(), (char *)env);
88 DEBUG(printf("[%d] Receive Exit for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
90 int stride = CkNumPes()/_ringtoken;
92 if (pe < CkNumPes() && pe % stride != 0)
93 CmiSyncSendAndFree(pe, env->getTotalsize(), (char *)env);
99 //everyone exits here - there may be issues with leftover messages in the queue
100 DEBUG(printf("[%d/%d] Am done here\n",CmiMyRank(),CmiMyPe());)
102 LrtsDrainResources();
104 _libExitStarted = false;
105 StopCharmScheduler();
108 CmiAbort("Internal Error(_libExitHandler): Unknown-msg-type. Contact Developers.\n");
112 // CharmBeginInit calls sets interop flags then calls ConverseInit. This
113 // initializes the runtime, but does not start the scheduler or send readonlies.
114 // It returns control the main after main chares have been created.
116 void CharmBeginInit(int argc, char** argv) {
117 #if !defined CMK_USE_LRTS || !CMK_USE_LRTS
118 CmiAbort("Interop is not supported in non-LRTS machine layers.");
122 CharmLibInterOperate = true;
123 ConverseInit(argc, argv, (CmiStartFn)_initCharm, 1, 0);
126 // CharmFinishInit broadcasts out readonly data then begins the interop
127 // scheduler. The split initialization allows interop apps to use readonlies
128 // without mainchares. They call CharmBeginInit(...), then set readonly values
129 // and perform other init such as group creation. They they call CharmFinishInit
130 // to bcast readonlies and group creation messages. Control returns to caller
131 // after all readonlies are received and all groups are created.
133 void CharmFinishInit() {
137 StartInteropScheduler();
140 // CharmInit is the simplified initialization function for apps which have
141 // mainchares or don't use readonlies and don't require groups to be created
142 // before regular execution. It calls both CharmStartInit and CharmFinishInit.
144 void CharmInit(int argc, char** argv) {
145 CharmBeginInit(argc, argv);
149 // CharmLibInit is specifically for MPI interop, where MPI applications want
150 // to call Charm as a library. It does full initialization and starts the
151 // scheduler. If Charm is built on MPI, multiple Charm instances can be created
152 // using different communicators.
154 void CharmLibInit(MPI_Comm userComm, int argc, char **argv) {
156 #if CMK_USE_LRTS && !CMK_HAS_INTEROP
157 if(!userDrivenMode) {
158 CmiAbort("mpi-interoperate not supported in this machine layer; did you mean to use CharmInit?");
163 if(!userDrivenMode) {
164 MPI_Comm_dup(userComm, &charmComm);
168 CharmLibInterOperate = true;
169 ConverseInit(argc, argv, (CmiStartFn)_initCharm, 1, 0);
170 StartInteropScheduler();
173 // CharmLibExit is called for both forms of interop when the application is
174 // done with Charm. In userDrivenMode, this does a full exit and kills the
175 // application, just like CkExit(). In MPI interop, it just kills the Charm
176 // instance, but allows the outside application and other Charm instances to
179 #define CkExit CKEXIT_0 // CKEXIT_0 and other CkExit macros defined in charm.h
181 void CharmLibExit() {
187 if (CmiMyRank() == CmiMyNodeSize()) {
188 while (ckExitComplete.load() == 0) { CommunicationServerThread(5); }