[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / runtime / gum / RBH.lc
1 %
2 % (c) The AQUA/Parade Projects, Glasgow University, 1995
3 %
4 %************************************************************************
5 %*                                                                      *
6 \section[RBH.lc]{Revertible Black Hole Manipulation}
7 %*                                                                      *
8 %************************************************************************
9
10 \begin{code}
11 #ifdef PAR /* whole file */
12
13 #include "rtsdefs.h"
14 \end{code}
15
16 Turn a closure into a revertable 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
21 words of the closure.
22
23 \begin{code}
24 EXTFUN(RBH_Save_0_info);
25 EXTFUN(RBH_Save_1_info);
26 EXTFUN(RBH_Save_2_info);
27
28 P_
29 convertToRBH(closure)
30 P_ closure;
31 {
32     P_ infoPtr, newInfoPtr;
33     W_ size, ptrs, nonptrs, vhs;
34     P_  rbh_save;
35     int isSpec;
36
37     if ((rbh_save = AllocateHeap(SPEC_HS + 2)) == NULL)
38         return NULL;
39
40     infoPtr = get_closure_info(closure, &size, &ptrs, &nonptrs, &vhs);
41     ASSERT(size >= MIN_UPD_SIZE);
42
43     switch (BASE_INFO_TYPE(infoPtr)) {
44     case INFO_SPEC_TYPE:
45         isSpec = 1;
46         break;
47     case INFO_GEN_TYPE:
48         isSpec = 0;
49         break;
50     default:
51         fprintf(stderr, "Panic: turn %#lx (IP %#lx) into RBH\n", (W_)closure, (W_)infoPtr);
52         EXIT(EXIT_FAILURE);
53     }
54
55     /* Fill in the RBH_Save closure with the original data */
56     rbh_save[SPEC_HS] = closure[isSpec ? SPEC_HS : GEN_HS];
57     rbh_save[SPEC_HS + 1] = closure[(isSpec ? SPEC_HS : GEN_HS) + 1];
58
59     /*
60      * Set the info_ptr for the rbh_Save closure according to the number of pointers
61      * in the original
62      */
63
64     newInfoPtr = (P_) (ptrs == 0 ? RBH_Save_0_info :
65                        ptrs == 1 ? RBH_Save_1_info :
66                        RBH_Save_2_info);
67     SET_INFO_PTR(rbh_save, newInfoPtr);
68
69     /* Do some magic garbage collection mangling on the first word */
70
71 #if defined(GCap) || defined(GCgn)
72
73     /*
74      * If the closure's in the old generation, we have to make sure it goes on the
75      * mutables list
76      */
77
78     if (closure <= StorageMgrInfo.OldLim) {
79         MUT_LINK(closure) = (W_) StorageMgrInfo.OldMutables;
80         StorageMgrInfo.OldMutables = closure;
81     } else
82         MUT_LINK(closure) = MUT_NOT_LINKED;
83 #endif
84
85     /*
86      * Second word points to the RBH_Save closure with the original data. This may
87      * become a blocking queue terminated by the RBH_Save closure.
88      */
89     if (isSpec)
90         SPEC_RBH_BQ(closure) = (W_) rbh_save;
91     else
92         GEN_RBH_BQ(closure) = (W_) rbh_save;
93
94     /* OK, now actually turn it into a RBH (what a great system!) */
95     SET_INFO_PTR(closure, RBH_INFOPTR(INFO_PTR(closure)));
96
97     return closure;
98 }
99
100 \end{code}
101
102 Converting a closure to a FetchMe is trivial, unless the closure has
103 acquired a blocking queue.  If that has happened, we first have to
104 awaken the blocking queue.  What a nuisance!  Fortunately,
105 @AwakenBlockingQueue@ should now know what to do.
106
107 \begin{code}
108 EXTDATA_RO(FetchMe_info);
109
110 void
111 convertToFetchMe(closure, ga)
112 P_ closure;
113 globalAddr *ga;
114 {
115     P_ ip = (P_) INFO_PTR(closure);
116     P_ bqe;
117 #if defined(GCap) || defined(GCgn)    
118     rtsBool linked = IS_MUTABLE(ip) && MUT_LINK(closure) != MUT_NOT_LINKED;
119 #endif
120
121     switch(INFO_TYPE(ip)) {
122     case INFO_SPEC_RBH_TYPE:
123         bqe = (P_) SPEC_RBH_BQ(closure);
124         break;
125     case INFO_GEN_RBH_TYPE:
126         bqe = (P_) GEN_RBH_BQ(closure);
127         break;
128     default:
129 #ifdef DEBUG
130         fprintf(stderr, "Weird...just tried to convert %#lx (IP %#lx) to FetchMe\n",
131           closure, ip);
132 #endif
133         return;
134     }
135
136     SET_INFO_PTR(closure, FetchMe_info);
137
138 #if defined(GCap) || defined(GCgn)
139     /* If we modify a fetchme in the old generation,
140        we have to make sure it goes on the mutables list */
141
142     if(closure <= StorageMgrInfo.OldLim) {
143         if (!linked) {
144             MUT_LINK(closure) = (W_) StorageMgrInfo.OldMutables;
145             StorageMgrInfo.OldMutables = closure;
146         }
147     } else
148         MUT_LINK(closure) = MUT_NOT_LINKED;
149 #endif
150     
151     FETCHME_GA(closure) = ga;
152     if (IS_MUTABLE(INFO_PTR(bqe)))
153         AwakenBlockingQueue(bqe);
154 }
155
156 #endif /* PAR -- whole file */
157 \end{code}