[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / rts / StablePtr.c
1 /* -----------------------------------------------------------------------------
2  * $Id: StablePtr.c,v 1.2 1998/12/02 13:28:48 simonm Exp $
3  *
4  * Stable pointers
5  *
6  * ---------------------------------------------------------------------------*/
7
8 #include "Rts.h"
9 #include "StablePtr.h"
10 #include "GC.h"
11 #include "RtsUtils.h"
12 #include "Storage.h"
13 #include "RtsAPI.h"
14 #include "RtsFlags.h"
15
16 /* Comment from ADR's implementation in old RTS:
17
18   This files (together with @ghc/runtime/storage/PerformIO.lhc@ and a
19   small change in @HpOverflow.lc@) consists of the changes in the
20   runtime system required to implement "Stable Pointers". But we're
21   getting a bit ahead of ourselves --- what is a stable pointer and what
22   is it used for?
23
24   When Haskell calls C, it normally just passes over primitive integers,
25   floats, bools, strings, etc.  This doesn't cause any problems at all
26   for garbage collection because the act of passing them makes a copy
27   from the heap, stack or wherever they are onto the C-world stack.
28   However, if we were to pass a heap object such as a (Haskell) @String@
29   and a garbage collection occured before we finished using it, we'd run
30   into problems since the heap object might have been moved or even
31   deleted.
32
33   So, if a C call is able to cause a garbage collection or we want to
34   store a pointer to a heap object between C calls, we must be careful
35   when passing heap objects. Our solution is to keep a table of all
36   objects we've given to the C-world and to make sure that the garbage
37   collector collects these objects --- updating the table as required to
38   make sure we can still find the object.
39
40
41   Of course, all this rather begs the question: why would we want to
42   pass a boxed value?
43
44   One very good reason is to preserve laziness across the language
45   interface. Rather than evaluating an integer or a string because it
46   {\em might\/} be required by the C function, we can wait until the C
47   function actually wants the value and then force an evaluation.
48
49   Another very good reason (the motivating reason!) is that the C code
50   might want to execute an object of sort $IO ()$ for the side-effects
51   it will produce. For example, this is used when interfacing to an X
52   widgets library to allow a direct implementation of callbacks.
53
54
55   The @makeStablePointer :: a -> IO (StablePtr a)@ function
56   converts a value into a stable pointer.  It is part of the @PrimIO@
57   monad, because we want to be sure we don't allocate one twice by
58   accident, and then only free one of the copies.
59
60   \begin{verbatim}
61   makeStablePtr#  :: a -> State# RealWorld -> (# RealWorld, a #)
62   freeStablePtr#  :: StablePtr# a -> State# RealWorld -> State# RealWorld
63   deRefStablePtr# :: StablePtr# a -> State# RealWorld -> 
64         (# State# RealWorld, a #)
65   \end{verbatim}
66   There is also a C procedure @FreeStablePtr@ which frees a stable pointer.
67
68   There may be additional functions on the C side to allow evaluation,
69   application, etc of a stable pointer.
70
71   When Haskell calls C, it normally just passes over primitive integers,
72   floats, bools, strings, etc.  This doesn't cause any problems at all
73   for garbage collection because the act of passing them makes a copy
74   from the heap, stack or wherever they are onto the C-world stack.
75   However, if we were to pass a heap object such as a (Haskell) @String@
76   and a garbage collection occured before we finished using it, we'd run
77   into problems since the heap object might have been moved or even
78   deleted.
79
80   So, if a C call is able to cause a garbage collection or we want to
81   store a pointer to a heap object between C calls, we must be careful
82   when passing heap objects. Our solution is to keep a table of all
83   objects we've given to the C-world and to make sure that the garbage
84   collector collects these objects --- updating the table as required to
85   make sure we can still find the object.
86 */
87
88
89 StgPtr *stable_ptr_table;
90 StgPtr *stable_ptr_free;
91
92 static nat SPT_size;
93
94 #define INIT_SPT_SIZE 64
95
96 static inline void
97 initFreeList(StgPtr *table, nat n, StgPtr *free)
98 {
99   StgPtr *p;
100
101   for (p = table + n - 1; p >= table; p--) {
102     *p = (P_)free;
103     free = p;
104   }
105   stable_ptr_free = table;
106 }
107
108 void
109 initStablePtrTable(void)
110 {
111   SPT_size = INIT_SPT_SIZE;
112   stable_ptr_table = stgMallocWords(SPT_size, "initStablePtrTable");
113
114   initFreeList(stable_ptr_table,INIT_SPT_SIZE,NULL);
115 }
116
117 void
118 enlargeStablePtrTable(void)
119 {
120   nat old_SPT_size = SPT_size;
121   
122   SPT_size *= 2;
123   stable_ptr_table = stgReallocWords(stable_ptr_table, SPT_size, 
124                                      "enlargeStablePtrTable");
125   
126   initFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL);
127 }
128
129 void
130 markStablePtrTable(void)
131 {
132   StgPtr *p, q, *end_stable_ptr_table;
133   
134   end_stable_ptr_table = &stable_ptr_table[SPT_size];
135
136   for (p = stable_ptr_table; p < end_stable_ptr_table; p++) {
137     q = *p;
138     /* internal pointers or NULL are free slots */
139     if (q && (q < (P_)stable_ptr_table || q >= (P_)end_stable_ptr_table)) {
140       (StgClosure *)*p = MarkRoot((StgClosure *)q);
141     }
142   }
143 }
144
145 /* -----------------------------------------------------------------------------
146    performIO
147
148    This is a useful function for calling from C land (or Haskell land
149    with _ccall_GC) which runs an arbitrary Haskell IO computation in a
150    new thread.
151
152    The closure to evaluate is passed in as a stable pointer, and
153    should have type StablePtr (IO ()).  No checking is done on the
154    type, so be careful!
155
156    The thread will be run in the context of the existing system;
157    ie. running threads will continue to run etc.
158    -------------------------------------------------------------------------- */
159
160 void
161 performIO(StgStablePtr io)
162 {
163   rts_evalIO((StgClosure *)deRefStablePointer(io), NULL);
164 }
165