[project @ 2000-04-05 10:11:55 by simonmar]
[ghc-hetmet.git] / ghc / includes / Updates.h
1 /* -----------------------------------------------------------------------------
2  * $Id: Updates.h,v 1.16 2000/01/13 14:34:01 hwloidl 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 == &BLACKHOLE_BQ_info ||               \
127             info == &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 == &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 == &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_DATA const StgPolyInfoTable 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 *)&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 #define UPD_CAF(cafptr, bhptr)                                          \
216   {                                                                     \
217     LOCK_CLOSURE(cafptr);                                               \
218     ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);           \
219     SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&IND_STATIC_info);   \
220     STGCALL1(newCAF,(StgClosure *)cafptr);                              \
221   }
222
223 /* -----------------------------------------------------------------------------
224    Update-related prototypes
225    -------------------------------------------------------------------------- */
226
227 DLL_IMPORT_RTS extern STGFUN(Upd_frame_entry);
228
229 extern DLL_IMPORT_DATA const StgInfoTable PAP_info;
230 DLL_IMPORT_RTS STGFUN(PAP_entry);
231
232 EXTFUN_RTS(stg_update_PAP);
233
234 extern DLL_IMPORT_DATA const StgInfoTable AP_UPD_info;
235 DLL_IMPORT_RTS STGFUN(AP_UPD_entry);
236
237 extern DLL_IMPORT_DATA const StgInfoTable raise_info;
238
239 #endif /* UPDATES_H */