Remove trailing whitespace from HaddockUtils
[ghc-hetmet.git] / rts / Weak.c
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-1999
4  *
5  * Weak pointers / finalizers
6  *
7  * ---------------------------------------------------------------------------*/
8
9 #include "PosixSource.h"
10 #include "Rts.h"
11 #include "RtsUtils.h"
12 #include "SchedAPI.h"
13 #include "RtsFlags.h"
14 #include "Weak.h"
15 #include "Schedule.h"
16 #include "Prelude.h"
17 #include "RtsAPI.h"
18 #include "Trace.h"
19
20 // ForeignPtrs with C finalizers rely on weak pointers inside weak_ptr_list
21 // to always be in the same order.
22
23 StgWeak *weak_ptr_list;
24
25 void
26 runCFinalizer(StgVoid *fn, StgVoid *ptr, StgVoid *env, StgWord flag)
27 {
28     if (flag)
29         ((void (*)(void *, void *))fn)(env, ptr);
30     else
31         ((void (*)(void *))fn)(ptr);
32 }
33
34 void
35 runAllCFinalizers(StgWeak *list)
36 {
37     StgWeak *w;
38
39     for (w = list; w; w = w->link) {
40         StgArrWords *farr;
41
42         farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
43
44         if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
45             runCFinalizer((StgVoid *)farr->payload[0],
46                           (StgVoid *)farr->payload[1],
47                           (StgVoid *)farr->payload[2],
48                           farr->payload[3]);
49     }
50 }
51
52 /*
53  * scheduleFinalizers() is called on the list of weak pointers found
54  * to be dead after a garbage collection.  It overwrites each object
55  * with DEAD_WEAK, and creates a new thread to run the pending finalizers.
56  *
57  * This function is called just after GC.  The weak pointers on the
58  * argument list are those whose keys were found to be not reachable,
59  * however the value and finalizer fields have by now been marked live.
60  * The weak pointer object itself may not be alive - i.e. we may be
61  * looking at either an object in from-space or one in to-space.  It
62  * doesn't really matter either way.
63  *
64  * Pre-condition: sched_mutex _not_ held.
65  */
66
67 void
68 scheduleFinalizers(Capability *cap, StgWeak *list)
69 {
70     StgWeak *w;
71     StgTSO *t;
72     StgMutArrPtrs *arr;
73     nat n;
74
75     // count number of finalizers, and kill all the weak pointers first...
76     n = 0;
77     for (w = list; w; w = w->link) { 
78         StgArrWords *farr;
79
80         // Better not be a DEAD_WEAK at this stage; the garbage
81         // collector removes DEAD_WEAKs from the weak pointer list.
82         ASSERT(w->header.info != &stg_DEAD_WEAK_info);
83
84         if (w->finalizer != &stg_NO_FINALIZER_closure) {
85             n++;
86         }
87
88         farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
89
90         if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
91             runCFinalizer((StgVoid *)farr->payload[0],
92                           (StgVoid *)farr->payload[1],
93                           (StgVoid *)farr->payload[2],
94                           farr->payload[3]);
95
96 #ifdef PROFILING
97         // A weak pointer is inherently used, so we do not need to call
98         // LDV_recordDead().
99         //
100         // Furthermore, when PROFILING is turned on, dead weak
101         // pointers are exactly as large as weak pointers, so there is
102         // no need to fill the slop, either.  See stg_DEAD_WEAK_info
103         // in StgMiscClosures.hc.
104 #endif
105         SET_HDR(w, &stg_DEAD_WEAK_info, w->header.prof.ccs);
106     }
107         
108     // No finalizers to run?
109     if (n == 0) return;
110
111     debugTrace(DEBUG_weak, "weak: batching %d finalizers", n);
112
113     arr = (StgMutArrPtrs *)allocateLocal(cap, sizeofW(StgMutArrPtrs) + n);
114     TICK_ALLOC_PRIM(sizeofW(StgMutArrPtrs), n, 0);
115     SET_HDR(arr, &stg_MUT_ARR_PTRS_FROZEN_info, CCS_SYSTEM);
116     arr->ptrs = n;
117
118     n = 0;
119     for (w = list; w; w = w->link) {
120         if (w->finalizer != &stg_NO_FINALIZER_closure) {
121             arr->payload[n] = w->finalizer;
122             n++;
123         }
124     }
125
126     t = createIOThread(cap, 
127                        RtsFlags.GcFlags.initialStkSize, 
128                        rts_apply(cap,
129                            rts_apply(cap,
130                                (StgClosure *)runFinalizerBatch_closure,
131                                rts_mkInt(cap,n)), 
132                            (StgClosure *)arr)
133         );
134     scheduleThread(cap,t);
135 }