1 /* -----------------------------------------------------------------------------
2 * $Id: StablePtr.c,v 1.2 1998/12/02 13:28:48 simonm Exp $
6 * ---------------------------------------------------------------------------*/
16 /* Comment from ADR's implementation in old RTS:
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
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
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.
41 Of course, all this rather begs the question: why would we want to
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.
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.
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.
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 #)
66 There is also a C procedure @FreeStablePtr@ which frees a stable pointer.
68 There may be additional functions on the C side to allow evaluation,
69 application, etc of a stable pointer.
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
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.
89 StgPtr *stable_ptr_table;
90 StgPtr *stable_ptr_free;
94 #define INIT_SPT_SIZE 64
97 initFreeList(StgPtr *table, nat n, StgPtr *free)
101 for (p = table + n - 1; p >= table; p--) {
105 stable_ptr_free = table;
109 initStablePtrTable(void)
111 SPT_size = INIT_SPT_SIZE;
112 stable_ptr_table = stgMallocWords(SPT_size, "initStablePtrTable");
114 initFreeList(stable_ptr_table,INIT_SPT_SIZE,NULL);
118 enlargeStablePtrTable(void)
120 nat old_SPT_size = SPT_size;
123 stable_ptr_table = stgReallocWords(stable_ptr_table, SPT_size,
124 "enlargeStablePtrTable");
126 initFreeList(stable_ptr_table + old_SPT_size, old_SPT_size, NULL);
130 markStablePtrTable(void)
132 StgPtr *p, q, *end_stable_ptr_table;
134 end_stable_ptr_table = &stable_ptr_table[SPT_size];
136 for (p = stable_ptr_table; p < end_stable_ptr_table; 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);
145 /* -----------------------------------------------------------------------------
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
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
156 The thread will be run in the context of the existing system;
157 ie. running threads will continue to run etc.
158 -------------------------------------------------------------------------- */
161 performIO(StgStablePtr io)
163 rts_evalIO((StgClosure *)deRefStablePointer(io), NULL);