summaryrefslogtreecommitdiff
path: root/ghc/includes/Updates.h
blob: 04838e777cfeeb841b8a2745f6f27283ca51f2e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* -----------------------------------------------------------------------------
 * $Id: Updates.h,v 1.6 1999/01/21 10:31:45 simonm Exp $
 *
 * Definitions related to updates.
 *
 * ---------------------------------------------------------------------------*/

#ifndef UPDATES_H
#define UPDATES_H

/* -----------------------------------------------------------------------------
   Update a closure with an indirection.  This may also involve waking
   up a queue of blocked threads waiting on the result of this
   computation.
   -------------------------------------------------------------------------- */

/* ToDo: overwrite slop words with something safe in case sanity checking 
 *       is turned on.  
 *       (I think the fancy version of the GC is supposed to do this too.)
 */

/* This expands to a fair chunk of code, what with waking up threads 
 * and checking whether we're updating something in a old generation.
 * preferably don't use this macro inline in compiled code.
 */

#define UPD_IND(updclosure, heapptr)                            \
        AWAKEN_BQ(updclosure);                                  \
	updateWithIndirection((StgClosure *)updclosure,         \
			      (StgClosure *)heapptr);

/* -----------------------------------------------------------------------------
   Awaken any threads waiting on this computation
   -------------------------------------------------------------------------- */

extern void awaken_blocked_queue(StgTSO *q);

#define AWAKEN_BQ(closure)						\
     	if (closure->header.info == &BLACKHOLE_BQ_info) {		\
		StgTSO *bq = ((StgBlockingQueue *)closure)->blocking_queue;\
		if (bq != (StgTSO *)&END_TSO_QUEUE_closure) {		\
			STGCALL1(awaken_blocked_queue, bq);		\
		}							\
	}


/* -----------------------------------------------------------------------------
   Push an update frame on the stack.
   -------------------------------------------------------------------------- */

#if defined(PROFILING)
#define PUSH_STD_CCCS(frame) frame->header.prof.ccs = CCCS
#else
#define PUSH_STD_CCCS(frame)
#endif

extern const StgPolyInfoTable Upd_frame_info; 

#define PUSH_UPD_FRAME(target, Sp_offset)			\
	{							\
		StgUpdateFrame *__frame;			\
		TICK_UPDF_PUSHED();  			        \
		__frame = stgCast(StgUpdateFrame*,Sp + (Sp_offset)) - 1; \
		SET_INFO(__frame,stgCast(StgInfoTable*,&Upd_frame_info));   \
		__frame->link = Su;				\
		__frame->updatee = (StgClosure *)(target);	\
		PUSH_STD_CCCS(__frame);				\
		Su = __frame;					\
	}

/* -----------------------------------------------------------------------------
   Entering CAFs

   When a CAF is first entered, it creates a black hole in the heap,
   and updates itself with an indirection to this new black hole.

   We update the CAF with an indirection to a newly-allocated black
   hole in the heap.  We also set the blocking queue on the newly
   allocated black hole to be empty.

   Why do we make a black hole in the heap when we enter a CAF?
      
       - for a  generational garbage collector, which needs a fast
         test for whether an updatee is in an old generation or not

       - for the parallel system, which can implement updates more
         easily if the updatee is always in the heap. (allegedly).

   When debugging, we maintain a separate CAF list so we can tell when
   a CAF has been garbage collected.
   -------------------------------------------------------------------------- */
   
/* ToDo: only call newCAF when debugging. */

extern void newCAF(StgClosure*);

#define UPD_CAF(cafptr, bhptr)					\
  {								\
    SET_INFO((StgInd *)cafptr,&IND_STATIC_info);	        \
    ((StgInd *)cafptr)->indirectee   = (StgClosure *)(bhptr);	\
    STGCALL1(newCAF,(StgClosure *)cafptr);			\
  }

/* -----------------------------------------------------------------------------
   Update-related prototypes
   -------------------------------------------------------------------------- */

extern STGFUN(Upd_frame_entry);

extern const StgInfoTable PAP_info;
STGFUN(PAP_entry);

EXTFUN(stg_update_PAP);

extern const StgInfoTable AP_UPD_info;
STGFUN(AP_UPD_entry);

extern const StgInfoTable raise_info;

#endif /* UPDATES_H */