c80cf8c3c1b9f364e8795b6edab226ae9a1e5fe9
[ghc-hetmet.git] / ghc / rts / Weak.c
1 /* -----------------------------------------------------------------------------
2  * $Id: Weak.c,v 1.19 2001/11/22 14:25:13 simonmar Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Weak pointers / finalizers
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #include "PosixSource.h"
11 #include "Rts.h"
12 #include "RtsAPI.h"
13 #include "SchedAPI.h"
14 #include "RtsFlags.h"
15 #include "Weak.h"
16 #include "Storage.h"
17 #include "Prelude.h"
18
19 StgWeak *weak_ptr_list;
20
21 /*
22  * finalizeWeakPointersNow() is called just before the system is shut
23  * down.  It runs the finalizer for each weak pointer still in the
24  * system.
25  *
26  * Careful here - rts_evalIO might cause a garbage collection, which
27  * might change weak_ptr_list.  Must re-load weak_ptr_list each time
28  * around the loop.
29  */
30
31 void
32 finalizeWeakPointersNow(void)
33 {
34   StgWeak *w;
35   
36   while ((w = weak_ptr_list)) {
37     weak_ptr_list = w->link;
38     if (w->header.info != &stg_DEAD_WEAK_info) {
39         // @LDV profiling
40         // Even thought the info type of w changes, we DO NOT perform any
41         // LDV profiling because at this moment, LDV profiling must already
42         // have been terminated. See the comments in shutdownHaskell().
43         // At any rate, there is no need to call LDV_recordDead() because
44         // weak pointers are inherently used.
45 #ifdef PROFILING
46         ASSERT(ldvTime == 0);   // LDV profiling is turned off.
47 #endif
48         w->header.info = &stg_DEAD_WEAK_info;
49         IF_DEBUG(weak,fprintf(stderr,"Finalising weak pointer at %p -> %p\n", w, w->key));
50         if (w->finalizer != &stg_NO_FINALIZER_closure) {
51             rts_evalIO(w->finalizer,NULL);
52         }
53     }
54   }
55
56
57 /*
58  * scheduleFinalizers() is called on the list of weak pointers found
59  * to be dead after a garbage collection.  It overwrites each object
60  * with DEAD_WEAK, and creates a new thread to run the pending finalizers.
61  *
62  * This function is called just after GC.  The weak pointers on the
63  * argument list are those whose keys were found to be not reachable,
64  * however the value and finalizer fields have by now been marked live.
65  * The weak pointer object itself may not be alive - i.e. we may be
66  * looking at either an object in from-space or one in to-space.  It
67  * doesn't really matter either way.
68  */
69
70 void
71 scheduleFinalizers(StgWeak *list)
72 {
73     StgWeak *w;
74     StgTSO *t;
75     StgMutArrPtrs *arr;
76     nat n;
77
78     /* count number of finalizers first... */
79     for (n = 0, w = list; w; w = w->link) { 
80         if (w->finalizer != &stg_NO_FINALIZER_closure)
81             n++;
82     }
83         
84     if (n == 0) return;
85
86     IF_DEBUG(weak,fprintf(stderr,"weak: batching %d finalizers\n", n));
87
88     arr = (StgMutArrPtrs *)allocate(sizeofW(StgMutArrPtrs) + n);
89     SET_HDR(arr, &stg_MUT_ARR_PTRS_FROZEN_info, CCS_SYSTEM);
90     arr->ptrs = n;
91
92     for (n = 0, w = list; w; w = w->link) {
93         if (w->finalizer != &stg_NO_FINALIZER_closure) {
94             arr->payload[n] = w->finalizer;
95             n++;
96         }
97
98 #ifdef PROFILING
99         // A weak pointer is inherently used, so we do not need to call
100         // LDV_recordDead().
101         //
102         // Furthermore, when PROFILING is turned on, dead weak
103         // pointers are exactly as large as weak pointers, so there is
104         // no need to fill the slop, either.  See stg_DEAD_WEAK_info
105         // in StgMiscClosures.hc.
106 #endif
107         SET_HDR(w, &stg_DEAD_WEAK_info, w->header.prof.ccs);
108     }
109
110     t = createIOThread(RtsFlags.GcFlags.initialStkSize, 
111                        rts_apply(
112                            rts_apply(
113                                (StgClosure *)runFinalizerBatch_closure,
114                                rts_mkInt(n)), 
115                            (StgClosure *)arr)
116         );
117     scheduleThread(t);
118 }