2 Time-stamp: <Sun Dec 12 1999 20:39:04 Stardate: [-30]4039.09 software>
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::
39 //@node Externs and prototypes, Conversion Functions
40 //@section Externs and prototypes
42 EXTFUN(RBH_Save_0_info);
43 EXTFUN(RBH_Save_1_info);
44 EXTFUN(RBH_Save_2_info);
46 //@node Conversion Functions, Index, Externs and prototypes
47 //@section Conversion Functions
50 A closure is turned into an RBH upon packing it (see PackClosure in Pack.c).
51 This is needed in case we have to do a GC before the packet is turned
52 into a graph on the PE receiving the packet.
54 //@cindex convertToRBH
60 StgInfoTable *info_ptr, *rbh_info_ptr, *old_info;
61 nat size, ptrs, nonptrs, vhs;
65 Closure layout before this routine runs amuck:
72 Turn closure into an RBH. This is done by modifying the info_ptr,
73 grabbing the info_ptr of the RBH for this closure out of its
74 ITBL. Additionally, we have to save the words from the closure, which
75 will hold the link to the blocking queue. For this purpose we use the
76 RBH_Save_N closures, with N being the number of pointers for this
79 belch(":* Converting closure %p (%s) into an RBH",
80 closure, info_type(closure)));
82 belch(":* Converting closure %p (%s) into an RBH",
83 closure, info_type(closure)));
85 ASSERT(closure_THUNK(closure));
88 old_info = get_itbl(closure));
90 /* Allocate a new closure for the holding data ripped out of closure */
91 if ((rbh_save = (StgRBHSave *)allocate(FIXED_HS + 2)) == NULL)
92 return NULL; /* have to Garbage Collect; check that in the caller! */
94 info_ptr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
95 ASSERT(size >= MIN_UPD_SIZE);
97 /* Fill in the RBH_Save closure with the original data from closure */
98 rbh_save->payload[0] = (StgPtr) ((StgRBH *)closure)->blocking_queue;
99 rbh_save->payload[1] = (StgPtr) ((StgRBH *)closure)->mut_link;
101 /* Set the info_ptr for the rbh_Save closure according to the number of
102 pointers in the original */
104 rbh_info_ptr = (StgInfoTable *) (ptrs == 0 ? &RBH_Save_0_info :
105 ptrs == 1 ? &RBH_Save_1_info :
107 SET_INFO(rbh_save, rbh_info_ptr);
108 /* same bitmask as the original closure */
109 SET_GRAN_HDR(rbh_save, PROCS(closure));
111 /* Init the blocking queue of the RBH and have it point to the saved data */
112 ((StgRBH *)closure)->blocking_queue = (StgBlockingQueueElement *)rbh_save;
114 ASSERT(LOOKS_LIKE_GHC_INFO(RBH_INFOPTR(get_itbl(closure))));
115 /* Turn the closure into a RBH; a great system, indeed! */
116 SET_INFO(closure, RBH_INFOPTR(get_itbl(closure)));
119 add closure to the mutable list!
120 do this after having turned the closure into an RBH, because an
121 RBH is mutable but the think it was previously isn't
123 //recordMutable((StgMutClosure *)closure);
125 //IF_GRAN_DEBUG(pack,
126 /* sanity check; make sure that reverting the RBH yields the
127 orig closure, again */
128 //ASSERT(REVERT_INFOPTR(get_itbl(closure))==old_info));
131 Closure layout after this routine has run amuck:
132 +---------------------
133 | RBH-HEADER | | | ...
134 +--------------|---|--
136 | Mutable-list ie another StgMutClosure
139 | RBH_SAVE with 0-2 words of DATA
147 An RBH closure is turned into a FETCH_ME when reveiving an ACK message
148 indicating that the transferred closure has been unpacked on the other PE
149 (see processAck in HLComms.c). The ACK also contains the new GA of the
150 closure to which the FETCH_ME closure has to point.
152 Converting a closure to a FetchMe is trivial, unless the closure has
153 acquired a blocking queue. If that has happened, we first have to awaken
154 the blocking queue. What a nuisance! Fortunately, @AwakenBlockingQueue@
155 should now know what to do.
157 A note on GrAnSim: In GrAnSim we don't have FetchMe closures. However,
158 we have to turn a RBH back to its original form when the simulated
159 transfer of the closure has been finished. Therefore we need the
160 @convertFromRBH@ routine below. After converting the RBH back to its
161 original form and awakening all TSOs, the first TSO will reenter the
162 closure which is now local and carry on merrily reducing it (the other
163 TSO will be less merrily blocked on the now local closure; we're costing
164 the difference between local and global blocks in the BQ code). -- HWL
169 EXTFUN(FETCH_ME_info);
171 //@cindex convertToFetchMe
173 convertToFetchMe(rbh, ga)
177 // StgInfoTable *ip = get_itbl(rbh);
178 StgBlockingQueueElement *bqe = rbh->blocking_queue;
180 ASSERT(get_itbl(rbh)->type==RBH);
183 belch(":* Converting RBH %p (%s) into a FETCH_ME for GA ((%x, %d, %x))",
185 ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight));
187 /* put closure on mutables list, while it is still a RBH */
188 //recordMutable((StgMutClosure *)rbh);
190 /* actually turn it into a FETCH_ME */
191 SET_INFO((StgClosure *)rbh, &FETCH_ME_info);
193 /* set the global pointer in the FETCH_ME closure to the given value */
194 ((StgFetchMe *)rbh)->ga = ga;
197 if (get_itbl(bqe)->type==TSO || get_itbl(bqe)->type==BLOCKED_FETCH)
198 belch(":* Awakening non-empty BQ of RBH closure %p (first TSO is %d (%p)",
199 rbh, ((StgTSO *)bqe)->id, ((StgTSO *)bqe)));
201 /* awaken all TSOs and BLOCKED_FETCHES on the blocking queue */
202 if (get_itbl(bqe)->type==TSO || get_itbl(bqe)->type==BLOCKED_FETCH)
203 awaken_blocked_queue(bqe, (StgClosure *)rbh);
207 // void UnlinkFromMUT(StgPtr closure);
210 This routine in fact reverts the RBH into its original form; this code
211 should be of interest for GUM, too, but is not needed in the current version.
212 convertFromRBH is called where GUM uses convertToFetchMe.
215 convertFromRBH(closure)
218 StgBlockingQueueElement *bqe = ((StgRBH*)closure)->blocking_queue;
219 char str[NODE_STR_LEN]; // debugging only
220 StgInfoTable *rip = REVERT_INFOPTR(get_itbl(closure)); // debugging only
223 if (get_itbl(bqe)->type==TSO)
224 sprintf(str, "%d (%p)",
225 ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
227 strcpy(str, "empty");
228 belch(":* Reverting RBH %p (%s) into a ??? closure again; BQ start: %s",
229 closure, info_type(closure), str));
231 ASSERT(get_itbl(closure)->type==RBH);
233 /* awaken_blocked_queue also restores the RBH_Save closure
234 (have to call it even if there are no TSOs in the queue!) */
235 awaken_blocked_queue(bqe, closure);
237 /* Put back old info pointer (grabbed from the RBH's info table).
238 We do that *after* awakening the BQ to be sure node is an RBH when
239 calling awaken_blocked_queue (different in GUM!)
241 SET_INFO(closure, REVERT_INFOPTR(get_itbl(closure)));
243 /* put closure on mutables list */
244 //recordMutable((StgMutClosure *)closure);
246 # if 0 /* rest of this fct */
248 /* FETCHME_GA(closure) = ga; */
249 if (IS_MUTABLE(INFO_PTR(bqe))) {
250 PROC old_proc = CurrentProc, /* NB: For AwakenBlockingQueue, */
251 new_proc = where_is(closure); /* CurentProc must be where */
253 CurrentProc = new_proc;
255 # if defined(GRAN_CHECK)
256 if (RTSflags.GranFlags.debug & 0x100)
257 fprintf(stderr,"===== AwBQ of node 0x%lx (%s) [PE %2u]\n",
258 closure, (isSpec ? "SPEC_RBH" : "GEN_RBH"), new_proc);
261 rbh_save = AwakenBlockingQueue(bqe); /* AwakenBlockingQueue(bqe); */
262 CurrentProc = old_proc;
267 /* Put data from special RBH save closures back into the closure */
268 if ( rbh_save == NULL ) {
269 fprintf(stderr,"convertFromRBH: No RBH_Save_? closure found at end of BQ!\n");
272 closure[isSpec ? SPEC_HS : GEN_HS] = rbh_save[SPEC_HS];
273 closure[(isSpec ? SPEC_HS : GEN_HS) + 1] = rbh_save[SPEC_HS + 1];
277 # if 0 && (defined(GCap) || defined(GCgn))
279 /* If we convert from an RBH in the old generation,
280 we have to make sure it goes on the mutables list */
282 if(closure <= StorageMgrInfo.OldLim) {
283 if (IS_MUTABLE(INFO_PTR(closure)) && MUT_LINK(closure) == MUT_NOT_LINKED) {
284 MUT_LINK(closure) = (StgWord) StorageMgrInfo.OldMutables;
285 StorageMgrInfo.OldMutables = closure;
292 /* Remove closure from the mutables list */
296 UnlinkFromMUT(StgPtr closure)
298 StgPtr curr = StorageMgrInfo.OldMutables, prev = NULL;
300 while (curr != NULL && curr != closure) {
301 ASSERT(MUT_LINK(curr)!=MUT_NOT_LINKED);
307 StorageMgrInfo.OldMutables = MUT_LINK(curr);
309 MUT_LINK(prev) = MUT_LINK(curr);
310 MUT_LINK(curr) = MUT_NOT_LINKED;
313 # if 0 && (defined(GCap) || defined(GCgn))
316 extern closq ex_RBH_q;
318 newclos = (closq) stgMallocBytes(sizeof(struct clos), "UnlinkFromMUT");
319 CLOS_CLOSURE(newclos) = closure;
320 CLOS_PREV(newclos) = NULL;
321 CLOS_NEXT(newclos) = ex_RBH_q;
323 CLOS_PREV(ex_RBH_q) = newclos;
330 #endif /* PAR || GRAN -- whole file */
332 //@node Index, , Conversion Functions
336 //* convertToFetchMe:: @cindex\s-+convertToFetchMe
337 //* convertToRBH:: @cindex\s-+convertToRBH