ebc2e7301d9954bd2e33ec02d503730e1946651c
[ghc-hetmet.git] / ghc / includes / Updates.h
1 /* -----------------------------------------------------------------------------
2  * $Id: Updates.h,v 1.34 2003/11/12 17:27:06 sof Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Definitions related to updates.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #ifndef UPDATES_H
11 #define UPDATES_H
12
13 /* -----------------------------------------------------------------------------
14    Update a closure with an indirection.  This may also involve waking
15    up a queue of blocked threads waiting on the result of this
16    computation.
17    -------------------------------------------------------------------------- */
18
19 /* ToDo: overwrite slop words with something safe in case sanity checking 
20  *       is turned on.  
21  *       (I think the fancy version of the GC is supposed to do this too.)
22  */
23
24 /* This expands to a fair chunk of code, what with waking up threads 
25  * and checking whether we're updating something in a old generation.
26  * preferably don't use this macro inline in compiled code.
27  */
28
29 #ifdef TICKY_TICKY
30 # define UPD_IND(updclosure, heapptr) \
31    UPD_PERM_IND(updclosure,heapptr)
32 # define UPD_SPEC_IND(updclosure, ind_info, heapptr, and_then) \
33    UPD_PERM_IND(updclosure,heapptr); and_then
34 #else
35 #  define SEMI ;
36 # define UPD_IND(updclosure, heapptr) \
37    UPD_REAL_IND(updclosure,&stg_IND_info,heapptr,SEMI)
38 # define UPD_SPEC_IND(updclosure, ind_info, heapptr, and_then) \
39    UPD_REAL_IND(updclosure,ind_info,heapptr,and_then)
40 #endif
41
42 /* UPD_IND actually does a PERM_IND if TICKY_TICKY is on;
43    if you *really* need an IND use UPD_REAL_IND
44  */
45 #ifdef SMP
46 #define UPD_REAL_IND(updclosure, ind_info, heapptr, and_then)           \
47    {                                                                    \
48         const StgInfoTable *info;                                       \
49         if (Bdescr((P_)updclosure)->u.back != (bdescr *)BaseReg) {      \
50                 info = LOCK_CLOSURE(updclosure);                        \
51         } else {                                                        \
52                 info = updclosure->header.info;                         \
53         }                                                               \
54         AWAKEN_BQ(info,updclosure);                                     \
55         updateWithIndirection(info, ind_info,                           \
56                               (StgClosure *)updclosure,                 \
57                               (StgClosure *)heapptr,                    \
58                               and_then);                                \
59    }
60 #else
61 #define UPD_REAL_IND(updclosure, ind_info, heapptr, and_then)   \
62    {                                                    \
63         const StgInfoTable *info;                       \
64         info = ((StgClosure *)updclosure)->header.info; \
65         AWAKEN_BQ(info,updclosure);                     \
66         updateWithIndirection(((StgClosure *)updclosure)->header.info, ind_info,                \
67                               (StgClosure *)updclosure, \
68                               (StgClosure *)heapptr,    \
69                               and_then);                \
70    }
71 #endif
72
73 #define UPD_STATIC_IND(updclosure, heapptr)                     \
74    {                                                            \
75         const StgInfoTable *info;                               \
76         info = ((StgClosure *)updclosure)->header.info;         \
77         AWAKEN_STATIC_BQ(info,updclosure);                      \
78         updateWithStaticIndirection(info,                       \
79                                     (StgClosure *)updclosure,   \
80                                     (StgClosure *)heapptr);     \
81    }
82
83 #if defined(PROFILING) || defined(TICKY_TICKY)
84 #define UPD_PERM_IND(updclosure, heapptr)                       \
85    {                                                            \
86         const StgInfoTable *info;                               \
87         info = ((StgClosure *)updclosure)->header.info;         \
88         AWAKEN_BQ(info,updclosure);                             \
89         updateWithPermIndirection(info,                         \
90                                   (StgClosure *)updclosure,     \
91                                   (StgClosure *)heapptr);       \
92    }
93 #endif
94
95 #ifdef SMP
96 #define UPD_IND_NOLOCK(updclosure, heapptr)                             \
97    {                                                                    \
98         const StgInfoTable *info;                                       \
99         info = updclosure->header.info;                                 \
100         AWAKEN_BQ(info,updclosure);                                     \
101         updateWithIndirection(info,&stg_IND_info,                       \
102                               (StgClosure *)updclosure,                 \
103                               (StgClosure *)heapptr,);                  \
104    }
105 #elif defined(RTS_SUPPORTS_THREADS)
106
107 # ifdef TICKY_TICKY
108 #  define UPD_IND_NOLOCK(updclosure, heapptr)                   \
109    {                                                            \
110         const StgInfoTable *info;                               \
111         info = ((StgClosure *)updclosure)->header.info;         \
112         AWAKEN_BQ_NOLOCK(info,updclosure);                      \
113         updateWithPermIndirection(info,                         \
114                                   (StgClosure *)updclosure,     \
115                                   (StgClosure *)heapptr);       \
116    }
117 # else
118 #  define UPD_IND_NOLOCK(updclosure, heapptr)           \
119    {                                                    \
120         const StgInfoTable *info;                       \
121         info = ((StgClosure *)updclosure)->header.info; \
122         AWAKEN_BQ_NOLOCK(info,updclosure);              \
123         updateWithIndirection(info,&stg_IND_info,       \
124                               (StgClosure *)updclosure, \
125                               (StgClosure *)heapptr,);  \
126    }
127 # endif
128
129 #else
130 #define UPD_IND_NOLOCK(updclosure,heapptr) UPD_IND(updclosure,heapptr)
131 #endif
132
133 /* -----------------------------------------------------------------------------
134    Awaken any threads waiting on this computation
135    -------------------------------------------------------------------------- */
136
137 #if defined(PAR) 
138
139 /* 
140    In a parallel setup several types of closures might have a blocking queue:
141      BLACKHOLE_BQ ... same as in the default concurrent setup; it will be
142                       reawakened via calling UPD_IND on that closure after
143                       having finished the computation of the graph
144      FETCH_ME_BQ  ... a global indirection (FETCH_ME) may be entered by a 
145                       local TSO, turning it into a FETCH_ME_BQ; it will be
146                       reawakened via calling processResume
147      RBH          ... a revertible black hole may be entered by another 
148                       local TSO, putting it onto its blocking queue; since
149                       RBHs only exist while the corresponding closure is in 
150                       transit, they will be reawakened via calling 
151                       convertToFetchMe (upon processing an ACK message)
152
153    In a parallel setup a blocking queue may contain 3 types of closures:
154      TSO           ... as in the default concurrent setup
155      BLOCKED_FETCH ... indicating that a TSO on another PE is waiting for
156                        the result of the current computation
157      CONSTR        ... an RBHSave closure (which contains data ripped out of
158                        the closure to make room for a blocking queue; since
159                        it only contains data we use the exisiting type of
160                        a CONSTR closure); this closure is the end of a 
161                        blocking queue for an RBH closure; it only exists in
162                        this kind of blocking queue and must be at the end
163                        of the queue
164 */                    
165 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
166 #define DO_AWAKEN_BQ(bqe, node)  STGCALL2(awakenBlockedQueue, bqe, node);
167
168 #define AWAKEN_BQ(info,closure)                                         \
169         if (info == &stg_BLACKHOLE_BQ_info ||               \
170             info == &stg_FETCH_ME_BQ_info ||                \
171             get_itbl(closure)->type == RBH) {                           \
172                 DO_AWAKEN_BQ(((StgBlockingQueue *)closure)->blocking_queue, closure);                           \
173         }
174
175 #elif defined(GRAN)
176
177 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
178 #define DO_AWAKEN_BQ(bq, node)  STGCALL2(awakenBlockedQueue, bq, node);
179
180 /* In GranSim we don't have FETCH_ME or FETCH_ME_BQ closures, so they are
181    not checked. The rest of the code is the same as for GUM.
182 */
183 #define AWAKEN_BQ(info,closure)                                         \
184         if (info == &stg_BLACKHOLE_BQ_info ||               \
185             get_itbl(closure)->type == RBH) {                           \
186                 DO_AWAKEN_BQ(((StgBlockingQueue *)closure)->blocking_queue, closure);                           \
187         }
188
189
190 #else /* !GRAN && !PAR */
191
192 extern void awakenBlockedQueue(StgTSO *q);
193 #define DO_AWAKEN_BQ(closure)   \
194         STGCALL1(awakenBlockedQueue,            \
195                  ((StgBlockingQueue *)closure)->blocking_queue);
196
197 #define AWAKEN_BQ(info,closure)                                         \
198         if (info == &stg_BLACKHOLE_BQ_info) {                           \
199           DO_AWAKEN_BQ(closure);                                        \
200         }
201
202 #define AWAKEN_STATIC_BQ(info,closure)                                  \
203         if (info == &stg_BLACKHOLE_BQ_STATIC_info) {                    \
204           DO_AWAKEN_BQ(closure);                                        \
205         }
206
207 #ifdef RTS_SUPPORTS_THREADS
208 extern void awakenBlockedQueueNoLock(StgTSO *q);
209 #define DO_AWAKEN_BQ_NOLOCK(closure)                                    \
210         STGCALL1(awakenBlockedQueueNoLock,                              \
211                  ((StgBlockingQueue *)closure)->blocking_queue);
212
213 #define AWAKEN_BQ_NOLOCK(info,closure)                                  \
214         if (info == &stg_BLACKHOLE_BQ_info) {                           \
215           DO_AWAKEN_BQ_NOLOCK(closure);                                 \
216         }
217 #endif
218 #endif /* GRAN || PAR */
219
220 /* -------------------------------------------------------------------------
221    Push an update frame on the stack.
222    ------------------------------------------------------------------------- */
223
224 #if defined(PROFILING)
225 // frame->header.prof.hp.rs = NULL (or frame-header.prof.hp.ldvw = 0) is unnecessary 
226 // because it is not used anyhow.
227 #define PUSH_STD_CCCS(frame) (frame->header.prof.ccs = CCCS)
228 #else
229 #define PUSH_STD_CCCS(frame)
230 #endif
231
232 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_upd_frame_info; 
233 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_noupd_frame_info; 
234
235 #define PUSH_UPD_FRAME(target, Sp_offset)                       \
236         {                                                       \
237                 StgUpdateFrame *__frame;                        \
238                 TICK_UPDF_PUSHED(target, GET_INFO((StgClosure*)target)); \
239                 __frame = (StgUpdateFrame *)(Sp + (Sp_offset)) - 1; \
240                 SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);   \
241                 __frame->updatee = (StgClosure *)(target);      \
242                 PUSH_STD_CCCS(__frame);                         \
243         }
244
245 /* -----------------------------------------------------------------------------
246    Entering CAFs
247
248    When a CAF is first entered, it creates a black hole in the heap,
249    and updates itself with an indirection to this new black hole.
250
251    We update the CAF with an indirection to a newly-allocated black
252    hole in the heap.  We also set the blocking queue on the newly
253    allocated black hole to be empty.
254
255    Why do we make a black hole in the heap when we enter a CAF?
256       
257        - for a  generational garbage collector, which needs a fast
258          test for whether an updatee is in an old generation or not
259
260        - for the parallel system, which can implement updates more
261          easily if the updatee is always in the heap. (allegedly).
262
263    When debugging, we maintain a separate CAF list so we can tell when
264    a CAF has been garbage collected.
265    -------------------------------------------------------------------------- */
266    
267 /* ToDo: only call newCAF when debugging. */
268
269 extern void newCAF(StgClosure*);
270
271 /* newCAF must be called before the itbl ptr is overwritten, since
272    newCAF records the old itbl ptr in order to do CAF reverting
273    (which Hugs needs to do in order that combined mode works right.)
274 */
275 #define UPD_CAF(cafptr, bhptr)                                          \
276   {                                                                     \
277     LOCK_CLOSURE(cafptr);                                               \
278     STGCALL1(newCAF,(StgClosure *)cafptr);                              \
279     ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);           \
280     SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&stg_IND_STATIC_info);\
281   }
282
283 /* -----------------------------------------------------------------------------
284    Update-related prototypes
285    -------------------------------------------------------------------------- */
286
287 #endif /* UPDATES_H */