Do not link ghc stage1 using -threaded, only for stage2 or 3
[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 // So that we can detect when a finalizer illegally calls back into Haskell
26 rtsBool running_finalizers = rtsFalse;
27
28 void
29 runCFinalizer(StgVoid *fn, StgVoid *ptr, StgVoid *env, StgWord flag)
30 {
31     if (flag)
32         ((void (*)(void *, void *))fn)(env, ptr);
33     else
34         ((void (*)(void *))fn)(ptr);
35 }
36
37 void
38 runAllCFinalizers(StgWeak *list)
39 {
40     StgWeak *w;
41
42     running_finalizers = rtsTrue;
43
44     for (w = list; w; w = w->link) {
45         StgArrWords *farr;
46
47         farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
48
49         if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
50             runCFinalizer((StgVoid *)farr->payload[0],
51                           (StgVoid *)farr->payload[1],
52                           (StgVoid *)farr->payload[2],
53                           farr->payload[3]);
54     }
55
56     running_finalizers = rtsFalse;
57 }
58
59 /*
60  * scheduleFinalizers() is called on the list of weak pointers found
61  * to be dead after a garbage collection.  It overwrites each object
62  * with DEAD_WEAK, and creates a new thread to run the pending finalizers.
63  *
64  * This function is called just after GC.  The weak pointers on the
65  * argument list are those whose keys were found to be not reachable,
66  * however the value and finalizer fields have by now been marked live.
67  * The weak pointer object itself may not be alive - i.e. we may be
68  * looking at either an object in from-space or one in to-space.  It
69  * doesn't really matter either way.
70  *
71  * Pre-condition: sched_mutex _not_ held.
72  */
73
74 void
75 scheduleFinalizers(Capability *cap, StgWeak *list)
76 {
77     StgWeak *w;
78     StgTSO *t;
79     StgMutArrPtrs *arr;
80     nat n;
81
82     running_finalizers = rtsTrue;
83
84     // count number of finalizers, and kill all the weak pointers first...
85     n = 0;
86     for (w = list; w; w = w->link) { 
87         StgArrWords *farr;
88
89         // Better not be a DEAD_WEAK at this stage; the garbage
90         // collector removes DEAD_WEAKs from the weak pointer list.
91         ASSERT(w->header.info != &stg_DEAD_WEAK_info);
92
93         if (w->finalizer != &stg_NO_FINALIZER_closure) {
94             n++;
95         }
96
97         farr = (StgArrWords *)UNTAG_CLOSURE(w->cfinalizer);
98
99         if ((StgClosure *)farr != &stg_NO_FINALIZER_closure)
100             runCFinalizer((StgVoid *)farr->payload[0],
101                           (StgVoid *)farr->payload[1],
102                           (StgVoid *)farr->payload[2],
103                           farr->payload[3]);
104
105 #ifdef PROFILING
106         // A weak pointer is inherently used, so we do not need to call
107         // LDV_recordDead().
108         //
109         // Furthermore, when PROFILING is turned on, dead weak
110         // pointers are exactly as large as weak pointers, so there is
111         // no need to fill the slop, either.  See stg_DEAD_WEAK_info
112         // in StgMiscClosures.hc.
113 #endif
114         SET_HDR(w, &stg_DEAD_WEAK_info, w->header.prof.ccs);
115     }
116         
117     running_finalizers = rtsFalse;
118
119     // No finalizers to run?
120     if (n == 0) return;
121
122     debugTrace(DEBUG_weak, "weak: batching %d finalizers", n);
123
124     arr = (StgMutArrPtrs *)allocateLocal(cap, sizeofW(StgMutArrPtrs) + n);
125     TICK_ALLOC_PRIM(sizeofW(StgMutArrPtrs), n, 0);
126     SET_HDR(arr, &stg_MUT_ARR_PTRS_FROZEN_info, CCS_SYSTEM);
127     arr->ptrs = n;
128
129     n = 0;
130     for (w = list; w; w = w->link) {
131         if (w->finalizer != &stg_NO_FINALIZER_closure) {
132             arr->payload[n] = w->finalizer;
133             n++;
134         }
135     }
136
137     t = createIOThread(cap, 
138                        RtsFlags.GcFlags.initialStkSize, 
139                        rts_apply(cap,
140                            rts_apply(cap,
141                                (StgClosure *)runFinalizerBatch_closure,
142                                rts_mkInt(cap,n)), 
143                            (StgClosure *)arr)
144         );
145     scheduleThread(cap,t);
146 }