2 Time-stamp: <Tue Mar 13 2001 19:07:13 Stardate: [-30]6323.98 hwloidl>
4 Revertible Black Hole Manipulation.
5 Used in GUM and GranSim during the packing of closures. These black holes
6 must be revertible because a GC might occur while the packet is being
7 transmitted. In this case all RBHs have to be reverted.
10 #if defined(PAR) || defined(GRAN) /* whole file */
15 #include "GranSimRts.h"
16 #include "ParallelRts.h"
18 # include "ParallelDebug.h"
20 #include "Storage.h" // for recordMutable
21 #include "StgMacros.h" // inlined IS_... fcts
24 Turn a closure into a revertible black hole. After the conversion, the
25 first two words of the closure (after the fixed header, of course) will
26 be a link to the mutables list (if appropriate for the garbage
27 collector), and a pointer to the blocking queue. The blocking queue is
28 terminated by a 2-word SPEC closure which holds the original contents of
29 the first two words of the closure.
33 //* Externs and prototypes::
34 //* Conversion Functions::
38 //@node Externs and prototypes, Conversion Functions
39 //@section Externs and prototypes
41 EXTFUN(stg_RBH_Save_0_info);
42 EXTFUN(stg_RBH_Save_1_info);
43 EXTFUN(stg_RBH_Save_2_info);
45 //@node Conversion Functions, Index, Externs and prototypes
46 //@section Conversion Functions
49 A closure is turned into an RBH upon packing it (see PackClosure in Pack.c).
50 This is needed in case we have to do a GC before the packet is turned
51 into a graph on the PE receiving the packet.
53 //@cindex convertToRBH
59 StgInfoTable *info_ptr, *rbh_info_ptr, *old_info;
60 nat size, ptrs, nonptrs, vhs;
64 Closure layout before this routine runs amuck:
71 Turn closure into an RBH. This is done by modifying the info_ptr,
72 grabbing the info_ptr of the RBH for this closure out of its
73 ITBL. Additionally, we have to save the words from the closure, which
74 will hold the link to the blocking queue. For this purpose we use the
75 RBH_Save_N closures, with N being the number of pointers for this
78 belch("*>:: %p (%s): Converting closure into an RBH",
79 closure, info_type(closure)));
81 belch("*>:: %p (%s): Converting closure into an RBH",
82 closure, info_type(closure)));
84 ASSERT(closure_THUNK(closure));
87 old_info = get_itbl(closure));
89 /* Allocate a new closure for the holding data ripped out of closure */
90 if ((rbh_save = (StgRBHSave *)allocate(_HS + 2)) == NULL)
91 return NULL; /* have to Garbage Collect; check that in the caller! */
93 info_ptr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
94 ASSERT(size >= _HS+MIN_UPD_SIZE);
96 /* Fill in the RBH_Save closure with the original data from closure */
97 rbh_save->payload[0] = (StgPtr) ((StgRBH *)closure)->blocking_queue;
98 rbh_save->payload[1] = (StgPtr) ((StgRBH *)closure)->mut_link;
100 /* Set the info_ptr for the rbh_Save closure according to the number of
101 pointers in the original */
103 rbh_info_ptr = (StgInfoTable *) (ptrs == 0 ? &stg_RBH_Save_0_info :
104 ptrs == 1 ? &stg_RBH_Save_1_info :
105 &stg_RBH_Save_2_info);
106 SET_INFO(rbh_save, rbh_info_ptr);
107 /* same bitmask as the original closure */
108 SET_GRAN_HDR(rbh_save, PROCS(closure));
110 /* Init the blocking queue of the RBH and have it point to the saved data */
111 ((StgRBH *)closure)->blocking_queue = (StgBlockingQueueElement *)rbh_save;
113 ASSERT(LOOKS_LIKE_GHC_INFO(RBH_INFOPTR(get_itbl(closure))));
114 /* Turn the closure into a RBH; a great system, indeed! */
115 SET_INFO(closure, RBH_INFOPTR(get_itbl(closure)));
118 add closure to the mutable list!
119 do this after having turned the closure into an RBH, because an
120 RBH is mutable but the closure it was before wasn't mutable
122 recordMutable((StgMutClosure *)closure);
124 //IF_GRAN_DEBUG(pack,
125 /* sanity check; make sure that reverting the RBH yields the
126 orig closure, again */
127 //ASSERT(REVERT_INFOPTR(get_itbl(closure))==old_info));
130 Closure layout after this routine has run amuck:
131 +---------------------
132 | RBH-HEADER | | | ...
133 +--------------|---|--
135 | Mutable-list ie another StgMutClosure
138 | RBH_SAVE with 0-2 words of DATA
146 An RBH closure is turned into a FETCH_ME when reveiving an ACK message
147 indicating that the transferred closure has been unpacked on the other PE
148 (see processAck in HLComms.c). The ACK also contains the new GA of the
149 closure to which the FETCH_ME closure has to point.
151 Converting a closure to a FetchMe is trivial, unless the closure has
152 acquired a blocking queue. If that has happened, we first have to awaken
153 the blocking queue. What a nuisance! Fortunately, @AwakenBlockingQueue@
154 should now know what to do.
156 A note on GrAnSim: In GrAnSim we don't have FetchMe closures. However,
157 we have to turn a RBH back to its original form when the simulated
158 transfer of the closure has been finished. Therefore we need the
159 @convertFromRBH@ routine below. After converting the RBH back to its
160 original form and awakening all TSOs, the first TSO will reenter the
161 closure which is now local and carry on merrily reducing it (the other
162 TSO will be less merrily blocked on the now local closure; we're costing
163 the difference between local and global blocks in the BQ code). -- HWL
168 EXTFUN(stg_FETCH_ME_info);
170 //@cindex convertToFetchMe
172 convertToFetchMe(rbh, ga)
176 // StgInfoTable *ip = get_itbl(rbh);
177 StgBlockingQueueElement *bqe = rbh->blocking_queue;
179 ASSERT(get_itbl(rbh)->type==RBH);
182 belch("**:: Converting RBH %p (%s) into a FETCH_ME for GA ((%x, %d, %x))",
184 ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight));
186 /* put closure on mutables list, while it is still a RBH */
187 recordMutable((StgMutClosure *)rbh);
189 /* actually turn it into a FETCH_ME */
190 SET_INFO((StgClosure *)rbh, &stg_FETCH_ME_info);
192 /* set the global pointer in the FETCH_ME closure to the given value */
193 ((StgFetchMe *)rbh)->ga = ga;
196 if (get_itbl(bqe)->type==TSO || get_itbl(bqe)->type==BLOCKED_FETCH)
197 belch("**:: Awakening non-empty BQ of RBH closure %p (first TSO is %d (%p)",
198 rbh, ((StgTSO *)bqe)->id, ((StgTSO *)bqe)));
200 /* awaken all TSOs and BLOCKED_FETCHES on the blocking queue */
201 if (get_itbl(bqe)->type==TSO || get_itbl(bqe)->type==BLOCKED_FETCH)
202 awakenBlockedQueue(bqe, (StgClosure *)rbh);
206 // void UnlinkFromMUT(StgPtr closure);
209 This routine in fact reverts the RBH into its original form; this code
210 should be of interest for GUM, too, but is not needed in the current version.
211 convertFromRBH is called where GUM uses convertToFetchMe.
214 convertFromRBH(closure)
217 StgBlockingQueueElement *bqe = ((StgRBH*)closure)->blocking_queue;
218 char str[NODE_STR_LEN]; // debugging only
219 StgInfoTable *rip = REVERT_INFOPTR(get_itbl(closure)); // debugging only
222 if (get_itbl(bqe)->type==TSO)
223 sprintf(str, "%d (%p)",
224 ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
226 strcpy(str, "empty");
227 belch("*<:: Reverting RBH %p (%s) into a ??? closure again; BQ start: %s",
228 closure, info_type(closure), str));
230 ASSERT(get_itbl(closure)->type==RBH);
232 /* awakenBlockedQueue also restores the RBH_Save closure
233 (have to call it even if there are no TSOs in the queue!) */
234 awakenBlockedQueue(bqe, closure);
236 /* Put back old info pointer (grabbed from the RBH's info table).
237 We do that *after* awakening the BQ to be sure node is an RBH when
238 calling awakenBlockedQueue (different in GUM!)
240 SET_INFO(closure, REVERT_INFOPTR(get_itbl(closure)));
242 /* put closure on mutables list */
243 recordMutable((StgMutClosure *)closure);
245 # if 0 /* rest of this fct */
247 /* FETCHME_GA(closure) = ga; */
248 if (IS_MUTABLE(INFO_PTR(bqe))) {
249 PROC old_proc = CurrentProc, /* NB: For AwakenBlockingQueue, */
250 new_proc = where_is(closure); /* CurentProc must be where */
252 CurrentProc = new_proc;
254 # if defined(GRAN_CHECK)
255 if (RTSflags.GranFlags.debug & 0x100)
256 fprintf(stderr,"===== AwBQ of node 0x%lx (%s) [PE %2u]\n",
257 closure, (isSpec ? "SPEC_RBH" : "GEN_RBH"), new_proc);
260 rbh_save = AwakenBlockingQueue(bqe); /* AwakenBlockingQueue(bqe); */
261 CurrentProc = old_proc;
266 /* Put data from special RBH save closures back into the closure */
267 if ( rbh_save == NULL ) {
268 fprintf(stderr,"convertFromRBH: No RBH_Save_? closure found at end of BQ!\n");
271 closure[isSpec ? SPEC_HS : GEN_HS] = rbh_save[SPEC_HS];
272 closure[(isSpec ? SPEC_HS : GEN_HS) + 1] = rbh_save[SPEC_HS + 1];
276 # if 0 && (defined(GCap) || defined(GCgn))
278 /* If we convert from an RBH in the old generation,
279 we have to make sure it goes on the mutables list */
281 if(closure <= StorageMgrInfo.OldLim) {
282 if (IS_MUTABLE(INFO_PTR(closure)) && MUT_LINK(closure) == MUT_NOT_LINKED) {
283 MUT_LINK(closure) = (StgWord) StorageMgrInfo.OldMutables;
284 StorageMgrInfo.OldMutables = closure;
291 /* Remove closure from the mutables list */
295 UnlinkFromMUT(StgPtr closure)
297 StgPtr curr = StorageMgrInfo.OldMutables, prev = NULL;
299 while (curr != NULL && curr != closure) {
300 ASSERT(MUT_LINK(curr)!=MUT_NOT_LINKED);
306 StorageMgrInfo.OldMutables = MUT_LINK(curr);
308 MUT_LINK(prev) = MUT_LINK(curr);
309 MUT_LINK(curr) = MUT_NOT_LINKED;
312 # if 0 && (defined(GCap) || defined(GCgn))
315 extern closq ex_RBH_q;
317 newclos = (closq) stgMallocBytes(sizeof(struct clos), "UnlinkFromMUT");
318 CLOS_CLOSURE(newclos) = closure;
319 CLOS_PREV(newclos) = NULL;
320 CLOS_NEXT(newclos) = ex_RBH_q;
322 CLOS_PREV(ex_RBH_q) = newclos;
329 #endif /* PAR || GRAN -- whole file */
331 //@node Index, , Conversion Functions
335 //* convertToFetchMe:: @cindex\s-+convertToFetchMe
336 //* convertToRBH:: @cindex\s-+convertToRBH