chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] FFI and stack use


From: Francisco Rafael Leon
Subject: Re: [Chicken-users] FFI and stack use
Date: Wed, 22 Jul 2009 01:46:59 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.60 (gnu/linux)

Thomas Bushnell BSG <address@hidden> writes:

> I have an FFI function, and it will be allocating some significant stack
> space.  (It calls the Linux syscall epoll_wait, with a significant
> stack-allocated array, and then wants to cons the results into a list.)
>
> So this raises a question.  Scheme functions get compiled into code that
> carefully checks stack bounds before allocating, and bangs off to the
> garbage collector if necessary.
>
> The FFI doesn't do this.  So I'm assuming that in fact, I have the full
> C stack available, and can just go ahead and use it.  When I invoke the
> return continuation, it will go just fine, and presumably if I've
> exceeded the Chicken stack size, it will just trigger a gc and proceed
> happily as before.
>
> Am I right?
>
> Thomas

In C, when you make a mess, you must clean it up yourself.

For this reason, I treat all my FFI calls like toxic waste, and wrap
them in (let ... ) containers which allocate everything I need for the 
FFI call. I get pointers using (location ...) and call the C function.
After the FFI call returns, the closing ")" of the "let" 
establishes scope and the GC can do whatever it wants after that.  It
has never eaten my stuff before the ")", so this seems to work. The last
line before the ")" is a call to "cons" or "append" or "list" with
whatever I need from my "let". This is how I write wrappers. It Works
For Me (TM). 

For event-driven programs with external C contexts and data structures,
you need an event loop which calls (collect-c-garbage context) which checks your
program state and calls free() when needed.  You need to write
(collect-c-garbage) yourself, and fill it with conditionals and calls to
free(). For programs with I/O structures or AI genetic algorithms or
whatever, you can probably come up with reasonable conditionals for when
you need or don't need something anymore.  Read through the lolevel unit
docs in the manual about tools you can use for this.  With persistent
data out in C-land, an event loop with a custom GC is excellent form I
think.  Within the loop, you pass pointers around and use them and then
do a check at the end of each iteration.

Those are two easy ways of making C behave. They add overhead. They are
simple and difficult to screw up. 

Then, there is the incredibly scary alternative which involves
sprinkling your functions with FFI calls to alloc() and free() and then
trying to map out the state space and all possible transitions and
drawing epic flow diagrams to try and match up calls to alloc() and
free(). This is not a good idea because life is short, and even if you
spend 100 hours doing this, you will still screw it up. I promise.  

Lastly, there is the overwhelmingly popular option of doing the above,
but not worrying about matching up calls to alloc() and free(). If you
want an example of this ... well I'll stop before I become really 
offensive. Let me just state that *some* languages lack GC, and that
*some* software in those languages use lots of memory. I am not
kidding. In 2009, this is still true. 

I haven't looked at the chicken source code, but I don't really want to,
because then I will think I am smart and will use GC tricks that are not
portable to other implementations.  Or worse, I might learn that my
"let" statements are not safe from the GC and that I should use
object-evict to be totally safe.  So far, the GC has not harmed me and
has respected the closing ")" of the let before moving anything.

        -Rafael




reply via email to

[Prev in Thread] Current Thread [Next in Thread]