1 /* -----------------------------------------------------------------------------
2 * $Id: Updates.h,v 1.22 2001/01/29 17:23:41 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Definitions related to updates.
8 * ---------------------------------------------------------------------------*/
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
17 -------------------------------------------------------------------------- */
19 /* ToDo: overwrite slop words with something safe in case sanity checking
21 * (I think the fancy version of the GC is supposed to do this too.)
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.
30 # define UPD_IND(updclosure, heapptr) UPD_PERM_IND(updclosure,heapptr)
32 # define UPD_IND(updclosure, heapptr) UPD_REAL_IND(updclosure,heapptr)
35 /* UPD_IND actually does a PERM_IND if TICKY_TICKY is on;
36 if you *really* need an IND use UPD_REAL_IND
39 #define UPD_REAL_IND(updclosure, heapptr) \
41 const StgInfoTable *info; \
42 if (Bdescr((P_)updclosure)->back != (bdescr *)BaseReg) { \
43 info = LOCK_CLOSURE(updclosure); \
45 info = updclosure->header.info; \
47 AWAKEN_BQ(info,updclosure); \
48 updateWithIndirection(info, \
49 (StgClosure *)updclosure, \
50 (StgClosure *)heapptr); \
53 #define UPD_REAL_IND(updclosure, heapptr) \
55 const StgInfoTable *info; \
56 info = ((StgClosure *)updclosure)->header.info; \
57 AWAKEN_BQ(info,updclosure); \
58 updateWithIndirection(info, \
59 (StgClosure *)updclosure, \
60 (StgClosure *)heapptr); \
64 #define UPD_STATIC_IND(updclosure, heapptr) \
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); \
74 #if defined(PROFILING) || defined(TICKY_TICKY)
75 #define UPD_PERM_IND(updclosure, heapptr) \
77 const StgInfoTable *info; \
78 info = ((StgClosure *)updclosure)->header.info; \
79 AWAKEN_BQ(info,updclosure); \
80 updateWithPermIndirection(info, \
81 (StgClosure *)updclosure, \
82 (StgClosure *)heapptr); \
87 #define UPD_IND_NOLOCK(updclosure, heapptr) \
89 const StgInfoTable *info; \
90 info = updclosure->header.info; \
91 AWAKEN_BQ(info,updclosure); \
92 updateWithIndirection(info, \
93 (StgClosure *)updclosure, \
94 (StgClosure *)heapptr); \
97 #define UPD_IND_NOLOCK(updclosure,heapptr) UPD_IND(updclosure,heapptr)
100 /* -----------------------------------------------------------------------------
101 Awaken any threads waiting on this computation
102 -------------------------------------------------------------------------- */
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)
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
132 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
133 #define DO_AWAKEN_BQ(bqe, node) STGCALL2(awakenBlockedQueue, bqe, node);
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); \
146 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
147 #define DO_AWAKEN_BQ(bq, node) STGCALL2(awakenBlockedQueue, bq, node);
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.
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); \
161 #else /* !GRAN && !PAR */
163 extern void awakenBlockedQueue(StgTSO *q);
164 #define DO_AWAKEN_BQ(closure) \
165 STGCALL1(awakenBlockedQueue, \
166 ((StgBlockingQueue *)closure)->blocking_queue);
168 #define AWAKEN_BQ(info,closure) \
169 if (info == &stg_BLACKHOLE_BQ_info) { \
170 DO_AWAKEN_BQ(closure); \
173 #define AWAKEN_STATIC_BQ(info,closure) \
174 if (info == &stg_BLACKHOLE_BQ_STATIC_info) { \
175 DO_AWAKEN_BQ(closure); \
178 #endif /* GRAN || PAR */
180 /* -------------------------------------------------------------------------
181 Push an update frame on the stack.
182 ------------------------------------------------------------------------- */
184 #if defined(PROFILING)
185 #define PUSH_STD_CCCS(frame) frame->header.prof.ccs = CCCS
187 #define PUSH_STD_CCCS(frame)
190 extern DLL_IMPORT_RTS const StgPolyInfoTable stg_upd_frame_info;
192 #define PUSH_UPD_FRAME(target, Sp_offset) \
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); \
204 /* -----------------------------------------------------------------------------
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.
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.
214 Why do we make a black hole in the heap when we enter a CAF?
216 - for a generational garbage collector, which needs a fast
217 test for whether an updatee is in an old generation or not
219 - for the parallel system, which can implement updates more
220 easily if the updatee is always in the heap. (allegedly).
222 When debugging, we maintain a separate CAF list so we can tell when
223 a CAF has been garbage collected.
224 -------------------------------------------------------------------------- */
226 /* ToDo: only call newCAF when debugging. */
228 extern void newCAF(StgClosure*);
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.)
234 #define UPD_CAF(cafptr, bhptr) \
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);\
243 extern void newCAF_made_by_Hugs(StgCAF*);
246 /* -----------------------------------------------------------------------------
247 Update-related prototypes
248 -------------------------------------------------------------------------- */
250 DLL_IMPORT_RTS extern STGFUN(stg_upd_frame_entry);
252 extern DLL_IMPORT_RTS const StgInfoTable stg_PAP_info;
253 DLL_IMPORT_RTS STGFUN(stg_PAP_entry);
255 EXTFUN_RTS(stg_update_PAP);
257 extern DLL_IMPORT_RTS const StgInfoTable stg_AP_UPD_info;
258 DLL_IMPORT_RTS STGFUN(stg_AP_UPD_entry);
260 extern DLL_IMPORT_RTS const StgInfoTable stg_raise_info;
262 #endif /* UPDATES_H */