1 /* -----------------------------------------------------------------------------
2 * $Id: Updates.h,v 1.16 2000/01/13 14:34:01 hwloidl 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 #define UPD_CAF(cafptr, bhptr) \
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); \
223 /* -----------------------------------------------------------------------------
224 Update-related prototypes
225 -------------------------------------------------------------------------- */
227 DLL_IMPORT_RTS extern STGFUN(Upd_frame_entry);
229 extern DLL_IMPORT_DATA const StgInfoTable PAP_info;
230 DLL_IMPORT_RTS STGFUN(PAP_entry);
232 EXTFUN_RTS(stg_update_PAP);
234 extern DLL_IMPORT_DATA const StgInfoTable AP_UPD_info;
235 DLL_IMPORT_RTS STGFUN(AP_UPD_entry);
237 extern DLL_IMPORT_DATA const StgInfoTable raise_info;
239 #endif /* UPDATES_H */