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