I'd like to extend the set of functions that a Haskell system provides to C programs. As well as hs_init, hs_exit and hs_set_argv, I'd like to have:
int hs_garbage_collect( int how_hard ); This invokes the Haskell garbage collector. The argument and result are for use when interacting with generational collectors. The result is 0 if the garbage collector has done a full GC. Increasing the size of the argument provides greater and greater encouragement to do a full GC. Thus, this loop int i=0; while (hs_garbage_collect(i++)) {} is guaranteed to terminate when further GC calls will not free up any more objects. Subtleties: 1) What happens if the programmer writes this code instead: int i=10; while (hs_garbage_collect(i++)) {} ^^ start deeper It can either behave the same as if they started at 0 or it can start by doing a hefty GC or whatever it feels like. All that matters is that increasing the value of how_hard makes more GC happen. What if they write the loop backwards: int i=10; while (hs_garbage_collect(i--)) {} ^^ start deeper ^^ decrement They'll start with a hefty collection and then do increasingly small collections. The subsequent (smaller) collections might not even achieve anything but they will still return zero only if there is no more garbage to be collected. 2) On a distributed Haskell implementation, increasing the value of how_hard must eventually cause remote machines to do a GC too. 3) It might seem simpler to just have hs_garbage_collect do a full collection. But this would give no efficient way to write code that garbage collects until enough C objects have been released. Using the above interface this would be: int freespace; void free(void* object, int size) { freespace += size; raw_free(object); } void* alloc(int requirement) { int i=0; while (freespace < requirement) { if (hs_garbage_collect(i++) == 0) { return 0; // fail } } return raw_alloc(requirement); } 4) Increasing the value of how_hard must eventually cause all ForeignPtr finalizers for free objects to be invoked. i.e., GHC would have to keep track of whether there are any runnable finalizer threads and run them to completion. Because we want to garbage collect no more than we have to, we might want the how_hard argument to behave as follows: if there are any pending finalizers, run one of them; otherwise do either a big or small collection. // Note that this version ignores the how_hard argument // but will behave correctly anyway. int hs_garbage_collect(int how_hard) { static next_depth = 0; if (pending_finalizers > 0) { // finalize what we can run_one_finalizer_to_completion(); return 1; } if (next_depth == 0) { minor_garbage_collect(); next_depth = 1; return 1; } else { major_garbage_collect(); next_depth = 0; return (pending_finalizers > 0); } } -- Alastair Reid [EMAIL PROTECTED] http://www.cs.utah.edu/~reid/ ps Was there any consensus about changing the hs_init API as sugegsted last week? _______________________________________________ FFI mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/ffi