[m-rev.] for review: --trace-table-io-require

Zoltan Somogyi zs at cs.mu.OZ.AU
Sun Jul 21 18:41:32 AEST 2002


On 19-Jul-2002, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> Hmm... I don't really understand the rational for these annotations.
> What's the point of writing "tabled_for_io" annotations,
> if they are required for all foreign_procs that do I/O?

We discussed this long ago.

The tabled_for_io annotation is an assertion that the foreign_proc may do I/O,
but will not call Mercury code. Another annotation, tabled_for_descendant_io
(which will be introduced by a diff that I intend to send tomorrow) asserts
that the foreign_proc will not do I/O, although it may call Mercury code
(that may or may not do I/O). There is no provision for foreign_procs
that both do I/O and call Mercury code, since our current mechanisms for retry
in the debugger cannot handle a retry within such a foreign_proc correctly.

The problem is the following. Suppose predicate p is implemented using
foreign_proc, and it calls predicates q1, ... qn, all of which are in Mercury.
All have a pair of I/O state arguments, and suppose p does I/O between calls
to e.g. q2 and q3. Suppose execution has progressed to the exit port of q3,
and the user does a retry of p (the parent of q3). How do you ensure that after
the retyry, the I/O that p did before the call to q3 will not be reexecuted,
but the I/O that p does after the call to q3 will be executed (since it hasn't
been executed before)? Since p is not in Mercury, the debugger cannot ensure
this regardless of the help it gets from the compiler.

> Can't the compiler infer these annotations automatically
> from the type?

No.

The annotations are necesary to tell the compiler which of the first two cases
above applies to a given foreign_proc, and to ensure that third case doesn't
occur.

> > +++ browser/dl.m	2002/07/18 05:58:23
> > @@ -35,7 +35,7 @@
> >  
> >  % high-level interface to the C function dlsym().
> >  % This version returns a higher-order predicate or function term.
> > -% The user must use an inst cast (implemented using pragma c_code)
> > +% The user must use an inst cast (implemented using foreign_proc)
> >  % to cast this term to the appropriate higher-order inst before calling
> >  % it; see dl_test.m for an example of this.
> 
> "foriegn_proc" is still not yet officially supported.
> So it should be:
> ... (implemented using pragma c_code or foreign_proc)

OK, but I thought pragma c_code is deprecated in favor of foreign_proc.
If that isn't the case, why isn't it?

> >  :- pred high_level_code is semidet.
> > -:- pragma c_code(high_level_code, [will_not_call_mercury, thread_safe], "
> > +:- pragma foreign_proc("C", high_level_code,
> > +	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
> > +"
> >  #ifdef MR_HIGHLEVEL_CODE
> >  	SUCCESS_INDICATOR = MR_TRUE;
> >  #else
> 
> Why is that tabled_for_io?

It shouldn't be. I fixed it.

> > Index: compiler/gcc.m
> ...
> >  :- pred call_gcc_backend(string::in, int::out,
> >  		io__state::di, io__state::uo) is det.
> > -:- pragma import(call_gcc_backend(in, out, di, uo), "MC_call_gcc_backend").
> > +:- pragma import(call_gcc_backend(in, out, di, uo),
> > +	[will_not_call_mercury, tabled_for_io],
> > +	"MC_call_gcc_backend").
> 
> will_not_call_mercury is not correct there.
> The GCC back-end will invoke a callback that ends up
> calling back to Mercury code from the Mercury compiler front-end.

Fixed.

It may be a good idea to deprecate the version of pragma import that doesn't
specify a list of properties.

> Likewise in browser/dl.m:
> > -:- pragma c_code(dlopen(FileName::in, Mode::in, Scope::in, Result::out,
> > -               _IO0::di, _IO::uo), [], "
> > -{
> > +:- pragma foreign_proc("C",
> > +       dlopen(FileName::in, Mode::in, Scope::in, Result::out,
> > +               _IO0::di, _IO::uo),
> > +       [will_not_call_mercury, promise_pure, tabled_for_io],
> > +"{
> 
> As the comment two lines above this code says,
> dlopen() could invoke module initializers (e.g. C++ constructors
> for global variables) that could call Mercury code,
> so will_not_call_mercury is not safe here.
> 
> Likewise for dlclose().

Actually, it looks like dlopen and dlclose both do I/O of their own (reading
the named file) and may call Mercury code. However, since the Mercury code is
initialization code, we should be to deal with it by turning off execution
tracing and I/O tabling within it, thus treating dlopen and everything it calls
as a single I/O primitive. I'll add a third annotation to cover such cases
in my next change. I will also have to apply it to call_gcc_backend, which
is not ideal, but is the only safe thing to do.

Zoltan.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list