[m-users.] Mercury with Guile (was Re: installation failure (Mercury 14.01))

Peter Wang novalazy at gmail.com
Sun Aug 3 17:51:27 AEST 2014


On Sat, 2 Aug 2014 20:12:25 +0200, "Tomas By" <tomas at basun.net> wrote:
> 
> This code:
> http://www.mercurylang.org/list-archives/users/2011-June/005409.html
> 
> I am trying to create a binary containing both Mercury and Guile that does
> not crash immediately.

Hi Tomas,

When Guile is first initialised it calls GC_set_all_interior_pointers(0)
which resets the pointer displacements registered by the Mercury
wrapper.  This will cause premature collection of Mercury structures.

The following program works for me, though it's not very comprehensive.

I built Guile against Mercury's par_gc library by setting BDW_GC_CFLAGS
and BDW_GC_LIBS when configuring Guile.  I needed to comment out a call
to GC_dump as it does not exist in Mercury's build.

Peter
-------------- next part --------------
%-----------------------------------------------------------------------------%

:- module t.
:- interface.

:- import_module io.

:- pred main(io::di, io::uo) is det.

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- implementation.

:- import_module bool.
:- import_module int.
:- import_module list.
:- import_module thread.

:- pragma foreign_decl("C", "
    #include <libguile.h>
").

%-----------------------------------------------------------------------------%

main(!IO) :-
    init_guile(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO),
    p1(!IO), p2(!IO).

%-----------------------------------------------------------------------------%

:- pred p1(io::di, io::uo) is det.

p1(!IO) :-
    scm_with_guile(do_scm, !IO).

:- pred do_scm(io::di, io::uo) is det.

do_scm(!IO) :-
    scm_c_eval_string(alloc_scm, R, !IO),
    io.write_int(R, !IO),
    io.nl(!IO).

:- func alloc_scm = string.

alloc_scm =
    "(let loop ((i 0) (xs '()))
        (if (>= i 10000)
            (length xs)
            (loop (+ i 1) (cons (make-vector 1000 #f) xs))))".

%-----------------------------------------------------------------------------%

:- pred p2(io::di, io::uo) is det.

p2(!IO) :-
    R = alloc(0, []),
    io.write_int(R, !IO),
    io.nl(!IO).

:- func alloc(int, list(list(int))) = int.

alloc(I, Xs) =
    ( I >= 10000 ->
        length(Xs)
    ;
        alloc(I + 1, cons(1 .. 1000, Xs))
    ).

%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%

:- pred init_guile(io::di, io::uo) is det.

:- pragma foreign_proc("C",
    init_guile(_IO0::di, _IO::uo),
    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io,
        may_not_duplicate],
"
    scm_with_guile(nothing, NULL);
    /*
    ** scm_storage_prehistory calls GC_set_all_interior_pointers which has the
    ** side-effect of resetting the pointer displacements which were set up
    ** before entering main, so we need to register them again.
    */
    register_displacements();
").

:- pragma foreign_decl("C", local, "
static void *
nothing(void *extra)
{
    return NULL;
}

static void
register_displacements(void)
{
    int i;
    int limit;

    limit = (1 << MR_LOW_TAG_BITS);

#if defined(MR_RECORD_TERM_SIZES) || \
    defined(MR_MPROF_PROFILE_MEMORY_ATTRIBUTION)
    limit += sizeof(MR_Word);
#endif

    for (i = 1; i < limit; i++) {
        GC_REGISTER_DISPLACEMENT(i);
    }
}
").

%-----------------------------------------------------------------------------%

:- pred scm_with_guile(pred(io, io), io, io).
:- mode scm_with_guile(pred(di, uo) is det, di, uo) is det.

:- pragma foreign_proc("C",
    scm_with_guile(Pred::in(pred(di, uo) is det), _IO0::di, _IO::uo),
    [may_call_mercury, promise_pure, thread_safe, tabled_for_io,
        may_not_duplicate],
"
    scm_with_guile(call_pred, (void *) Pred);
").

:- pragma foreign_decl("C", local, "
static void *
call_pred(void *data)
{
    do_call((MR_Word) data);
    return NULL;
}
").

:- pred do_call(pred(io, io), io, io).
:- mode do_call(pred(di, uo) is det, di, uo) is det.

:- pragma foreign_export("C", do_call(pred(di, uo) is det, di, uo), "do_call").

do_call(P, !IO) :-
    call(P, !IO).

%-----------------------------------------------------------------------------%

:- pred scm_c_eval_string(string::in, int::out, io::di, io::uo) is det.

:- pragma foreign_proc("C",
    scm_c_eval_string(S::in, R::out, _IO0::di, _IO::uo),
    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
"
    SCM r = scm_c_eval_string(S);
    R = scm_to_int(r);
").

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sts=4 sw=4 et


More information about the users mailing list