[mercury-users] nondet pragma c_code (LOCALS)

Fergus Henderson fjh at cs.mu.OZ.AU
Sat Nov 27 17:27:31 AEDT 1999


On 26-Nov-1999, Robert Bossy <bossy at ccr.jussieu.fr> wrote:
> This is a simple question since I'm not familiar with how the compiler
> works: is it necessary to free the local variables declared in the
> local_vars section when coding a nondet predicate in C?

The variables declared in a `local_vars' section will be allocated
by the Mercury implementation, e.g. (with the current implementation)
on the Mercury nondet stack.  They will be allocated when the
nondet C procedure is called, and they will be deallocated in
several circumstances:

	(1) if the nondet C procedure fails,
	    which it can do by returning with SUCCESS_INDICATOR = FAIL;

	(2) if the nondet C procedure succeeds and indicates
	    that this is the last solution, which it can do by
	    returning with SUCCESS_INDICATOR = SUCCEED_LAST;

	(3) if the nondet C procedure throws an exception,
	    which can happen if it calls Mercury code exported to C
	    using `pragma export' and that Mercury code throws
	    an exception;

	(4) if the nondet C procedure succeeds, and then the caller
	    commits to that solution (pruning away any remaining
	    alternatives), which can happen if the nondet C procedure
	    is called from a context where only one solution is
	    required, such as a goal with no output variables or a
	    procedure with determinism `cc_nondet'.

In all cases, this allocation and deallocation of the `local_vars'
variables happens automatically.  So you don't need to worry about
allocating and deallocating them.

However, if you want some of the local_vars to point to dynamically
allocated memory, then the situation is a bit more complex.  Although
the memory for the variables will be allocated and deallocated
automatically, if those variables point to dynamically allocated
memory, then it is up to you to ensure that the memory that they point
to will be deallocated at the appropriate time.  The simplest way to do
that is to allocate the memory with GC_MALLOC() rather than malloc().
Then the conservative garbage collector will be responsible for
deallocation.

Alternatively, if for some reason you don't want to use the conservative
collector, you can use malloc(), but it is a bit tricky.
The remainder of this mail explains how to do it.

--------------------

If you are using malloc() to allocate memory which is pointed to by
variables defined in a `local_vars' section, then you need to make
sure that this memory will be deallocated in all of the cases that the
`local_vars' variables themselves will be deallocated.
Deallocating the memory in cases (1) and (2) is easy enough;
you can do that in the C code, just before setting SUCCESS_INDICATOR.
But dealing with (3) and (4) is harder.

If the C code doesn't call Mercury code, then you don't have to worry
about (3), and if it does call Mercury code, then you can just make
sure that the Mercury code that it calls will catch exceptions.
(I can elaborate in more detail on that if anyone is interested.)

To handle (4), i.e. to deallocate the memory when the caller commits
to a solution, is not so easy.  To do that, you need to enable trailing
(with the `--use-trail' option), and then you need to call MR_trail_function()
to establish a trail handler, so that you can get control when a commit
occurs.  Your trail handler needs to check for the `MR_commit' case, and 
if that case occurs, it must deallocate the memory.  If you use this
solution, you can also deallocate the memory in the `MR_exception' case,
so this solves (3) as well.

If you allocate memory using malloc(), then you also need to be aware
that the Boehm (et al) conservative garbage collector that we use does
not trace through memory allocated via malloc(), so you must be careful
to ensure that any memory which is pointed to via malloc()'ed memory is
also pointed to by at least one place that the converative garbage
collector does trace -- i.e. the C stack, the Mercury stacks, and global
variables -- otherwise the garbage collector may think that it is no
longer live and may thus reuse it for something else.
(On most platforms, this can be avoided by compiling the collector with
-DREDEFINE_MALLOC, which defines malloc() and friends to call GC_MALLOC(),
but that is not quite as portable.)

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list