[project @ 1999-03-18 17:57:19 by simonm]
[ghc-hetmet.git] / ghc / includes / Updates.h
1 /* -----------------------------------------------------------------------------
2  * $Id: Updates.h,v 1.9 1999/03/18 17:57:20 simonm Exp $
3  *
4  * (c) The GHC Team, 1998-1999
5  *
6  * Definitions related to updates.
7  *
8  * ---------------------------------------------------------------------------*/
9
10 #ifndef UPDATES_H
11 #define UPDATES_H
12
13 /* -----------------------------------------------------------------------------
14    Update a closure with an indirection.  This may also involve waking
15    up a queue of blocked threads waiting on the result of this
16    computation.
17    -------------------------------------------------------------------------- */
18
19 /* ToDo: overwrite slop words with something safe in case sanity checking 
20  *       is turned on.  
21  *       (I think the fancy version of the GC is supposed to do this too.)
22  */
23
24 /* This expands to a fair chunk of code, what with waking up threads 
25  * and checking whether we're updating something in a old generation.
26  * preferably don't use this macro inline in compiled code.
27  */
28
29 #define UPD_IND(updclosure, heapptr)                            \
30         AWAKEN_BQ(updclosure);                                  \
31         updateWithIndirection((StgClosure *)updclosure,         \
32                               (StgClosure *)heapptr);
33
34 #ifdef PROFILING
35 #define UPD_PERM_IND(updclosure, heapptr)                       \
36         AWAKEN_BQ(updclosure);                                  \
37         updateWithPermIndirection((StgClosure *)updclosure,     \
38                                   (StgClosure *)heapptr);
39 #endif
40
41 /* -----------------------------------------------------------------------------
42    Awaken any threads waiting on this computation
43    -------------------------------------------------------------------------- */
44
45 extern void awaken_blocked_queue(StgTSO *q);
46
47 #define AWAKEN_BQ(closure)                                              \
48         if (closure->header.info == &BLACKHOLE_BQ_info) {               \
49                 StgTSO *bq = ((StgBlockingQueue *)closure)->blocking_queue;\
50                 if (bq != (StgTSO *)&END_TSO_QUEUE_closure) {           \
51                         STGCALL1(awaken_blocked_queue, bq);             \
52                 }                                                       \
53         }
54
55
56 /* -----------------------------------------------------------------------------
57    Push an update frame on the stack.
58    -------------------------------------------------------------------------- */
59
60 #if defined(PROFILING)
61 #define PUSH_STD_CCCS(frame) frame->header.prof.ccs = CCCS
62 #else
63 #define PUSH_STD_CCCS(frame)
64 #endif
65
66 extern DLL_IMPORT_DATA const StgPolyInfoTable Upd_frame_info; 
67
68 #define PUSH_UPD_FRAME(target, Sp_offset)                       \
69         {                                                       \
70                 StgUpdateFrame *__frame;                        \
71                 TICK_UPDF_PUSHED();                             \
72                 __frame = stgCast(StgUpdateFrame*,Sp + (Sp_offset)) - 1; \
73                 SET_INFO(__frame,stgCast(StgInfoTable*,&Upd_frame_info));   \
74                 __frame->link = Su;                             \
75                 __frame->updatee = (StgClosure *)(target);      \
76                 PUSH_STD_CCCS(__frame);                         \
77                 Su = __frame;                                   \
78         }
79
80 /* -----------------------------------------------------------------------------
81    Entering CAFs
82
83    When a CAF is first entered, it creates a black hole in the heap,
84    and updates itself with an indirection to this new black hole.
85
86    We update the CAF with an indirection to a newly-allocated black
87    hole in the heap.  We also set the blocking queue on the newly
88    allocated black hole to be empty.
89
90    Why do we make a black hole in the heap when we enter a CAF?
91       
92        - for a  generational garbage collector, which needs a fast
93          test for whether an updatee is in an old generation or not
94
95        - for the parallel system, which can implement updates more
96          easily if the updatee is always in the heap. (allegedly).
97
98    When debugging, we maintain a separate CAF list so we can tell when
99    a CAF has been garbage collected.
100    -------------------------------------------------------------------------- */
101    
102 /* ToDo: only call newCAF when debugging. */
103
104 extern void newCAF(StgClosure*);
105
106 #define UPD_CAF(cafptr, bhptr)                                  \
107   {                                                             \
108     SET_INFO((StgInd *)cafptr,(const StgInfoTable*)&IND_STATIC_info);           \
109     ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);   \
110     STGCALL1(newCAF,(StgClosure *)cafptr);                      \
111   }
112
113 /* -----------------------------------------------------------------------------
114    Update-related prototypes
115    -------------------------------------------------------------------------- */
116
117 DLL_IMPORT_RTS extern STGFUN(Upd_frame_entry);
118
119 extern DLL_IMPORT_DATA const StgInfoTable PAP_info;
120 DLL_IMPORT_RTS STGFUN(PAP_entry);
121
122 EXTFUN_RTS(stg_update_PAP);
123
124 extern DLL_IMPORT_DATA const StgInfoTable AP_UPD_info;
125 DLL_IMPORT_RTS STGFUN(AP_UPD_entry);
126
127 extern DLL_IMPORT_DATA const StgInfoTable raise_info;
128
129 #endif /* UPDATES_H */