2 % (c) The AQUA/Parade Projects, Glasgow University, 1995
4 %************************************************************************
6 \section[RBH.lc]{Revertible Black Hole Manipulation}
8 %************************************************************************
11 #if defined(PAR) || defined(GRAN) /* whole file */
16 Turn a closure into a revertible black hole. After the conversion,
17 the first two words of the closure will be a link to the mutables
18 list (if appropriate for the garbage collector), and a pointer
19 to the blocking queue. The blocking queue is terminated by a 2-word
20 SPEC closure which holds the original contents of the first two
24 EXTFUN(RBH_Save_0_info);
25 EXTFUN(RBH_Save_1_info);
26 EXTFUN(RBH_Save_2_info);
32 P_ infoPtr, newInfoPtr;
33 W_ size, ptrs, nonptrs, vhs;
38 if ((rbh_save = AllocateHeap(SPEC_HS + 2)) == NULL)
41 infoPtr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
42 ASSERT(size >= MIN_UPD_SIZE);
44 switch (BASE_INFO_TYPE(infoPtr)) {
52 fprintf(stderr, "Panic: turn %#lx (IP %#lx) into RBH\n", (W_)closure, (W_)infoPtr);
56 /* Fill in the RBH_Save closure with the original data */
57 rbh_save[SPEC_HS] = closure[isSpec ? SPEC_HS : GEN_HS];
58 rbh_save[SPEC_HS + 1] = closure[(isSpec ? SPEC_HS : GEN_HS) + 1];
61 * Set the info_ptr for the rbh_Save closure according to the number of pointers
65 newInfoPtr = (P_) (ptrs == 0 ? RBH_Save_0_info :
66 ptrs == 1 ? RBH_Save_1_info :
68 SET_INFO_PTR(rbh_save, newInfoPtr);
70 /* Do some magic garbage collection mangling on the first word */
72 #if defined(GCap) || defined(GCgn)
75 * If the closure's in the old generation, we have to make sure it goes on the
79 if (closure <= StorageMgrInfo.OldLim) {
80 MUT_LINK(closure) = (W_) StorageMgrInfo.OldMutables;
81 StorageMgrInfo.OldMutables = closure;
83 MUT_LINK(closure) = MUT_NOT_LINKED;
87 * Second word points to the RBH_Save closure with the original data. This may
88 * become a blocking queue terminated by the RBH_Save closure.
91 SPEC_RBH_BQ(closure) = (W_) rbh_save;
93 GEN_RBH_BQ(closure) = (W_) rbh_save;
95 /* OK, now actually turn it into a RBH (what a great system!) */
96 SET_INFO_PTR(closure, RBH_INFOPTR(INFO_PTR(closure)));
103 Converting a closure to a FetchMe is trivial, unless the closure has
104 acquired a blocking queue. If that has happened, we first have to
105 awaken the blocking queue. What a nuisance! Fortunately,
106 @AwakenBlockingQueue@ should now know what to do.
108 A note on GrAnSim: In GrAnSim we don't have FetchMe closures. However, we
109 have to turn a RBH back to its original form when the simulated transfer
110 of the closure has been finished. Therefore we need the @convertFromRBH@
111 routine below. After converting the RBH back to its original form and
112 awakening all TSOs, the first TSO will reenter the closure which is now
113 local and carry on merrily reducing it (the other TSO will be less merrily
114 blocked on the now local closure; we're costing the difference between
115 local and global blocks in the BQ code).
120 EXTDATA_RO(FetchMe_info);
123 convertToFetchMe(closure, ga)
127 P_ ip = (P_) INFO_PTR(closure);
129 #if defined(GCap) || defined(GCgn)
130 rtsBool linked = IS_MUTABLE(ip) && MUT_LINK(closure) != MUT_NOT_LINKED;
133 switch(INFO_TYPE(ip)) {
134 case INFO_SPEC_RBH_TYPE:
135 bqe = (P_) SPEC_RBH_BQ(closure);
137 case INFO_GEN_RBH_TYPE:
138 bqe = (P_) GEN_RBH_BQ(closure);
142 fprintf(stderr, "Weird...just tried to convert %#lx (IP %#lx) to FetchMe\n",
148 SET_INFO_PTR(closure, FetchMe_info);
150 #if defined(GCap) || defined(GCgn)
151 /* If we modify a fetchme in the old generation,
152 we have to make sure it goes on the mutables list */
154 if(closure <= StorageMgrInfo.OldLim) {
156 MUT_LINK(closure) = (W_) StorageMgrInfo.OldMutables;
157 StorageMgrInfo.OldMutables = closure;
160 MUT_LINK(closure) = MUT_NOT_LINKED;
163 FETCHME_GA(closure) = ga;
164 if (IS_MUTABLE(INFO_PTR(bqe)))
165 AwakenBlockingQueue(bqe);
169 void UnlinkFromMUT(P_ closure);
172 convertFromRBH(closure) /* The corresponding function in GUM is: */
173 /* convertToFetchMe */
176 P_ ip = (P_) INFO_PTR(closure);
177 P_ bqe, rbh_save = PrelBase_Z91Z93_closure;
179 #if defined(GCap) || defined(GCgn)
180 rtsBool linked = IS_MUTABLE(ip) && MUT_LINK(closure) != MUT_NOT_LINKED;
181 P_ oldLink = MUT_LINK(closure);
184 switch(INFO_TYPE(ip)) {
185 case INFO_SPEC_RBH_TYPE:
186 bqe = (P_) SPEC_RBH_BQ(closure);
189 case INFO_GEN_RBH_TYPE:
190 bqe = (P_) GEN_RBH_BQ(closure);
195 fprintf(stderr, "Weird...just tried to convert %#lx (IP %#lx) to FetchMe\n",
201 # if defined(GCap) || defined(GCgn)
202 /* If the RBH is turned back to a SPEC or GEN closure we have to take
203 it off the mutables list */
206 # if defined(GRAN_CHECK)
207 if (RTSflags.GranFlags.debug & 0x100) {
208 fprintf(stderr,"\n**>>>> Unlinking closure %#lx from mutables list on PE %d @ %ld (next mutable=%#lx)\n",
210 where_is(closure), CurrentTime[where_is(closure)],
215 UnlinkFromMUT(closure);
219 /* FETCHME_GA(closure) = ga; */
220 if (IS_MUTABLE(INFO_PTR(bqe))) {
221 PROC old_proc = CurrentProc, /* NB: For AwakenBlockingQueue, */
222 new_proc = where_is(closure); /* CurentProc must be where */
224 CurrentProc = new_proc;
226 # if defined(GRAN_CHECK)
227 if (RTSflags.GranFlags.debug & 0x100)
228 fprintf(stderr,"===== AwBQ of node 0x%lx (%s) [PE %2u]\n",
229 closure, (isSpec ? "SPEC_RBH" : "GEN_RBH"), new_proc);
232 rbh_save = AwakenBlockingQueue(bqe); /* AwakenBlockingQueue(bqe); */
233 CurrentProc = old_proc;
238 /* Put data from special RBH save closures back into the closure */
239 if ( rbh_save == PrelBase_Z91Z93_closure ) {
240 fprintf(stderr,"convertFromRBH: No RBH_Save_? closure found at end of BQ!\n");
243 closure[isSpec ? SPEC_HS : GEN_HS] = rbh_save[SPEC_HS];
244 closure[(isSpec ? SPEC_HS : GEN_HS) + 1] = rbh_save[SPEC_HS + 1];
247 /* Put back old info pointer (only in GrAnSim) -- HWL */
248 SET_INFO_PTR(closure, REVERT_INFOPTR(INFO_PTR(closure)));
250 # if (defined(GCap) || defined(GCgn))
251 /* If we convert from an RBH in the old generation,
252 we have to make sure it goes on the mutables list */
254 if(closure <= StorageMgrInfo.OldLim) {
255 if (IS_MUTABLE(INFO_PTR(closure)) && MUT_LINK(closure) == MUT_NOT_LINKED) {
256 MUT_LINK(closure) = (W_) StorageMgrInfo.OldMutables;
257 StorageMgrInfo.OldMutables = closure;
263 /* Remove closure from the mutables list */
266 UnlinkFromMUT(P_ closure)
268 P_ curr = StorageMgrInfo.OldMutables, prev = NULL;
270 while (curr != NULL && curr != closure) {
271 ASSERT(MUT_LINK(curr)!=MUT_NOT_LINKED);
277 StorageMgrInfo.OldMutables = MUT_LINK(curr);
279 MUT_LINK(prev) = MUT_LINK(curr);
280 MUT_LINK(curr) = MUT_NOT_LINKED;
283 #if 0 && (defined(GCap) || defined(GCgn))
286 extern closq ex_RBH_q;
288 newclos = (closq) stgMallocBytes(sizeof(struct clos), "UnlinkFromMUT");
289 CLOS_CLOSURE(newclos) = closure;
290 CLOS_PREV(newclos) = NULL;
291 CLOS_NEXT(newclos) = ex_RBH_q;
293 CLOS_PREV(ex_RBH_q) = newclos;
301 #endif /* PAR || GRAN -- whole file */