Tom Lord <xxxxxx@emf.net> writes:
> About the following: one of us is confused. Not sure which.
>
>
> > > > mn_ref *
> > > > mn_to_car (mn_call *call, mn_ref *ref)
> > > > {
> > > > mn__begin_incoherent (call);
> > > > {
> > > > ref->obj = check_pair (ref)->car;
> > > > }
> > > > mn__end_incoherent (call);
> > > >
> > > > return ref;
> > > > }
>
> > > Isn't that code incorrect in a threaded system? While `ref' is,
> > > indeed, about to be freed, the pair that it refers to is live.
> > > Assuming that the `incoherent' calls exclude only GC but not other
> > > mutators (which is the benefit you seem to be claiming), then the
> > > `->car' risks producing garbage.
>
> > This is what that comment is going on about. References are
> > immutable: there is no operation that changes a reference's referent.
> > mn_to_car looks like a counter-example, but it isn't: officially, it
> > frees REF, so it would be incorrect to call it if any other thread
> > were referring to it. But since it's freeing a reference and then
> > immediately allocating a new one, it might as well just reuse the
> > reference.
>
> That's not what I mean by "incorrect in a threaded system".
>
> Am I correct that `check_pair (ref)' returns a pointer to something
> like:
>
> struct pair
> {
> scheme_value car;
> scheme_value cdr;
> }
>
> ?
Yes.
> And am I correct that mn__begin_incoherent excludes GC but not other
> mutators?
Yes.
> If both assumptions are true then the code is incorrect because
> `->car' is not necessarily going to return a legitimate scheme value
> (it may return a "half written" one).
That's right, in theory.
(Just to be clear: we're now talking about details of the Minor
implementation, here, not whether the Minor API can be implemented
properly. I think we agree that the Minor interface gives
implementations the hooks they need to do whatever synchronization is
needed.)
I just assume things will work out here:
- The Minor implementation is not intended to be portable to all ISO C
/ POSIX platforms. I'm much more interested in the native code JIT
than in the interpreter, so the Minor implementation will generally
make machine-specific assumptions where doing so makes a big
difference. And since I'm interested in clean interoperation with
the C and C++ toolchains, I plan to generate native .o files, so
Minor will be ABI-specific, too.
- Java requires that pointers not be corrupted, even in the absence of
proper synchronization. As far as I can see, the gcj front end for
GCC doesn't do anything special to ensure that pointers are read and
written with single instructions. So I think C code should be able
to make the same assumption.
- GCC must not generate split stores for sig_atomic_t, and the GNU C
library simply defines that as 'int' on every platform. So on those
platforms where int can hold a pointer, I'm fine. This is true on
every platform I intend to care about, except the x86-64.
- Of course, the instructions the compiler generates don't dictate how
the inter-processor cache interactions work, so in theory they could
chop up the pointer, too. But Java already requires that writes to
words appear atomic, so this is apparently not a problem.