Avoid building user-driven-interop example on non-LRTS layers
[charm.git] / src / ck-core / mpi-interoperate.C
blob25cfbac703e929a6b39a4460ec55964811bd4687
1 #include "mpi-interoperate.h"
2 //#define PERFORM_DEBUG 1
3 #if PERFORM_DEBUG
4 #define DEBUG(a) a
5 #else
6 #define DEBUG(a) 
7 #endif
9 int _libExitHandlerIdx;
10 static bool _libExitStarted = false;
12 extern std::atomic<int> ckExitComplete;
13 extern std::atomic<int> _cleanUp;
15 #if CMK_CONVERSE_MPI
16 extern MPI_Comm charmComm;
17 #else
18 typedef int MPI_Comm;
19 #endif
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();
34 extern "C"
35 void StartCharmScheduler() {
36   CmiNodeAllBarrier();
37   StartInteropScheduler();
40 extern "C"
41 void StopCharmScheduler() {
42   StopInteropScheduler();
45 // triger LibExit on PE 0,
46 extern "C"
47 void LibCkExit(void)
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()) {
60     case StartExitMsg:
61       DEBUG(printf("[%d] Exit started for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
62       CkAssert(CkMyPe()==0);
63     case ExitMsg:
64       CkAssert(CkMyPe()==0);
65       if(_libExitStarted) {
66         DEBUG(printf("[%d] Duplicate Exit started for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
67         CmiFree(env);
68         return;
69       }
70       _libExitStarted = true;
71       env->setMsgtype(ReqStatMsg);
72       env->setSrcPe(CkMyPe());
73       // if exit in ring, instead of broadcasting, send in ring
74       if (_ringexit){
75         const int stride = CkNumPes()/_ringtoken;
76         int pe = 0;
77         while (pe<CkNumPes()) {
78           CmiSyncSend(pe, env->getTotalsize(), (char *)env);
79           pe += stride;
80         }
81         CmiFree(env);
82       }else{
83         DEBUG(printf("[%d] Broadcast Exit for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
84         CmiSyncBroadcastAllAndFree(env->getTotalsize(), (char *)env);
85       }
86       break;
87     case ReqStatMsg:
88       DEBUG(printf("[%d] Receive Exit for %d PE %d nodes\n",CmiMyPe(),CmiNumPes(),CmiNumNodes());)
89       if (_ringexit) {
90         int stride = CkNumPes()/_ringtoken;
91         int pe = CkMyPe()+1;
92         if (pe < CkNumPes() && pe % stride != 0)
93           CmiSyncSendAndFree(pe, env->getTotalsize(), (char *)env);
94         else
95           CmiFree(env);
96       }
97       else
98         CmiFree(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());)
101 #if !CMK_SMP
102       LrtsDrainResources();
103 #endif
104       _libExitStarted = false;
105       StopCharmScheduler();
106       break;
107     default:
108       CmiAbort("Internal Error(_libExitHandler): Unknown-msg-type. Contact Developers.\n");
109   }
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.
115 extern "C"
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.");
119 #endif
121   userDrivenMode = 1;
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.
132 extern "C"
133 void CharmFinishInit() {
134   if (CkMyPe() == 0) {
135     _sendReadonlies();
136   }
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.
143 extern "C"
144 void CharmInit(int argc, char** argv) {
145   CharmBeginInit(argc, argv);
146   CharmFinishInit();
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.
153 extern "C"
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?");
159   }
160 #endif
162 #if CMK_CONVERSE_MPI
163   if(!userDrivenMode) {
164     MPI_Comm_dup(userComm, &charmComm);
165   }
166 #endif
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
177 // continue.
178 #undef CkExit
179 #define CkExit CKEXIT_0 // CKEXIT_0 and other CkExit macros defined in charm.h
180 extern "C"
181 void CharmLibExit() {
182   _cleanUp = 1;
183   CmiNodeAllBarrier();
184   if(CkMyPe() == 0) {
185     CkExit();
186   }
187   if (CmiMyRank() == CmiMyNodeSize()) {
188     while (ckExitComplete.load() == 0) { CommunicationServerThread(5); }
189   } else { 
190     CsdScheduler(-1);
191     CmiNodeAllBarrier();
192   }