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  *   https://gitlab.haskell.org/ghc/ghc/wikis/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 #include "sm/GCUtils.h"
29 #include "sm/MarkWeak.h"
30 #include "sm/Sanity.h"
31 
32 /* -----------------------------------------------------------------------------
33    Weak Pointers
34 
35    traverseWeakPtrList is called possibly many times during garbage
36    collection.  It returns a flag indicating whether it did any work
37    (i.e. called evacuate on any live pointers).
38 
39    Invariant: traverseWeakPtrList is called when the heap is in an
40    idempotent state.  That means that there are no pending
41    evacuate/scavenge operations.  This invariant helps the weak
42    pointer code decide which weak pointers are dead - if there are no
43    new live weak pointers, then all the currently unreachable ones are
44    dead.
45 
46    For generational GC: we don't try to finalize weak pointers in
47    older generations than the one we're collecting.
48 
49    There are three distinct stages to processing weak pointers:
50 
51    - weak_stage == WeakPtrs
52 
53      We process all the weak pointers whos keys are alive (evacuate
54      their values and finalizers), and repeat until we can find no new
55      live keys.  If no live keys are found in this pass, then we
56      evacuate the finalizers of all the dead weak pointers in order to
57      run them.
58 
59    - weak_stage == WeakThreads
60 
61      Now, we discover which *threads* are still alive.  Pointers to
62      threads from the all_threads and main thread lists are the
63      weakest of all: a pointer from the finalizer of a dead weak
64      pointer can keep a thread alive.  Any threads found to be unreachable
65      are evacuated and placed on the resurrected_threads list so we
66      can send them a signal later.
67 
68    - weak_stage == WeakDone
69 
70      No more evacuation is done.
71 
72    -------------------------------------------------------------------------- */
73 
74 /* Which stage of processing various kinds of weak pointer are we at?
75  * (see traverseWeakPtrList() below for discussion).
76  */
77 typedef enum { WeakPtrs, WeakThreads, WeakDone } WeakStage;
78 static WeakStage weak_stage;
79 
80 static void    collectDeadWeakPtrs (generation *gen, StgWeak **dead_weak_ptr_list);
81 static bool tidyWeakList (generation *gen);
82 static bool resurrectUnreachableThreads (generation *gen, StgTSO **resurrected_threads);
83 static void    tidyThreadList (generation *gen);
84 
85 void
initWeakForGC(void)86 initWeakForGC(void)
87 {
88     uint32_t g;
89 
90     for (g = 0; g <= N; g++) {
91         generation *gen = &generations[g];
92         gen->old_weak_ptr_list = gen->weak_ptr_list;
93         gen->weak_ptr_list = NULL;
94     }
95 
96     weak_stage = WeakThreads;
97 }
98 
99 bool
traverseWeakPtrList(StgWeak ** dead_weak_ptr_list,StgTSO ** resurrected_threads)100 traverseWeakPtrList(StgWeak **dead_weak_ptr_list, StgTSO **resurrected_threads)
101 {
102   bool flag = false;
103 
104   switch (weak_stage) {
105 
106   case WeakDone:
107       return false;
108 
109   case WeakThreads:
110       /* Now deal with the gen->threads lists, which behave somewhat like
111        * the weak ptr list.  If we discover any threads that are about to
112        * become garbage, we wake them up and administer an exception.
113        */
114   {
115       uint32_t g;
116 
117       for (g = 0; g <= N; g++) {
118           tidyThreadList(&generations[g]);
119       }
120 
121       // Use weak pointer relationships (value is reachable if
122       // key is reachable):
123       for (g = 0; g <= N; g++) {
124           if (tidyWeakList(&generations[g])) {
125               flag = true;
126           }
127       }
128 
129       // if we evacuated anything new, we must scavenge thoroughly
130       // before we can determine which threads are unreachable.
131       if (flag) return true;
132 
133       // Resurrect any threads which were unreachable
134       for (g = 0; g <= N; g++) {
135           if (resurrectUnreachableThreads(&generations[g], resurrected_threads)) {
136               flag = true;
137           }
138       }
139 
140       // Next, move to the WeakPtrs stage after fully
141       // scavenging the finalizers we've just evacuated.
142       weak_stage = WeakPtrs;
143 
144       // if we evacuated anything new, we must scavenge thoroughly
145       // before entering the WeakPtrs stage.
146       if (flag) return true;
147 
148       // otherwise, fall through...
149   }
150   FALLTHROUGH;
151 
152   case WeakPtrs:
153   {
154       uint32_t g;
155 
156       // resurrecting threads might have made more weak pointers
157       // alive, so traverse those lists again:
158       for (g = 0; g <= N; g++) {
159           if (tidyWeakList(&generations[g])) {
160               flag = true;
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 dead_weak_ptr list is used as a list
166        * of pending finalizers later on.
167        */
168       if (flag == false) {
169           for (g = 0; g <= N; g++) {
170               collectDeadWeakPtrs(&generations[g], dead_weak_ptr_list);
171           }
172 
173           weak_stage = WeakDone;  // *now* we're done,
174       }
175 
176       return true;         // but one more round of scavenging, please
177   }
178 
179   default:
180       barf("traverseWeakPtrList");
181       return true;
182   }
183 }
184 
collectDeadWeakPtrs(generation * gen,StgWeak ** dead_weak_ptr_list)185 static void collectDeadWeakPtrs (generation *gen, StgWeak **dead_weak_ptr_list)
186 {
187     StgWeak *w, *next_w;
188     for (w = gen->old_weak_ptr_list; w != NULL; w = next_w) {
189         // If we have C finalizers, keep the value alive for this GC.
190         // See Note [MallocPtr finalizers] in GHC.ForeignPtr, and #10904
191         if (w->cfinalizers != &stg_NO_FINALIZER_closure) {
192             evacuate(&w->value);
193         }
194         evacuate(&w->finalizer);
195         next_w = w->link;
196         w->link = *dead_weak_ptr_list;
197         *dead_weak_ptr_list = w;
198     }
199 }
200 
resurrectUnreachableThreads(generation * gen,StgTSO ** resurrected_threads)201 static bool resurrectUnreachableThreads (generation *gen, StgTSO **resurrected_threads)
202 {
203     StgTSO *t, *tmp, *next;
204     bool flag = false;
205 
206     for (t = gen->old_threads; t != END_TSO_QUEUE; t = next) {
207         next = t->global_link;
208 
209         // ThreadFinished and ThreadComplete: we have to keep
210         // these on the all_threads list until they
211         // become garbage, because they might get
212         // pending exceptions.
213         switch (t->what_next) {
214         case ThreadKilled:
215         case ThreadComplete:
216             // The thread was unreachable so far, but it might still end up
217             // being reachable later, e.g. after collectDeadWeakPtrs(). We don't
218             // want the global_link field to be dangling in that case, so reset
219             // it to END_TSO_QUEUE. The copying GC doesn't currently care, but
220             // the compacting GC does, see #17785.
221             t->global_link = END_TSO_QUEUE;
222             continue;
223         default:
224             tmp = t;
225             evacuate((StgClosure **)&tmp);
226             tmp->global_link = *resurrected_threads;
227             *resurrected_threads = tmp;
228             flag = true;
229         }
230     }
231 
232     gen->old_threads = END_TSO_QUEUE;
233     return flag;
234 }
235 
tidyWeakList(generation * gen)236 static bool tidyWeakList(generation *gen)
237 {
238     StgWeak *w, **last_w, *next_w;
239     const StgInfoTable *info;
240     StgClosure *new;
241     bool flag = false;
242     last_w = &gen->old_weak_ptr_list;
243     for (w = gen->old_weak_ptr_list; w != NULL; w = next_w) {
244 
245         info = w->header.info;
246         /* N.B. This function is executed only during the serial part of GC
247          * so consequently there is no potential for data races and therefore
248          * no need for memory barriers.
249          */
250 
251         /* There might be a DEAD_WEAK on the list if finalizeWeak# was
252          * called on a live weak pointer object.  Just remove it.
253          */
254         if (info == &stg_DEAD_WEAK_info) {
255             next_w = w->link;
256             *last_w = next_w;
257             continue;
258         }
259 
260         info = INFO_PTR_TO_STRUCT(info);
261         switch (info->type) {
262 
263         case WEAK:
264             /* Now, check whether the key is reachable.
265              */
266             new = isAlive(w->key);
267             if (new != NULL) {
268                 generation *new_gen;
269 
270                 w->key = new;
271 
272                 // Find out which generation this weak ptr is in, and
273                 // move it onto the weak ptr list of that generation.
274 
275                 new_gen = Bdescr((P_)w)->gen;
276                 gct->evac_gen_no = new_gen->no;
277                 gct->failed_to_evac = false;
278 
279                 // evacuate the fields of the weak ptr
280                 scavengeLiveWeak(w);
281 
282                 if (gct->failed_to_evac) {
283                     debugTrace(DEBUG_weak,
284                                "putting weak pointer %p into mutable list",
285                                w);
286                     gct->failed_to_evac = false;
287                     recordMutableGen_GC((StgClosure *)w, new_gen->no);
288                 }
289 
290                 // remove this weak ptr from the old_weak_ptr list
291                 *last_w = w->link;
292                 next_w  = w->link;
293 
294                 // and put it on the correct weak ptr list.
295                 w->link = new_gen->weak_ptr_list;
296                 new_gen->weak_ptr_list = w;
297                 flag = true;
298 
299                 if (gen->no != new_gen->no) {
300                     debugTrace(DEBUG_weak,
301                       "moving weak pointer %p from %d to %d",
302                       w, gen->no, new_gen->no);
303                 }
304 
305 
306                 debugTrace(DEBUG_weak,
307                            "weak pointer still alive at %p -> %p",
308                            w, w->key);
309                 continue;
310             }
311             else {
312                 last_w = &(w->link);
313                 next_w = w->link;
314                 continue;
315             }
316 
317         default:
318             barf("tidyWeakList: not WEAK: %d, %p", info->type, w);
319         }
320     }
321 
322     return flag;
323 }
324 
tidyThreadList(generation * gen)325 static void tidyThreadList (generation *gen)
326 {
327     StgTSO *t, *tmp, *next, **prev;
328 
329     prev = &gen->old_threads;
330 
331     for (t = gen->old_threads; t != END_TSO_QUEUE; t = next) {
332 
333         tmp = (StgTSO *)isAlive((StgClosure *)t);
334 
335         if (tmp != NULL) {
336             t = tmp;
337         }
338 
339         ASSERT(get_itbl((StgClosure *)t)->type == TSO);
340         next = t->global_link;
341 
342         // if the thread is not masking exceptions but there are
343         // pending exceptions on its queue, then something has gone
344         // wrong.  However, pending exceptions are OK if there is an
345         // FFI call.
346         ASSERT(t->blocked_exceptions == END_BLOCKED_EXCEPTIONS_QUEUE
347                || t->why_blocked == BlockedOnCCall
348                || t->why_blocked == BlockedOnCCall_Interruptible
349                || (t->flags & TSO_BLOCKEX));
350 
351         if (tmp == NULL) {
352             // not alive (yet): leave this thread on the
353             // old_threads list.
354             prev = &(t->global_link);
355         }
356         else {
357             // alive
358             *prev = next;
359 
360             // move this thread onto the correct threads list.
361             generation *new_gen;
362             new_gen = Bdescr((P_)t)->gen;
363             t->global_link = new_gen->threads;
364             new_gen->threads  = t;
365         }
366     }
367 }
368 
369 #if defined(DEBUG)
checkWeakPtrSanity(StgWeak * hd,StgWeak * tl)370 static void checkWeakPtrSanity(StgWeak *hd, StgWeak *tl)
371 {
372     StgWeak *w, *prev;
373     for (prev = NULL, w = hd; w != NULL; prev = w, w = w->link) {
374         ASSERT(INFO_PTR_TO_STRUCT(UNTAG_CLOSURE((StgClosure*)w)->header.info)->type == WEAK
375             || UNTAG_CLOSURE((StgClosure*)w)->header.info == &stg_DEAD_WEAK_info);
376         checkClosure((StgClosure*)w);
377     }
378     if (tl != NULL) {
379         ASSERT(prev == tl);
380     }
381 }
382 #endif
383 
collectFreshWeakPtrs()384 void collectFreshWeakPtrs()
385 {
386     uint32_t i;
387     // move recently allocated weak_ptr_list to the old list as well
388     for (i = 0; i < n_capabilities; i++) {
389         Capability *cap = capabilities[i];
390         if (cap->weak_ptr_list_tl != NULL) {
391             IF_DEBUG(sanity, checkWeakPtrSanity(cap->weak_ptr_list_hd, cap->weak_ptr_list_tl));
392             cap->weak_ptr_list_tl->link = g0->weak_ptr_list;
393             g0->weak_ptr_list = cap->weak_ptr_list_hd;
394             cap->weak_ptr_list_tl = NULL;
395             cap->weak_ptr_list_hd = NULL;
396         } else {
397             ASSERT(cap->weak_ptr_list_hd == NULL);
398         }
399     }
400 }
401 
402 /* -----------------------------------------------------------------------------
403    Evacuate every weak pointer object on the weak_ptr_list, and update
404    the link fields.
405    -------------------------------------------------------------------------- */
406 
407 void
markWeakPtrList(void)408 markWeakPtrList ( void )
409 {
410     uint32_t g;
411 
412     for (g = 0; g <= N; g++) {
413         generation *gen = &generations[g];
414         StgWeak *w, **last_w;
415 
416         last_w = &gen->weak_ptr_list;
417         for (w = gen->weak_ptr_list; w != NULL; w = RELAXED_LOAD(&w->link)) {
418             // w might be WEAK, EVACUATED, or DEAD_WEAK (actually CON_STATIC) here
419 
420 #if defined(DEBUG)
421             {   // careful to do this assertion only reading the info ptr
422                 // once, because during parallel GC it might change under our feet.
423                 const StgInfoTable *info = RELAXED_LOAD(&w->header.info);
424                 ASSERT(IS_FORWARDING_PTR(info)
425                        || info == &stg_DEAD_WEAK_info
426                        || INFO_PTR_TO_STRUCT(info)->type == WEAK);
427             }
428 #endif
429 
430             evacuate((StgClosure **)last_w);
431             w = *last_w;
432             last_w = &(w->link);
433         }
434     }
435 }
436 
437 /* -----------------------------------------------------------------------------
438    Fully scavenge a known-to-be-alive weak pointer.
439 
440    In scavenge_block, we only partially scavenge a weak pointer because it may
441    turn out to be dead. This function should be called when we decide that the
442    weak pointer is alive after this GC.
443    -------------------------------------------------------------------------- */
444 
445 void
scavengeLiveWeak(StgWeak * w)446 scavengeLiveWeak(StgWeak *w)
447 {
448     evacuate(&w->value);
449     evacuate(&w->key);
450     evacuate(&w->finalizer);
451     evacuate(&w->cfinalizers);
452 }
453