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