add Outputable instance for OccIfaceEq
[ghc-hetmet.git] / rts / parallel / RBH.c
1 /*
2   Time-stamp: <Tue Mar 13 2001 19:07:13 Stardate: [-30]6323.98 hwloidl>
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 //@node Externs and prototypes, Conversion Functions
39 //@section Externs and prototypes
40
41 EXTFUN(stg_RBH_Save_0_info);
42 EXTFUN(stg_RBH_Save_1_info);
43 EXTFUN(stg_RBH_Save_2_info);
44
45 //@node Conversion Functions, Index, Externs and prototypes
46 //@section Conversion Functions
47
48 /*
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. 
52 */
53 //@cindex convertToRBH
54 StgClosure *
55 convertToRBH(closure)
56 StgClosure *closure;
57 {
58   StgRBHSave *rbh_save;
59   StgInfoTable *info_ptr, *rbh_info_ptr, *old_info;
60   nat size, ptrs, nonptrs, vhs;
61   char str[80];
62
63   /*
64      Closure layout before this routine runs amuck:
65        +-------------------
66        |   HEADER   | DATA ...
67        +-------------------
68        | FIXED_HS   |
69   */
70   /* 
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
76      closure.  */
77   IF_GRAN_DEBUG(pack,
78                 belch("*>::   %p (%s): Converting closure into an RBH",
79                       closure, info_type(closure))); 
80   IF_PAR_DEBUG(pack,
81                 belch("*>::   %p (%s): Converting closure into an RBH",
82                       closure, info_type(closure))); 
83
84   ASSERT(closure_THUNK(closure));
85
86   IF_GRAN_DEBUG(pack,
87                 old_info = get_itbl(closure));
88
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! */
92
93   info_ptr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs, str);
94   ASSERT(size >= _HS+MIN_UPD_SIZE);
95
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;
99
100   /* Set the info_ptr for the rbh_Save closure according to the number of
101      pointers in the original */
102
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));
109
110   /* Init the blocking queue of the RBH and have it point to the saved data */
111   ((StgRBH *)closure)->blocking_queue = (StgBlockingQueueElement *)rbh_save;
112
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)));
116
117   /*
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
121   */
122   recordMutable((StgMutClosure *)closure);
123
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));
128
129   /*
130      Closure layout after this routine has run amuck:
131        +---------------------
132        | RBH-HEADER | |   |  ...
133        +--------------|---|--
134        | FIXED_HS   | |   v
135                       |   Mutable-list ie another StgMutClosure
136                       v
137                       +---------
138                       | RBH_SAVE with 0-2 words of DATA
139                       +---------
140   */
141
142   return closure;
143 }
144
145 /*
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.
150
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.
155
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 
164 */
165
166 # if defined(PAR)
167
168 EXTFUN(stg_FETCH_ME_info);
169
170 //@cindex convertToFetchMe
171 void
172 convertToFetchMe(rbh, ga)
173 StgRBH *rbh;
174 globalAddr *ga;
175 {
176   // StgInfoTable *ip = get_itbl(rbh);
177   StgBlockingQueueElement *bqe = rbh->blocking_queue;
178
179   ASSERT(get_itbl(rbh)->type==RBH);
180
181   IF_PAR_DEBUG(pack,
182                belch("**:: Converting RBH %p (%s) into a FETCH_ME for GA ((%x, %d, %x))",
183                      rbh, info_type(rbh), 
184                      ga->payload.gc.gtid, ga->payload.gc.slot, ga->weight)); 
185
186   /* put closure on mutables list, while it is still a RBH */
187   recordMutable((StgMutClosure *)rbh);
188
189   /* actually turn it into a FETCH_ME */
190   SET_INFO((StgClosure *)rbh, &stg_FETCH_ME_info);
191
192   /* set the global pointer in the FETCH_ME closure to the given value */
193   ((StgFetchMe *)rbh)->ga = ga;
194
195   IF_PAR_DEBUG(pack,
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))); 
199
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);
203 }
204 # else  /* GRAN */
205 /* Prototype */
206 // void UnlinkFromMUT(StgPtr closure); 
207
208 /*
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.
212 */
213 void
214 convertFromRBH(closure)
215 StgClosure *closure;
216 {
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
220
221   IF_GRAN_DEBUG(pack,
222                 if (get_itbl(bqe)->type==TSO)
223                   sprintf(str, "%d (%p)", 
224                           ((StgTSO *)bqe)->id, ((StgTSO *)bqe));
225                 else 
226                   strcpy(str, "empty");
227                 belch("*<:: Reverting RBH %p (%s) into a ??? closure again; BQ start: %s",
228                       closure, info_type(closure), str));
229
230   ASSERT(get_itbl(closure)->type==RBH);
231
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);
235
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!)
239   */
240   SET_INFO(closure, REVERT_INFOPTR(get_itbl(closure)));
241
242   /* put closure on mutables list */
243   recordMutable((StgMutClosure *)closure);
244
245 # if 0 /* rest of this fct */
246     /* ngoq ngo' */
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 */
251                                           /*     closure lives. */
252       CurrentProc = new_proc;
253
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);
258 #  endif
259
260       rbh_save = AwakenBlockingQueue(bqe);     /* AwakenBlockingQueue(bqe); */
261       CurrentProc = old_proc;
262     } else {
263         rbh_save = bqe;
264     }
265
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");
269       EXIT(EXIT_FAILURE);
270     } else {
271       closure[isSpec ? SPEC_HS : GEN_HS] = rbh_save[SPEC_HS];
272       closure[(isSpec ? SPEC_HS : GEN_HS) + 1] = rbh_save[SPEC_HS + 1];
273     }
274 # endif /* 0 */
275
276 # if 0 && (defined(GCap) || defined(GCgn))
277     /* ngoq ngo' */
278     /* If we convert from an RBH in the old generation,
279        we have to make sure it goes on the mutables list */
280
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;
285         }
286     }
287 # endif /* 0 */
288 }
289 #endif /* PAR */
290
291 /* Remove closure from the mutables list */
292 #if 0
293 /* ngoq ngo' */
294 void
295 UnlinkFromMUT(StgPtr closure) 
296 {
297   StgPtr curr = StorageMgrInfo.OldMutables, prev = NULL;
298
299   while (curr != NULL && curr != closure) {
300     ASSERT(MUT_LINK(curr)!=MUT_NOT_LINKED);
301     prev=curr;
302     curr=MUT_LINK(curr); 
303   }
304   if (curr==closure) {   
305    if (prev==NULL) 
306      StorageMgrInfo.OldMutables = MUT_LINK(curr);
307    else   
308      MUT_LINK(prev) = MUT_LINK(curr);
309    MUT_LINK(curr) = MUT_NOT_LINKED;
310   }
311
312 #  if 0 && (defined(GCap) || defined(GCgn))
313   {
314     closq newclos;
315     extern closq ex_RBH_q;
316
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;
321     if (ex_RBH_q!=NULL)
322       CLOS_PREV(ex_RBH_q) = newclos;
323     ex_RBH_q = newclos;
324   }
325 #  endif
326 }
327 #endif /* PAR */
328
329 #endif /* PAR || GRAN -- whole file */
330
331 //@node Index,  , Conversion Functions
332 //@section Index
333
334 //@index
335 //* convertToFetchMe::  @cindex\s-+convertToFetchMe
336 //* convertToRBH::  @cindex\s-+convertToRBH
337 //@end index