183bdbbe41ccd98f0509580830ae6c5a37fac761
[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 //User's readonly global variables, set exactly once after initialization
21 class TCharmReadonlys {
22         //There's only one (shared) list per node, so no CpvAccess here
23         static CkVec<TCpupReadonlyGlobal> entries;
24  public:
25         static void add(TCpupReadonlyGlobal fn);
26         //Pups all registered readonlys 
27         static void pupAllReadonlys(PUP::er &p);
28
29         //Used by parameter marshalling:
30         void pup(PUP::er &p);
31 };
32 PUPmarshall(TCharmReadonlys);
33
34 class TCharmTraceLibList;
35
36 #include "tcharm.decl.h"
37
38 class TCharmReadonlyGroup : public Group {
39  public:
40         //Just unpacking the parameter is enough:
41         TCharmReadonlyGroup(const TCharmReadonlys &r) { /*nothing needed*/ }
42 };
43
44 class TCharm;
45
46 class TCharmInitMsg : public CMessage_TCharmInitMsg {
47  public:
48         //Function to start thread with:
49         CthVoidFn threadFn;
50         //Initial stack size, in bytes:
51         int stackSize;
52         //Array size (number of elements)
53         int numElements;
54         //Data to pass to thread:
55         char *data;
56
57         TCharmInitMsg(CthVoidFn threadFn_,int stackSize_)
58                 :threadFn(threadFn_), stackSize(stackSize_) {}
59 };
60
61 //Current computation location
62 typedef enum {inNodeSetup,inInit,inDriver,inFramework,inPup} inState;
63
64 //Thread-local variables:
65 CtvExtern(TCharm *,_curTCharm);
66 CkpvExtern(inState,_stateTCharm);
67
68 CDECL {typedef void (*TCpupUserDataC)(pup_er p,void *data);};
69 FDECL {typedef void (*TCpupUserDataF)(pup_er p,void *data);};
70
71 class TCharm: public CBase_TCharm
72 {
73  public:
74
75         //User's heap-allocated/global data:
76         class UserData {
77                 void *data; //user data pointer
78                 bool isC;
79                 TCpupUserDataC cfn;
80                 TCpupUserDataF ffn;
81         public:
82                 UserData(int i=0) {data=NULL; cfn=NULL; ffn=NULL;}
83                 UserData(TCpupUserDataC cfn_,void *data_)
84                         {cfn=cfn_; data=data_; isC=true;}
85                 class isFortran{};
86                 UserData(TCpupUserDataF ffn_,void *data_,isFortran tag)
87                         {ffn=ffn_; data=data_; isC=false;}
88                 inline void *getData(void) const {return data;}
89                 void pup(PUP::er &p);
90                 friend inline void operator|(PUP::er &p,UserData &d) {d.pup(p);}
91         };
92         //New interface for user data:
93         CkVec<UserData> sud;
94         
95         //Tiny semaphore-like pointer producer/consumer
96         class TCharmSemaphore {
97         public:
98                 int id; //User-defined identifier
99                 void *data; //User-defined data
100                 CthThread thread; //Waiting thread, or 0 if none
101                 
102                 TCharmSemaphore() { id=-1; data=NULL; thread=NULL; }
103                 TCharmSemaphore(int id_) { id=id_; data=NULL; thread=NULL; }
104         };
105         /// Short, unordered list of waiting semaphores.
106         CkVec<TCharmSemaphore> sema;
107         TCharmSemaphore *findSema(int id);
108         void freeSema(TCharmSemaphore *);
109         
110         /// Store data at the semaphore "id".
111         ///  The put can come before or after the get.
112         void semaPut(int id,void *data);
113         /// Retreive data from the semaphore "id".
114         ///  Blocks if the data is not immediately available.
115         ///  Consumes the data, so another put will be required for the next get.
116         void *semaGet(int id);
117
118         //One-time initialization
119         static void nodeInit(void);
120         static void procInit(void);
121  private:
122         //Informational data about the current thread:
123         class ThreadInfo {
124         public:
125                 CProxy_TCharm tProxy; //Our proxy
126                 int thisElement; //Index of current element
127                 int numElements; //Number of array elements
128         };
129
130         TCharmInitMsg *initMsg; //Thread initialization data
131         CthThread tid; //Our migratable thread
132         friend class TCharmAPIRoutine; //So he can get to heapBlocks:
133         CmiIsomallocBlockList *heapBlocks; //Migratable heap data
134
135         bool isStopped, resumeAfterMigration;
136         ThreadInfo threadInfo;
137         double timeOffset; //Value to add to CkWallTimer to get my clock
138
139         //Old interface for user data:
140         enum {maxUserData=16};
141         int nUd;
142         UserData ud[maxUserData];
143
144         void ResumeFromSync(void);
145
146 #ifdef CMK_OPTIMIZE
147         static inline void check(void) {}
148 #else
149         static void check(void);
150 #endif
151
152  public:
153         TCharm(TCharmInitMsg *initMsg);
154         TCharm(CkMigrateMessage *);
155         ~TCharm();
156         
157         virtual void ckJustMigrated(void);
158         void migrateDelayed(int destPE);
159
160         void clear();
161
162         //Pup routine packs the user data and migrates the thread
163         virtual void pup(PUP::er &p);
164
165         //Start running the thread for the first time
166         void run(void);
167
168         inline double getTimeOffset(void) const { return timeOffset; }
169
170 //Client-callable routines:
171         //One client is ready to run
172         void ready(void);
173
174         //Sleep till entire array is here
175         void barrier(void);
176         
177         //Block, migrate to destPE, and resume
178         void migrateTo(int destPE);
179
180         //Thread finished running
181         void done(void);
182
183         //Register user data to be packed with the thread
184         int add(const UserData &d);
185         void *lookupUserData(int ud);
186         
187         inline static TCharm *get(void) {check(); return CtvAccess(_curTCharm);}
188         inline static inState getState(void) {return CkpvAccess(_stateTCharm);}
189         inline static void setState(inState to) {CkpvAccess(_stateTCharm)=to;}
190         inline CthThread getThread(void) {return tid;}
191         inline const CProxy_TCharm &getProxy(void) const {return threadInfo.tProxy;}
192         inline int getElement(void) const {return threadInfo.thisElement;}
193         inline int getNumElements(void) const {return threadInfo.numElements;}
194
195         //Start/stop load balancer measurements
196         inline void stopTiming(void) {ckStopTiming();}
197         inline void startTiming(void) {ckStartTiming();}
198
199         //Block our thread, run the scheduler, and come back
200         inline void schedule(void) {
201                 stopTiming();
202                 CthYield();
203                 startTiming();
204         }
205
206         //As above, but start/stop the thread itself, too.
207         void stop(void); //Blocks; will not return until "start" called.
208         void start(void);
209         //Aliases:
210         inline void suspend(void) {stop();}
211         inline void resume(void) {start();}
212
213         //Go to sync, block, possibly migrate, and then resume
214         void migrate(void);
215
216         //Make subsequent malloc's go into our list:
217         inline void activateHeap(void) {
218                 CmiIsomallocBlockListActivate(heapBlocks);
219         }
220         //Disable migratable memory
221         inline void deactivateHeap(void) {
222                 CmiIsomallocBlockListActivate(NULL);
223         }
224 };
225
226
227
228 //TCharm internal class: Controls array startup, ready, run and shutdown
229 class TCharmCoordinator {
230         static int nArrays; //Total number of running thread arrays
231         static TCharmCoordinator *head; //List of coordinators
232
233         TCharmCoordinator *next; //Next coordinator in list
234         CProxy_TCharm threads;//The threads I coordinate
235         int nThreads;//Number of threads (array elements)
236         int nClients; //Number of bound client arrays
237         int nReady; //Number of ready clients
238 public:
239         TCharmCoordinator(CkArrayID threads,int nThreads);
240         ~TCharmCoordinator();
241         void addClient(const CkArrayID &client);
242         void clientReady(void);
243         void clientBarrier(void);
244         void clientDone(void);
245         
246         static int getTotal(void) {
247                 return nArrays;
248         }
249 };
250
251 //Controls initial setup (main::main & init routines)
252 class TCharmSetupCookie {
253         enum {correctMagic=0x5432abcd};
254         int magic; //To make sure this is actually a cookie
255         
256         int stackSize; //Thread stack size, in bytes
257         char **argv; //Command-line arguments
258         
259         CkArrayID tc; //Handle to last-created TCharm array
260         int numElements; //Number of elements in last-created TCharm
261         TCharmCoordinator *coord; 
262
263         //Points to the active cookie
264         static TCharmSetupCookie *theCookie;
265         friend class TCharmMain;
266  public:
267         TCharmSetupCookie(char **argv_);
268         
269 #ifdef CMK_OPTIMIZE //Skip check, for speed
270         inline TCharmSetupCookie &check(void) {return *this;}
271 #else
272         TCharmSetupCookie &check(void);
273 #endif
274         void setStackSize(int sz) {stackSize=sz;}
275         int getStackSize(void) const {return stackSize;}
276         char **getArgv(void) {return argv;}
277         
278         bool hasThreads(void) const {return 0!=coord;}
279         const CkArrayID &getThreads(void) const {return tc;}
280         TCharmCoordinator *getCoordinator(void) {return coord;}
281         int getNumElements(void) const {return numElements;}
282
283         void addClient(const CkArrayID &client) {coord->addClient(client);}
284         
285         void setThreads(const CkArrayID &aid,int nel);
286
287         static TCharmSetupCookie *get(void) {return theCookie;}
288 };
289
290 //Created in all API routines: disables/enables migratable malloc
291 class TCharmAPIRoutine {
292  public:
293         TCharmAPIRoutine() { //Entering Charm++ from user code
294                 //Disable migratable memory allocation while in Charm++:
295                 CmiIsomallocBlockListActivate(NULL);
296         }
297         ~TCharmAPIRoutine() { //Returning to user code from Charm++:
298                 //Reenable migratable memory allocation
299                 TCharm *tc=CtvAccess(_curTCharm);
300                 if (tc!=NULL) tc->activateHeap();
301         }
302 };
303
304
305 #define TCHARMAPI(routineName) TCHARM_API_TRACE(routineName,"tcharm");
306
307 //Node setup callbacks: called at startup on each node
308 FDECL void FTN_NAME(TCHARM_USER_NODE_SETUP,tcharm_user_node_setup)(void);
309 FDECL void FTN_NAME(TCHARM_USER_SETUP,tcharm_user_setup)(void);
310
311
312 #endif
313
314