1 /* -----------------------------------------------------------------------------
2 * $Id: Updates.h,v 1.17 2000/04/14 15:18:05 sewardj 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 #if defined(PROFILING) || defined(TICKY_TICKY)
65 #define UPD_PERM_IND(updclosure, heapptr) \
67 const StgInfoTable *info; \
68 info = ((StgClosure *)updclosure)->header.info; \
69 AWAKEN_BQ(info,updclosure); \
70 updateWithPermIndirection(info, \
71 (StgClosure *)updclosure, \
72 (StgClosure *)heapptr); \
77 #define UPD_IND_NOLOCK(updclosure, heapptr) \
79 const StgInfoTable *info; \
80 info = updclosure->header.info; \
81 AWAKEN_BQ(info,updclosure); \
82 updateWithIndirection(info, \
83 (StgClosure *)updclosure, \
84 (StgClosure *)heapptr); \
87 #define UPD_IND_NOLOCK(updclosure,heapptr) UPD_IND(updclosure,heapptr)
90 /* -----------------------------------------------------------------------------
91 Awaken any threads waiting on this computation
92 -------------------------------------------------------------------------- */
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)
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
122 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
123 #define DO_AWAKEN_BQ(bqe, node) STGCALL2(awakenBlockedQueue, bqe, node);
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); \
136 extern void awakenBlockedQueue(StgBlockingQueueElement *q, StgClosure *node);
137 #define DO_AWAKEN_BQ(bq, node) STGCALL2(awakenBlockedQueue, bq, node);
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.
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); \
151 #else /* !GRAN && !PAR */
153 extern void awakenBlockedQueue(StgTSO *q);
154 #define DO_AWAKEN_BQ(closure) \
155 STGCALL1(awakenBlockedQueue, \
156 ((StgBlockingQueue *)closure)->blocking_queue);
158 #define AWAKEN_BQ(info,closure) \
159 if (info == &BLACKHOLE_BQ_info) { \
160 DO_AWAKEN_BQ(closure); \
163 #endif /* GRAN || PAR */
165 /* -------------------------------------------------------------------------
166 Push an update frame on the stack.
167 ------------------------------------------------------------------------- */
169 #if defined(PROFILING)
170 #define PUSH_STD_CCCS(frame) frame->header.prof.ccs = CCCS
172 #define PUSH_STD_CCCS(frame)
175 extern DLL_IMPORT_DATA const StgPolyInfoTable Upd_frame_info;
177 #define PUSH_UPD_FRAME(target, Sp_offset) \
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); \
189 /* -----------------------------------------------------------------------------
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.
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.
199 Why do we make a black hole in the heap when we enter a CAF?
201 - for a generational garbage collector, which needs a fast
202 test for whether an updatee is in an old generation or not
204 - for the parallel system, which can implement updates more
205 easily if the updatee is always in the heap. (allegedly).
207 When debugging, we maintain a separate CAF list so we can tell when
208 a CAF has been garbage collected.
209 -------------------------------------------------------------------------- */
211 /* ToDo: only call newCAF when debugging. */
213 extern void newCAF(StgClosure*);
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.)
219 #define UPD_CAF(cafptr, bhptr) \
221 LOCK_CLOSURE(cafptr); \
222 STGCALL1(newCAF,(StgClosure *)cafptr); \
223 ((StgInd *)cafptr)->indirectee = (StgClosure *)(bhptr); \
224 SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&IND_STATIC_info); \
228 extern void newCAF_made_by_Hugs(StgCAF*);
231 /* -----------------------------------------------------------------------------
232 Update-related prototypes
233 -------------------------------------------------------------------------- */
235 DLL_IMPORT_RTS extern STGFUN(Upd_frame_entry);
237 extern DLL_IMPORT_DATA const StgInfoTable PAP_info;
238 DLL_IMPORT_RTS STGFUN(PAP_entry);
240 EXTFUN_RTS(stg_update_PAP);
242 extern DLL_IMPORT_DATA const StgInfoTable AP_UPD_info;
243 DLL_IMPORT_RTS STGFUN(AP_UPD_entry);
245 extern DLL_IMPORT_DATA const StgInfoTable raise_info;
247 #endif /* UPDATES_H */