Refactoring and tidy up
[ghc-hetmet.git] / rts / sm / MarkWeak.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team 1998-2008
4  *
5  * Weak pointers and weak-like things in the GC
6  *
7  * Documentation on the architecture of the Garbage Collector can be
8  * found in the online commentary:
9  * 
10  *   http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/GC
11  *
12  * ---------------------------------------------------------------------------*/
13
14 #include "PosixSource.h"
15 #include "Rts.h"
16
17 #include "MarkWeak.h"
18 #include "GC.h"
19 #include "GCThread.h"
20 #include "GCTDecl.h"
21 #include "Evac.h"
22 #include "Trace.h"
23 #include "Schedule.h"
24 #include "Weak.h"
25 #include "Storage.h"
26 #include "Threads.h"
27
28 /* -----------------------------------------------------------------------------
29    Weak Pointers
30
31    traverse_weak_ptr_list is called possibly many times during garbage
32    collection.  It returns a flag indicating whether it did any work
33    (i.e. called evacuate on any live pointers).
34
35    Invariant: traverse_weak_ptr_list is called when the heap is in an
36    idempotent state.  That means that there are no pending
37    evacuate/scavenge operations.  This invariant helps the weak
38    pointer code decide which weak pointers are dead - if there are no
39    new live weak pointers, then all the currently unreachable ones are
40    dead.
41
42    For generational GC: we just don't try to finalize weak pointers in
43    older generations than the one we're collecting.  This could
44    probably be optimised by keeping per-generation lists of weak
45    pointers, but for a few weak pointers this scheme will work.
46
47    There are three distinct stages to processing weak pointers:
48
49    - weak_stage == WeakPtrs
50
51      We process all the weak pointers whos keys are alive (evacuate
52      their values and finalizers), and repeat until we can find no new
53      live keys.  If no live keys are found in this pass, then we
54      evacuate the finalizers of all the dead weak pointers in order to
55      run them.
56
57    - weak_stage == WeakThreads
58
59      Now, we discover which *threads* are still alive.  Pointers to
60      threads from the all_threads and main thread lists are the
61      weakest of all: a pointers from the finalizer of a dead weak
62      pointer can keep a thread alive.  Any threads found to be unreachable
63      are evacuated and placed on the resurrected_threads list so we 
64      can send them a signal later.
65
66    - weak_stage == WeakDone
67
68      No more evacuation is done.
69
70    -------------------------------------------------------------------------- */
71
72 /* Which stage of processing various kinds of weak pointer are we at?
73  * (see traverse_weak_ptr_list() below for discussion).
74  */
75 typedef enum { WeakPtrs, WeakThreads, WeakDone } WeakStage;
76 static WeakStage weak_stage;
77
78 /* Weak pointers
79  */
80 StgWeak *old_weak_ptr_list; // also pending finaliser list
81
82 // List of threads found to be unreachable
83 StgTSO *resurrected_threads;
84
85 static void resurrectUnreachableThreads (generation *gen);
86 static rtsBool tidyThreadList (generation *gen);
87
88 void
89 initWeakForGC(void)
90 {
91     old_weak_ptr_list = weak_ptr_list;
92     weak_ptr_list = NULL;
93     weak_stage = WeakPtrs;
94     resurrected_threads = END_TSO_QUEUE;
95 }
96
97 rtsBool 
98 traverseWeakPtrList(void)
99 {
100   StgWeak *w, **last_w, *next_w;
101   StgClosure *new;
102   rtsBool flag = rtsFalse;
103   const StgInfoTable *info;
104
105   switch (weak_stage) {
106
107   case WeakDone:
108       return rtsFalse;
109
110   case WeakPtrs:
111       /* doesn't matter where we evacuate values/finalizers to, since
112        * these pointers are treated as roots (iff the keys are alive).
113        */
114       gct->evac_gen_no = 0;
115       
116       last_w = &old_weak_ptr_list;
117       for (w = old_weak_ptr_list; w != NULL; w = next_w) {
118           
119           /* There might be a DEAD_WEAK on the list if finalizeWeak# was
120            * called on a live weak pointer object.  Just remove it.
121            */
122           if (w->header.info == &stg_DEAD_WEAK_info) {
123               next_w = ((StgDeadWeak *)w)->link;
124               *last_w = next_w;
125               continue;
126           }
127           
128           info = get_itbl(w);
129           switch (info->type) {
130
131           case WEAK:
132               /* Now, check whether the key is reachable.
133                */
134               new = isAlive(w->key);
135               if (new != NULL) {
136                   w->key = new;
137                   // evacuate the value and finalizer 
138                   evacuate(&w->value);
139                   evacuate(&w->finalizer);
140                   // remove this weak ptr from the old_weak_ptr list 
141                   *last_w = w->link;
142                   // and put it on the new weak ptr list 
143                   next_w  = w->link;
144                   w->link = weak_ptr_list;
145                   weak_ptr_list = w;
146                   flag = rtsTrue;
147
148                   debugTrace(DEBUG_weak, 
149                              "weak pointer still alive at %p -> %p",
150                              w, w->key);
151                   continue;
152               }
153               else {
154                   last_w = &(w->link);
155                   next_w = w->link;
156                   continue;
157               }
158
159           default:
160               barf("traverseWeakPtrList: not WEAK");
161           }
162       }
163       
164       /* If we didn't make any changes, then we can go round and kill all
165        * the dead weak pointers.  The old_weak_ptr list is used as a list
166        * of pending finalizers later on.
167        */
168       if (flag == rtsFalse) {
169           for (w = old_weak_ptr_list; w; w = w->link) {
170               evacuate(&w->finalizer);
171           }
172
173           // Next, move to the WeakThreads stage after fully
174           // scavenging the finalizers we've just evacuated.
175           weak_stage = WeakThreads;
176       }
177
178       return rtsTrue;
179
180   case WeakThreads:
181       /* Now deal with the step->threads lists, which behave somewhat like
182        * the weak ptr list.  If we discover any threads that are about to
183        * become garbage, we wake them up and administer an exception.
184        */
185   {
186       nat g;
187           
188       // Traverse thread lists for generations we collected...
189 //      ToDo when we have one gen per capability:
190 //      for (n = 0; n < n_capabilities; n++) {
191 //          if (tidyThreadList(&nurseries[n])) {
192 //              flag = rtsTrue;
193 //          }
194 //      }              
195       for (g = 0; g <= N; g++) {
196           if (tidyThreadList(&generations[g])) {
197               flag = rtsTrue;
198           }
199       }
200
201       /* If we evacuated any threads, we need to go back to the scavenger.
202        */
203       if (flag) return rtsTrue;
204
205       /* And resurrect any threads which were about to become garbage.
206        */
207       {
208           nat g;
209           for (g = 0; g <= N; g++) {
210               resurrectUnreachableThreads(&generations[g]);
211           }
212       }
213         
214       weak_stage = WeakDone;  // *now* we're done,
215       return rtsTrue;         // but one more round of scavenging, please
216   }
217       
218   default:
219       barf("traverse_weak_ptr_list");
220       return rtsTrue;
221   }
222 }
223   
224   static void resurrectUnreachableThreads (generation *gen)
225 {
226     StgTSO *t, *tmp, *next;
227
228     for (t = gen->old_threads; t != END_TSO_QUEUE; t = next) {
229         next = t->global_link;
230         
231         // ThreadFinished and ThreadComplete: we have to keep
232         // these on the all_threads list until they
233         // become garbage, because they might get
234         // pending exceptions.
235         switch (t->what_next) {
236         case ThreadKilled:
237         case ThreadComplete:
238             continue;
239         default:
240             tmp = t;
241             evacuate((StgClosure **)&tmp);
242             tmp->global_link = resurrected_threads;
243             resurrected_threads = tmp;
244         }
245     }
246 }
247
248 static rtsBool tidyThreadList (generation *gen)
249 {
250     StgTSO *t, *tmp, *next, **prev;
251     rtsBool flag = rtsFalse;
252
253     prev = &gen->old_threads;
254
255     for (t = gen->old_threads; t != END_TSO_QUEUE; t = next) {
256               
257         tmp = (StgTSO *)isAlive((StgClosure *)t);
258         
259         if (tmp != NULL) {
260             t = tmp;
261         }
262         
263         ASSERT(get_itbl(t)->type == TSO);
264         next = t->global_link;
265         
266         // if the thread is not masking exceptions but there are
267         // pending exceptions on its queue, then something has gone
268         // wrong.  However, pending exceptions are OK if there is an
269         // FFI call.
270         ASSERT(t->blocked_exceptions == END_BLOCKED_EXCEPTIONS_QUEUE
271                || t->why_blocked == BlockedOnCCall
272                || t->why_blocked == BlockedOnCCall_Interruptible
273                || (t->flags & TSO_BLOCKEX));
274         
275         if (tmp == NULL) {
276             // not alive (yet): leave this thread on the
277             // old_all_threads list.
278             prev = &(t->global_link);
279         } 
280         else {
281             // alive
282             *prev = next;
283             
284             // move this thread onto the correct threads list.
285             generation *new_gen;
286             new_gen = Bdescr((P_)t)->gen;
287             t->global_link = new_gen->threads;
288             new_gen->threads  = t;
289         }
290     }
291
292     return flag;
293 }
294
295 /* -----------------------------------------------------------------------------
296    Evacuate every weak pointer object on the weak_ptr_list, and update
297    the link fields.
298
299    ToDo: with a lot of weak pointers, this will be expensive.  We
300    should have a per-GC weak pointer list, just like threads.
301    -------------------------------------------------------------------------- */
302
303 void
304 markWeakPtrList ( void )
305 {
306   StgWeak *w, **last_w;
307
308   last_w = &weak_ptr_list;
309   for (w = weak_ptr_list; w; w = w->link) {
310       // w might be WEAK, EVACUATED, or DEAD_WEAK (actually CON_STATIC) here
311
312 #ifdef DEBUG
313       {   // careful to do this assertion only reading the info ptr
314           // once, because during parallel GC it might change under our feet.
315           const StgInfoTable *info;
316           info = w->header.info;
317           ASSERT(IS_FORWARDING_PTR(info)
318                  || info == &stg_DEAD_WEAK_info 
319                  || INFO_PTR_TO_STRUCT(info)->type == WEAK);
320       }
321 #endif
322
323       evacuate((StgClosure **)last_w);
324       w = *last_w;
325       if (w->header.info == &stg_DEAD_WEAK_info) {
326           last_w = &(((StgDeadWeak*)w)->link);
327       } else {
328           last_w = &(w->link);
329       }
330   }
331 }
332