[project @ 2000-01-14 14:56:40 by simonmar]
[ghc-hetmet.git] / ghc / rts / parallel / RBH.c
1 /*
2   Time-stamp: <Sun Dec 12 1999 20:39:04 Stardate: [-30]4039.09 software>
3
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.
8   */
9
10 #if defined(PAR) || defined(GRAN) /* whole file */
11
12 #include "Rts.h"
13 #include "RtsFlags.h"
14 #include "RtsUtils.h"
15 #include "GranSimRts.h"
16 #include "ParallelRts.h"
17 # if defined(DEBUG)
18 # include "ParallelDebug.h"
19 # endif
20 #include "Storage.h"  // for recordMutable
21 #include "StgMacros.h" // inlined IS_... fcts
22
23 /*
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.  
30 */
31
32 //@menu
33 //* Externs and prototypes::    
34 //* Conversion Functions::      
35 //* Index::                     
36 //@end menu
37 //*/
38
39 //@node Externs and prototypes, Conversion Functions
40 //@section Externs and prototypes
41
42 EXTFUN(RBH_Save_0_info);
43 EXTFUN(RBH_Save_1_info);
44 EXTFUN(RBH_Save_2_info);
45
46 //@node Conversion Functions, Index, Externs and prototypes
47 //@section Conversion Functions
48
49 /*
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. 
53 */
54 //@cindex convertToRBH
55 StgClosure *
56 convertToRBH(closure)
57 StgClosure *closure;
58 {
59   StgRBHSave *rbh_save;
60   StgInfoTable *info_ptr, *rbh_info_ptr, *old_info;
61   nat size, ptrs, nonptrs, vhs;
62   char str[80];
63
64   /*
65      Closure layout before this routine runs amuck:
66        +-------------------
67        |   HEADER   | DATA ...
68        +-------------------
69        | FIXED_HS   |
70   */
71   /* 
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
77      closure.  */
78   IF_GRAN_DEBUG(pack,
79                 belch(":*   Converting closure %p (%s) into an RBH",
80                       closure, info_type(closure))); 
81   IF_PAR_DEBUG(pack,
82                 belch(":*   Converting closure %p (%s) into an RBH",
83                       closure, info_type(closure))); 
84
85   ASSERT(closure_THUNK(closure));
86
87   IF_GRAN_DEBUG(pack,
88                 old_info = get_itbl(closure));
89
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! */
93
94   info_ptr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
95   ASSERT(size >= MIN_UPD_SIZE);
96
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;
100
101   /* Set the info_ptr for the rbh_Save closure according to the number of
102      pointers in the original */
103
104   rbh_info_ptr = (StgInfoTable *) (ptrs == 0 ? &RBH_Save_0_info :
105                                    ptrs == 1 ? &RBH_Save_1_info :
106                                    &RBH_Save_2_info);
107   SET_INFO(rbh_save, rbh_info_ptr);
108   /* same bitmask as the original closure */
109   SET_GRAN_HDR(rbh_save, PROCS(closure));
110
111   /* Init the blocking queue of the RBH and have it point to the saved data */
112   ((StgRBH *)closure)->blocking_queue = (StgBlockingQueueElement *)rbh_save;
113
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)));
117
118   /*
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
122   */
123   //recordMutable((StgMutClosure *)closure);
124
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));
129
130   /*
131      Closure layout after this routine has run amuck:
132        +---------------------
133        | RBH-HEADER | |   |  ...
134        +--------------|---|--
135        | FIXED_HS   | |   v
136                       |   Mutable-list ie another StgMutClosure
137                       v
138                       +---------
139                       | RBH_SAVE with 0-2 words of DATA
140                       +---------
141   */
142
143   return closure;
144 }
145
146 /*
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.
151
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.
156
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 
165 */
166
167 # if defined(PAR)
168
169 EXTFUN(FETCH_ME_info);
170
171 //@cindex convertToFetchMe
172 void
173 convertToFetchMe(rbh, ga)
174 StgRBH *rbh;
175 globalAddr *ga;
176 {
177   // StgInfoTable *ip = get_itbl(rbh);
178   StgBlockingQueueElement *bqe = rbh->blocking_queue;
179
180   ASSERT(get_itbl(rbh)->type==RBH);
181
182   IF_PAR_DEBUG(pack,
183                belch(":*   Converting RBH %p (%s) into a FETCH_ME for GA ((%x, %d, %x))",
184                      rbh, info_type(rbh), 
185                      ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight)); 
186
187   /* put closure on mutables list, while it is still a RBH */
188   //recordMutable((StgMutClosure *)rbh);
189
190   /* actually turn it into a FETCH_ME */
191   SET_INFO((StgClosure *)rbh, &FETCH_ME_info);
192
193   /* set the global pointer in the FETCH_ME closure to the given value */
194   ((StgFetchMe *)rbh)->ga = ga;
195
196   IF_PAR_DEBUG(pack,
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))); 
200
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);
204 }
205 # else  /* GRAN */
206 /* Prototype */
207 // void UnlinkFromMUT(StgPtr closure); 
208
209 /*
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.
213 */
214 void
215 convertFromRBH(closure)
216 StgClosure *closure;
217 {
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
221
222   IF_GRAN_DEBUG(pack,
223                 if (get_itbl(bqe)->type==TSO)
224                   sprintf(str, "%d (%p)", 
225                           ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
226                 else 
227                   strcpy(str, "empty");
228                 belch(":*   Reverting RBH %p (%s) into a ??? closure again; BQ start: %s",
229                       closure, info_type(closure), str));
230
231   ASSERT(get_itbl(closure)->type==RBH);
232
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);
236
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!)
240   */
241   SET_INFO(closure, REVERT_INFOPTR(get_itbl(closure)));
242
243   /* put closure on mutables list */
244   //recordMutable((StgMutClosure *)closure);
245
246 # if 0 /* rest of this fct */
247     /* ngoq ngo' */
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 */
252                                           /*     closure lives. */
253       CurrentProc = new_proc;
254
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);
259 #  endif
260
261       rbh_save = AwakenBlockingQueue(bqe);     /* AwakenBlockingQueue(bqe); */
262       CurrentProc = old_proc;
263     } else {
264         rbh_save = bqe;
265     }
266
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");
270       EXIT(EXIT_FAILURE);
271     } else {
272       closure[isSpec ? SPEC_HS : GEN_HS] = rbh_save[SPEC_HS];
273       closure[(isSpec ? SPEC_HS : GEN_HS) + 1] = rbh_save[SPEC_HS + 1];
274     }
275 # endif /* 0 */
276
277 # if 0 && (defined(GCap) || defined(GCgn))
278     /* ngoq ngo' */
279     /* If we convert from an RBH in the old generation,
280        we have to make sure it goes on the mutables list */
281
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;
286         }
287     }
288 # endif /* 0 */
289 }
290 #endif /* PAR */
291
292 /* Remove closure from the mutables list */
293 #if 0
294 /* ngoq ngo' */
295 void
296 UnlinkFromMUT(StgPtr closure) 
297 {
298   StgPtr curr = StorageMgrInfo.OldMutables, prev = NULL;
299
300   while (curr != NULL && curr != closure) {
301     ASSERT(MUT_LINK(curr)!=MUT_NOT_LINKED);
302     prev=curr;
303     curr=MUT_LINK(curr); 
304   }
305   if (curr==closure) {   
306    if (prev==NULL) 
307      StorageMgrInfo.OldMutables = MUT_LINK(curr);
308    else   
309      MUT_LINK(prev) = MUT_LINK(curr);
310    MUT_LINK(curr) = MUT_NOT_LINKED;
311   }
312
313 #  if 0 && (defined(GCap) || defined(GCgn))
314   {
315     closq newclos;
316     extern closq ex_RBH_q;
317
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;
322     if (ex_RBH_q!=NULL)
323       CLOS_PREV(ex_RBH_q) = newclos;
324     ex_RBH_q = newclos;
325   }
326 #  endif
327 }
328 #endif /* PAR */
329
330 #endif /* PAR || GRAN -- whole file */
331
332 //@node Index,  , Conversion Functions
333 //@section Index
334
335 //@index
336 //* convertToFetchMe::  @cindex\s-+convertToFetchMe
337 //* convertToRBH::  @cindex\s-+convertToRBH
338 //@end index