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

Re: GC safety and return values

This page is part of the web mail archives of SRFI 50 from before July 7th, 2015. The new archives for SRFI 50 contain all messages, not just those from before July 7th, 2015.

>>>>> "Tom" == Tom Lord <lord@xxxxxxx> writes:

Tom> jimb is correct.

Right.  I misunderstood him.  Thanks for the clarifying example!

Tom> Consider the code:

Tom>         scheme_value x;

Tom>         [...]

Tom>         GCPRO(&x);

Tom>         [...]

Tom>         z = SCHEME_CONS (x, y);         /* XXX */

Tom> during execution of the the statement marked "XXX", the sequence
Tom> over time of operations may be:

Tom>         thread 1:                       thread 2:     
Tom>                                                       |
Tom>         reg1 = x;                       -             t
Tom>         reg2 = y;                       -             i
Tom>         -                               trigger GC    m
Tom>         call SCHEME_CONS                -             e
Tom>         (on return,                     -             |
Tom>         reg1 holds new pair)            -             V
Tom>         -                               trigger GC
Tom>         z = reg1                        -

Tom> At the first GC, a stop-and-copy GC will want to modify the values
Tom> stored in x and y, but it won't find reg1 and reg2.

Tom> At the second GC, a stop-and-copy GC will want to modify the value
Tom> about to be stored in z, but it won't find reg1.

Tom> That is one reason why it isn't sufficient to make sure that protected
Tom> scheme values are always stored in GCPROtected locations -- you must
Tom> also make sure that, other than in the internals of the FFI
Tom> implementation, they are not stored anywhere else.

Tom> You can make that guarantee by not passing or returning those values
Tom> directly at all -- but instead passing and returning "handles" for
Tom> those values.

Tom> Jimb and I have each shown a technique (so now you have two available)
Tom> for always passing and returning handles:  in jimb's approach, handles
Tom> are separately allocated objects;  in my approach, handles are the
Tom> addresses of GCPROtected values.    So you have either:

Tom>         scheme_value_handle x = 0;
Tom>         scheme_value_handle y = 0;
Tom>         scheme_value_handle z = 0;

Tom>         [....]

Tom>         z = SCHEME_CONS (this_call, x, y);

Tom>         /* caller frees any handles allocated above. */

Tom> or:

Tom>         struct my_frame
Tom>         { 
Tom>           scheme_value x;
Tom>           scheme_value y;
Tom>           scheme_value z;
Tom>         } f;

Tom>         GCPRO_FRAME (f);

Tom>         [...]

Tom>         SCHEME_CONS (&f.z, this_instance, &f.x, &f.y);

Tom>         /* eventual GCUNPRO_FRAME needed */

Tom> (As I said elsewhere, I think that there are some performance and,
Tom> more importantly, GC-precision advantages to the second approach.)

Tom> Either approach also has advantages for single-threaded systems simply
Tom> because they both make it harder to make certain kinds of mistakes
Tom> that will lead to subtle and difficult-to-reproduce GC bugs.

Tom> -t

Cheers =8-} Mike
Friede, Völkerverständigung und überhaupt blabla