Drastic simplification of TCharm's startup sequence:
[charm.git] / src / libs / ck-libs / tcharm / tcharm_impl.h
1 /*
2 Threaded Charm++ "Framework Framework" Implementation header
3
4 Implements an array of migratable threads.
5 Provides utility routines for registering user
6 data, stopping, starting, and migrating threads.
7
8 Orion Sky Lawlor, olawlor@acm.org, 11/19/2001
9 */
10 #ifndef __CHARM_TCHARM_IMPL_H
11 #define __CHARM_TCHARM_IMPL_H
12
13 #include "pup.h"
14 #include "pup_c.h"
15 #include "charm-api.h"
16 #include "tcharmc.h"
17 #include "cklists.h"
18 #include "memory-isomalloc.h"
19
20 PUPbytes(TCpupReadonlyGlobal);
21
22 //User's readonly global variables, set exactly once after initialization
23 class TCharmReadonlys {
24         CkVec<TCpupReadonlyGlobal> entries;
25  public:
26         void add(TCpupReadonlyGlobal fn);
27         void add(const TCharmReadonlys &r);
28         
29         inline int size(void) const {return entries.size();}
30         
31         //Pup the readonly *functions* (for shipping)
32         void pup(PUP::er &p);
33
34         //Pups the readonly *data*
35         void pupData(PUP::er &p);
36         
37         //Pups all registered readonlys 
38         static void pupAll(PUP::er &p);
39 };
40 PUPmarshall(TCharmReadonlys);
41
42 class TCharmTraceLibList;
43
44 #include "tcharm.decl.h"
45
46 class TCharm;
47
48 // This little class holds values between a call to TCHARM_Set_* 
49 //   and the subsequent TCHARM_Create_*.  It should be moved
50 //   into a parameter to TCHARM_Create.
51 class TCHARM_Thread_options {
52 public:
53         int stackSize; /* size of thread execution stack, in bytes */
54         int exitWhenDone; /* flag: call CkExit when thread is finished. */
55         // Fill out the default thread options:
56         TCHARM_Thread_options(int doDefault);
57         TCHARM_Thread_options() {}
58 };
59
60 class TCharmInitMsg : public CMessage_TCharmInitMsg {
61  public:
62         //Function to start thread with:
63         CthVoidFn threadFn;
64         //Initial thread parameters:
65         TCHARM_Thread_options opts;
66         //Array size (number of elements)
67         int numElements;
68         //Data to pass to thread:
69         char *data;
70
71         TCharmInitMsg(CthVoidFn threadFn_,const TCHARM_Thread_options &opts_)
72                 :threadFn(threadFn_), opts(opts_) {}
73 };
74
75 //Current computation location
76 typedef enum {inNodeSetup,inInit,inDriver,inFramework,inPup} inState;
77
78 //Thread-local variables:
79 CtvExtern(TCharm *,_curTCharm);
80 CkpvExtern(inState,_stateTCharm);
81
82 CDECL {typedef void (*TCpupUserDataC)(pup_er p,void *data);};
83 FDECL {typedef void (*TCpupUserDataF)(pup_er p,void *data);};
84
85 class TCharm: public CBase_TCharm
86 {
87  public:
88
89 //User's heap-allocated/global data:
90         class UserData {
91                 void *data; //user data pointer
92                 bool isC;
93                 TCpupUserDataC cfn;
94                 TCpupUserDataF ffn;
95         public:
96                 UserData(int i=0) {data=NULL; cfn=NULL; ffn=NULL;}
97                 UserData(TCpupUserDataC cfn_,void *data_)
98                         {cfn=cfn_; data=data_; isC=true;}
99                 class isFortran{};
100                 UserData(TCpupUserDataF ffn_,void *data_,isFortran tag)
101                         {ffn=ffn_; data=data_; isC=false;}
102                 inline void *getData(void) const {return data;}
103                 void pup(PUP::er &p);
104                 friend inline void operator|(PUP::er &p,UserData &d) {d.pup(p);}
105         };
106         //New interface for user data:
107         CkVec<UserData> sud;
108         
109 //Tiny semaphore-like pointer producer/consumer
110         class TCharmSemaphore {
111         public:
112                 int id; //User-defined identifier
113                 void *data; //User-defined data
114                 CthThread thread; //Waiting thread, or 0 if none
115                 
116                 TCharmSemaphore() { id=-1; data=NULL; thread=NULL; }
117                 TCharmSemaphore(int id_) { id=id_; data=NULL; thread=NULL; }
118         };
119         /// Short, unordered list of waiting semaphores.
120         CkVec<TCharmSemaphore> sema;
121         TCharmSemaphore *findSema(int id);
122         TCharmSemaphore *getSema(int id);
123         void freeSema(TCharmSemaphore *);
124         
125         /// Store data at the semaphore "id".
126         ///  The put can come before or after the get.
127         void semaPut(int id,void *data);
128
129         /// Retreive data from the semaphore "id", returning NULL if not there.
130         void *semaPeek(int id);
131         
132         /// Retreive data from the semaphore "id".
133         ///  Blocks if the data is not immediately available.
134         void *semaGets(int id);
135         
136         /// Retreive data from the semaphore "id".
137         ///  Blocks if the data is not immediately available.
138         ///  Consumes the data, so another put will be required for the next get.
139         void *semaGet(int id);
140
141 //One-time initialization
142         static void nodeInit(void);
143         static void procInit(void);
144  private:
145         //Informational data about the current thread:
146         class ThreadInfo {
147         public:
148                 CProxy_TCharm tProxy; //Our proxy
149                 int thisElement; //Index of current element
150                 int numElements; //Number of array elements
151         };
152
153         TCharmInitMsg *initMsg; //Thread initialization data
154         CthThread tid; //Our migratable thread
155         friend class TCharmAPIRoutine; //So he can get to heapBlocks:
156         CmiIsomallocBlockList *heapBlocks; //Migratable heap data
157
158         bool isStopped, resumeAfterMigration, exitWhenDone;
159         ThreadInfo threadInfo;
160         double timeOffset; //Value to add to CkWallTimer to get my clock
161
162         //Old interface for user data:
163         enum {maxUserData=16};
164         int nUd;
165         UserData ud[maxUserData];
166
167         void ResumeFromSync(void);
168
169 #ifdef CMK_OPTIMIZE
170         static inline void check(void) {}
171 #else
172         static void check(void);
173 #endif
174
175  public:
176         TCharm(TCharmInitMsg *initMsg);
177         TCharm(CkMigrateMessage *);
178         ~TCharm();
179         
180         virtual void ckJustMigrated(void);
181         void migrateDelayed(int destPE);
182         void atBarrier(CkReductionMsg *);
183         void atExit(CkReductionMsg *);
184
185         void clear();
186
187         //Pup routine packs the user data and migrates the thread
188         virtual void pup(PUP::er &p);
189
190         //Start running the thread for the first time
191         void run(void);
192
193         inline double getTimeOffset(void) const { return timeOffset; }
194
195 //Client-callable routines:
196         //Sleep till entire array is here
197         void barrier(void);
198         
199         //Block, migrate to destPE, and resume
200         void migrateTo(int destPE);
201
202         //Thread finished running
203         void done(void);
204
205         //Register user data to be packed with the thread
206         int add(const UserData &d);
207         void *lookupUserData(int ud);
208         
209         inline static TCharm *get(void) {check(); return CtvAccess(_curTCharm);}
210         inline static inState getState(void) {return CkpvAccess(_stateTCharm);}
211         inline static void setState(inState to) {CkpvAccess(_stateTCharm)=to;}
212         inline CthThread getThread(void) {return tid;}
213         inline const CProxy_TCharm &getProxy(void) const {return threadInfo.tProxy;}
214         inline int getElement(void) const {return threadInfo.thisElement;}
215         inline int getNumElements(void) const {return threadInfo.numElements;}
216
217         //Start/stop load balancer measurements
218         inline void stopTiming(void) {ckStopTiming();}
219         inline void startTiming(void) {ckStartTiming();}
220
221         //Block our thread, run the scheduler, and come back
222         inline void schedule(void) {
223                 stopTiming();
224                 CthYield();
225                 startTiming();
226         }
227
228         //As above, but start/stop the thread itself, too.
229         void stop(void); //Blocks; will not return until "start" called.
230         void start(void);
231         //Aliases:
232         inline void suspend(void) {stop();}
233         inline void resume(void) {start();}
234
235         //Go to sync, block, possibly migrate, and then resume
236         void migrate(void);
237
238         //Make subsequent malloc's go into our list:
239         inline void activateHeap(void) {
240                 CmiIsomallocBlockListActivate(heapBlocks);
241         }
242         //Disable migratable memory
243         inline void deactivateHeap(void) {
244                 CmiIsomallocBlockListActivate(NULL);
245         }
246 };
247
248
249 //Created in all API routines: disables/enables migratable malloc
250 class TCharmAPIRoutine {
251  public:
252         TCharmAPIRoutine() { //Entering Charm++ from user code
253                 //Disable migratable memory allocation while in Charm++:
254                 CmiIsomallocBlockListActivate(NULL);
255         }
256         ~TCharmAPIRoutine() { //Returning to user code from Charm++:
257                 //Reenable migratable memory allocation
258                 TCharm *tc=CtvAccess(_curTCharm);
259                 if (tc!=NULL) tc->activateHeap();
260         }
261 };
262
263
264 #define TCHARMAPI(routineName) TCHARM_API_TRACE(routineName,"tcharm");
265
266 //Node setup callbacks: called at startup on each node
267 FDECL void FTN_NAME(TCHARM_USER_NODE_SETUP,tcharm_user_node_setup)(void);
268 FDECL void FTN_NAME(TCHARM_USER_SETUP,tcharm_user_setup)(void);
269
270
271 #endif
272
273