019b1f6e04a5e15316acbaf844df74eac1fe12fb
[charm.git] / src / util / RTH.h
1 /* 
2 RTH runtime: Return-based "Threads" package,
3 for multiple flows-of-control *without* any 
4 crazy threading work.
5
6 I'll probably regret this, but if I make this a 
7 C++-based API I can make local variable access much easier.
8
9 Orion Sky Lawlor, olawlor@acm.org, 2003/07/23
10 */
11 #ifndef __CHARM_RTH_H
12 #define __CHARM_RTH_H
13
14 #include "pup.h"
15 #if CMK_STL_DONT_USE_DOT_H
16 #include <new> /* for in-place operator new */
17 #else
18 #include <new.h>   // for in-place new operator
19 #endif
20
21 /** All the local variables for RTH routines
22    are stored in subclasses of this type.  Keeping
23    the types allows us to have a PUP routine and 
24    an actual destructor. 
25 */
26 class RTH_Locals {
27 public:
28         virtual ~RTH_Locals();
29         virtual void pup(PUP::er &p);
30 };
31
32
33 /** An opaque handle to the RTH runtime data,
34   which includes the call stack and local variables.
35  */
36 class RTH_Runtime;
37
38 /** An RTH user subroutine, declared using the
39 RTH_Routine_* macros.
40 */
41 typedef void (*RTH_Routine)(RTH_Runtime *runtime,
42         void *object,RTH_Locals *locals,int pc);
43
44
45 /************************************************
46 RTH library interface: used for writing libraries
47 that call RTH routines and/or are called by RTH routines.
48 */
49
50 /** Create a new RTH runtime that will run this function
51     on its first "resume" call.
52 */
53 RTH_Runtime *RTH_Runtime_create(RTH_Routine fn,int localsSize,void *obj);
54
55 /** Pup this RTH_Runtime.  This routine can be called on 
56 an uninitialized RTH_Runtime if the PUP::er is unpacking.
57 This does *not* free the RTH_Runtime, so call RTH_Runtime_free
58 in your destructor as usual.
59 */
60 RTH_Runtime *RTH_Runtime_pup(RTH_Runtime *runtime,PUP::er &p,void *obj);
61
62 /** "Block" this RTH thread.  Saves the currently
63   running function and nextPC for later "resume" call.
64   Unlike a real thread, this routine returns, and you're
65   expected to exit the RTH_fn immediately.
66   Also see the RTH_Suspend macro, which can be used
67   directly from inside a user RTH_Routine.
68 */
69 void RTH_Runtime_suspend(RTH_Runtime *runtime,int nextPC);
70
71 /** Resume the blocked RTH thread immediately.
72    This call will not return until the thread blocks again.  
73 */
74 void RTH_Runtime_resume(RTH_Runtime *runtime);
75
76 /** Call this RTH subroutine inline. Returns 0 if the
77    current thread should block. (i.e., the call "failed") */
78 int RTH_Runtime_call(RTH_Runtime *runtime,RTH_Routine fn,int localsSize,int nextPC);
79
80 /** Called at the end of an RTH routine.
81     Allows the next routine to be started.
82  */
83 void RTH_Runtime_done(RTH_Runtime *runtime);
84
85 /** Dispose of the RTH runtime. Does not free the user object. */
86 void RTH_Runtime_destroy(RTH_Runtime *runtime);
87
88
89 /************************************************
90 RTH "translator":
91   Instruments user's source code with calls to
92   the RTH runtime.
93 */
94
95 /** Begins the definition of an RTH user routine.
96 You define a routine foo for a class bar using 
97 these macros like:
98    RTH_Routine_locals(foo,bar)
99      int i, j;
100      double z;
101    RTH_Routine_code(foo,bar)
102      z=0.0; 
103      for (i=0;i<3;i++) z+=1.0;
104    RTH_Routine_end(foo,bar)
105
106 IMPLEMENTATION: Creates a small wrapper object to hold
107   the routine and the routine's local variables.
108 */
109 #define RTH_Routine_locals(object,name) \
110 class RTH_Routine_##object##_##name : public RTH_Locals { \
111   typedef RTH_Locals super; \
112   typedef RTH_Routine_##object##_##name locals_t; \
113 public:  /* user's local variables go here */
114
115 /** After listing any local variables (and a pup routine),
116     use this macro to start defining the body code of your
117     subroutine. 
118 IMPLEMENTATION: Opens the actual routine, and adds a 
119  "switch(pc)" statement.
120 */
121 #define RTH_Routine_code(object,name) \
122   inline void name(RTH_Runtime *RTH_impl_runtime,\
123               object *c,int RTH_impl_pc) { \
124     switch(RTH_impl_pc) { \
125     case 0: /* Program counter at routine start (PC_START): */ \
126       new ((void *)this) locals_t; /* Call our locals' constructor in-place */
127
128 /** Ends the definition of an RTH routine. 
129  IMPLEMENTATION: Ends the switch statement started by 
130  RTH_Routine_code, and adds the callfn static function.
131 */
132 #define RTH_Routine_end(object,name) \
133     /* end-of-routine: check if we need to resume our calling routine */ \
134       RTH_Runtime_done(RTH_impl_runtime); \
135       return;  \
136     default: \
137       printf("Bad pc %d\n",RTH_impl_pc); exit(1);/* unrecognized program counter: */ \
138     }; /* Switch end */ \
139   } /* User routine end */ \
140 \
141   /* C-style call-function for user routine-- applies appropriate typecasts. */ \
142   static void RTH_Call_routine(RTH_Runtime *runtime,\
143               void *c,RTH_Locals *locals,int pc) \
144   {\
145     ((locals_t *)locals)->name(runtime,(object *)c,pc);\
146   }\
147 \
148 }; /* locals_t class end */ 
149
150 /** Block the currently running RTH thread.  Can only
151   be called from inside an RTH_Routine.
152 IMPLEMENTATION: Uses the bizarre method of stashing the 
153   program counter for the next statement and returning.
154   On the next resume, the statements following the suspend
155   will be executed.
156  */
157 #define RTH_Suspend() do {\
158         RTH_Runtime_suspend(RTH_impl_runtime,__LINE__);\
159         return;\
160 case __LINE__: ; \
161 } while(0)
162
163 /** Call this RTH subroutine (blocking).  Can only be called
164     from inside an RTH_Routine.
165     Store any arguments for the routine inside your object. 
166 FIXME: add real argument-passing and return types, based 
167   on pup (somehow).
168 */
169 #define RTH_Call(object,name) do{ \
170      if (!RTH_Runtime_call(RTH_impl_runtime,RTH_Routine_lookup(object,name),__LINE__)) \
171         return;\
172 case __LINE__: ; \
173 } while(0)
174
175 /** Given a routine name, convert to a call-function and locals size.
176   Can be called from inside or outside an RTH_Routine.
177 */
178 #define RTH_Routine_lookup(object,name) \
179    RTH_Routine_##object##_##name::RTH_Call_routine, sizeof(RTH_Routine_##object##_##name)
180
181 #endif
182