[project @ 2001-03-21 15:33:47 by simonmar]
[ghc-hetmet.git] / ghc / includes / Updates.h
1 /* -----------------------------------------------------------------------------
2  * $Id: Updates.h,v 1.23 2001/02/09 13:09:17 simonmar 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)->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 #else
97 #define UPD_IND_NOLOCK(updclosure,heapptr) UPD_IND(updclosure,heapptr)
98 #endif
99
100 /* -----------------------------------------------------------------------------
101    Awaken any threads waiting on this computation
102    -------------------------------------------------------------------------- */
103
104 #if defined(PAR) 
105
106 /* 
107    In a parallel setup several types of closures, might have a blocking queue:
108      BLACKHOLE_BQ ... same as in the default concurrent setup; it will be
109                       reawakened via calling UPD_IND on that closure after
110                       having finished the computation of the graph
111      FETCH_ME_BQ  ... a global indirection (FETCH_ME) may be entered by a 
112                       local TSO, turning it into a FETCH_ME_BQ; it will be
113                       reawakened via calling processResume
114      RBH          ... a revertible black hole may be entered by another 
115                       local TSO, putting it onto its blocking queue; since
116                       RBHs only exist while the corresponding closure is in 
117                       transit, they will be reawakened via calling 
118                       convertToFetchMe (upon processing an ACK message)
119
120    In a parallel setup a blocking queue may contain 3 types of closures:
121      TSO           ... as in the default concurrent setup
122      BLOCKED_FETCH ... indicating that a TSO on another PE is waiting for
123                        the result of the current computation
124      CONSTR        ... a RBHSave closure (which contains data ripped out of
125                        the closure to make room for a blocking queue; since
126                        it only contains data we use the exisiting type of
127                        a CONSTR closure); this closure is the end of a 
128                        blocking queue for an RBH closure; it only exists in
129                        this kind of blocking queue and must be at the end
130                        of the queue
131 */                    
132 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
133 #define DO_AWAKEN_BQ(bqe, node)  STGCALL2(awakenBlockedQueue, bqe, node);
134
135 #define AWAKEN_BQ(info,closure)                                         \
136         if (info == &stg_BLACKHOLE_BQ_info ||               \
137             info == &stg_FETCH_ME_BQ_info ||                \
138             get_itbl(closure)->type == RBH) {                           \
139                 StgBlockingQueueElement *bqe = ((StgBlockingQueue *)closure)->blocking_queue;\
140                 ASSERT(bqe!=END_BQ_QUEUE);                              \
141                 DO_AWAKEN_BQ(bqe, closure);                             \
142         }
143
144 #elif defined(GRAN)
145
146 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
147 #define DO_AWAKEN_BQ(bq, node)  STGCALL2(awakenBlockedQueue, bq, node);
148
149 /* In GranSim we don't have FETCH_ME or FETCH_ME_BQ closures, so they are
150    not checked. The rest of the code is the same as for GUM.
151 */
152 #define AWAKEN_BQ(info,closure)                                         \
153         if (info == &stg_BLACKHOLE_BQ_info ||               \
154             get_itbl(closure)->type == RBH) {                           \
155                 StgBlockingQueueElement *bqe = ((StgBlockingQueue *)closure)->blocking_queue;\
156                 ASSERT(bqe!=END_BQ_QUEUE);                              \
157                 DO_AWAKEN_BQ(bqe, closure);                             \
158         }
159
160
161 #else /* !GRAN && !PAR */
162
163 extern void awakenBlockedQueue(StgTSO *q);
164 #define DO_AWAKEN_BQ(closure)   \
165         STGCALL1(awakenBlockedQueue,            \
166                  ((StgBlockingQueue *)closure)->blocking_queue);
167
168 #define AWAKEN_BQ(info,closure)                                         \
169         if (info == &stg_BLACKHOLE_BQ_info) {                           \
170           DO_AWAKEN_BQ(closure);                                        \
171         }
172
173 #define AWAKEN_STATIC_BQ(info,closure)                                  \
174         if (info == &stg_BLACKHOLE_BQ_STATIC_info) {                    \
175           DO_AWAKEN_BQ(closure);                                        \
176         }
177
178 #endif /* GRAN || PAR */
179
180 /* -------------------------------------------------------------------------
181    Push an update frame on the stack.
182    ------------------------------------------------------------------------- */
183
184 #if defined(PROFILING)
185 #define PUSH_STD_CCCS(frame) frame->header.prof.ccs = CCCS
186 #else
187 #define PUSH_STD_CCCS(frame)
188 #endif
189
190 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_upd_frame_info; 
191
192 #define PUSH_UPD_FRAME(target, Sp_offset)                       \
193         {                                                       \
194                 StgUpdateFrame *__frame;                        \
195                 TICK_UPDF_PUSHED(target, GET_INFO((StgClosure*)target)); \
196                 __frame = (StgUpdateFrame *)(Sp + (Sp_offset)) - 1; \
197                 SET_INFO(__frame, (StgInfoTable *)&stg_upd_frame_info);   \
198                 __frame->link = Su;                             \
199                 __frame->updatee = (StgClosure *)(target);      \
200                 PUSH_STD_CCCS(__frame);                         \
201                 Su = __frame;                                   \
202         }
203
204 /* -----------------------------------------------------------------------------
205    Entering CAFs
206
207    When a CAF is first entered, it creates a black hole in the heap,
208    and updates itself with an indirection to this new black hole.
209
210    We update the CAF with an indirection to a newly-allocated black
211    hole in the heap.  We also set the blocking queue on the newly
212    allocated black hole to be empty.
213
214    Why do we make a black hole in the heap when we enter a CAF?
215       
216        - for a  generational garbage collector, which needs a fast
217          test for whether an updatee is in an old generation or not
218
219        - for the parallel system, which can implement updates more
220          easily if the updatee is always in the heap. (allegedly).
221
222    When debugging, we maintain a separate CAF list so we can tell when
223    a CAF has been garbage collected.
224    -------------------------------------------------------------------------- */
225    
226 /* ToDo: only call newCAF when debugging. */
227
228 extern void newCAF(StgClosure*);
229
230 /* newCAF must be called before the itbl ptr is overwritten, since
231    newCAF records the old itbl ptr in order to do CAF reverting
232    (which Hugs needs to do in order that combined mode works right.)
233 */
234 #define UPD_CAF(cafptr, bhptr)                                          \
235   {                                                                     \
236     LOCK_CLOSURE(cafptr);                                               \
237     STGCALL1(newCAF,(StgClosure *)cafptr);                              \
238     ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);           \
239     SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&stg_IND_STATIC_info);\
240   }
241
242 /* -----------------------------------------------------------------------------
243    Update-related prototypes
244    -------------------------------------------------------------------------- */
245
246 DLL_IMPORT_RTS extern STGFUN(stg_upd_frame_entry);
247
248 extern DLL_IMPORT_RTS const StgInfoTable stg_PAP_info;
249 DLL_IMPORT_RTS STGFUN(stg_PAP_entry);
250
251 EXTFUN_RTS(stg_update_PAP);
252
253 extern DLL_IMPORT_RTS const StgInfoTable stg_AP_UPD_info;
254 DLL_IMPORT_RTS STGFUN(stg_AP_UPD_entry);
255
256 extern DLL_IMPORT_RTS const StgInfoTable stg_raise_info;
257
258 #endif /* UPDATES_H */