CNF: Silence pointer fix-up message unless gc debugging is enabled
[ghc.git] / rts / Weak.c
index a50a72e..f3e91fb 100644 (file)
@@ -8,44 +8,55 @@
 
 #include "PosixSource.h"
 #include "Rts.h"
+#include "RtsAPI.h"
+
 #include "RtsUtils.h"
-#include "SchedAPI.h"
-#include "RtsFlags.h"
 #include "Weak.h"
 #include "Schedule.h"
 #include "Prelude.h"
-#include "RtsAPI.h"
 #include "Trace.h"
 
-// ForeignPtrs with C finalizers rely on weak pointers inside weak_ptr_list
-// to always be in the same order.
-
-StgWeak *weak_ptr_list;
-
 void
-runCFinalizer(StgVoid *fn, StgVoid *ptr, StgVoid *env, StgWord flag)
+runCFinalizers(StgCFinalizerList *list)
 {
-    if (flag)
-       ((void (*)(void *, void *))fn)(env, ptr);
-    else
-       ((void (*)(void *))fn)(ptr);
+    StgCFinalizerList *head;
+    for (head = list;
+        (StgClosure *)head != &stg_NO_FINALIZER_closure;
+        head = (StgCFinalizerList *)head->link)
+    {
+        if (head->flag)
+            ((void (*)(void *, void *))head->fptr)(head->eptr, head->ptr);
+        else
+            ((void (*)(void *))head->fptr)(head->ptr);
+    }
 }
 
 void
 runAllCFinalizers(StgWeak *list)
 {
     StgWeak *w;
+    Task *task;
 
-    for (w = list; w; w = w->link) {
-       StgArrWords *farr;
+    task = myTask();
+    if (task != NULL) {
+        task->running_finalizers = true;
+    }
 
-       farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
+    for (w = list; w; w = w->link) {
+        // We need to filter out DEAD_WEAK objects, because it's not guaranteed
+        // that the list will not have them when shutting down.
+        // They only get filtered out during GC for the generation they
+        // belong to.
+        // If there's no major GC between the time that the finalizer for the
+        // object from the oldest generation is manually called and shutdown
+        // we end up running the same finalizer twice. See #7170.
+        if (w->header.info != &stg_DEAD_WEAK_info) {
+            runCFinalizers((StgCFinalizerList *)w->cfinalizers);
+        }
+    }
 
-       if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
-           runCFinalizer((StgVoid *)farr->payload[0],
-                         (StgVoid *)farr->payload[1],
-                         (StgVoid *)farr->payload[2],
-                         farr->payload[3]);
+    if (task != NULL) {
+        task->running_finalizers = false;
     }
 }
 
@@ -70,66 +81,75 @@ scheduleFinalizers(Capability *cap, StgWeak *list)
     StgWeak *w;
     StgTSO *t;
     StgMutArrPtrs *arr;
-    nat n;
+    StgWord size;
+    uint32_t n, i;
+    Task *task;
+
+    task = myTask();
+    if (task != NULL) {
+        task->running_finalizers = true;
+    }
 
     // count number of finalizers, and kill all the weak pointers first...
     n = 0;
-    for (w = list; w; w = w->link) { 
-       StgArrWords *farr;
-
-       // Better not be a DEAD_WEAK at this stage; the garbage
-       // collector removes DEAD_WEAKs from the weak pointer list.
-       ASSERT(w->header.info != &stg_DEAD_WEAK_info);
-
-       if (w->finalizer != &stg_NO_FINALIZER_closure) {
-           n++;
-       }
+    for (w = list; w; w = w->link) {
+        // Better not be a DEAD_WEAK at this stage; the garbage
+        // collector removes DEAD_WEAKs from the weak pointer list.
+        ASSERT(w->header.info != &stg_DEAD_WEAK_info);
 
-       farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
+        if (w->finalizer != &stg_NO_FINALIZER_closure) {
+            n++;
+        }
 
-       if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
-           runCFinalizer((StgVoid *)farr->payload[0],
-                         (StgVoid *)farr->payload[1],
-                         (StgVoid *)farr->payload[2],
-                         farr->payload[3]);
+        runCFinalizers((StgCFinalizerList *)w->cfinalizers);
 
-#ifdef PROFILING
+#if defined(PROFILING)
         // A weak pointer is inherently used, so we do not need to call
         // LDV_recordDead().
-       //
+        //
         // Furthermore, when PROFILING is turned on, dead weak
         // pointers are exactly as large as weak pointers, so there is
         // no need to fill the slop, either.  See stg_DEAD_WEAK_info
-        // in StgMiscClosures.hc.
+        // in StgMiscClosures.cmm.
 #endif
-       SET_HDR(w, &stg_DEAD_WEAK_info, w->header.prof.ccs);
+        SET_HDR(w, &stg_DEAD_WEAK_info, w->header.prof.ccs);
     }
-       
+
+    if (task != NULL) {
+        task->running_finalizers = false;
+    }
+
     // No finalizers to run?
     if (n == 0) return;
 
     debugTrace(DEBUG_weak, "weak: batching %d finalizers", n);
 
-    arr = (StgMutArrPtrs *)allocateLocal(cap, sizeofW(StgMutArrPtrs) + n);
+    size = n + mutArrPtrsCardTableSize(n);
+    arr = (StgMutArrPtrs *)allocate(cap, sizeofW(StgMutArrPtrs) + size);
     TICK_ALLOC_PRIM(sizeofW(StgMutArrPtrs), n, 0);
     SET_HDR(arr, &stg_MUT_ARR_PTRS_FROZEN_info, CCS_SYSTEM);
     arr->ptrs = n;
+    arr->size = size;
 
     n = 0;
     for (w = list; w; w = w->link) {
-       if (w->finalizer != &stg_NO_FINALIZER_closure) {
-           arr->payload[n] = w->finalizer;
-           n++;
-       }
+        if (w->finalizer != &stg_NO_FINALIZER_closure) {
+            arr->payload[n] = w->finalizer;
+            n++;
+        }
+    }
+    // set all the cards to 1
+    for (i = n; i < size; i++) {
+        arr->payload[i] = (StgClosure *)(W_)(-1);
     }
 
-    t = createIOThread(cap, 
-                      RtsFlags.GcFlags.initialStkSize, 
-                      rts_apply(cap,
-                          rts_apply(cap,
-                              (StgClosure *)runFinalizerBatch_closure,
-                              rts_mkInt(cap,n)), 
-                          (StgClosure *)arr)
-       );
+    t = createIOThread(cap,
+                       RtsFlags.GcFlags.initialStkSize,
+                       rts_apply(cap,
+                           rts_apply(cap,
+                               (StgClosure *)runFinalizerBatch_closure,
+                               rts_mkInt(cap,n)),
+                           (StgClosure *)arr)
+        );
     scheduleThread(cap,t);
 }