guile-devel
[Top][All Lists]
Advanced

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

Re: the new gc asserts in master


From: Ludovic Courtès
Subject: Re: the new gc asserts in master
Date: Thu, 28 Aug 2008 16:17:33 +0200
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.2 (gnu/linux)

Hello,

Thanks for the nice summary!

Andy Wingo <address@hidden> writes:

> But what if it goes like this:
>
>   S becomes collectable in theory
>
>   mark phase: S is indeed marked as collectable
>
>   C is returned from a callback: get_ptr() return S
>
>   at some later time the card containing S is swept; S's free function
>   is run, and S is marked as a free cell
>
>   at some later point maybe S gets reused for some other purpose
>
>   however S was already alive in scheme, and we are using it as a smob!
>
> The point is:
>
>   You cannot do C->Scheme mapping reliably in the presence of lazy
>   sweeping, because there is a time in which the object is marked as
>   sweepable but not swept, but the C->Scheme code has no way of knowing
>   this.
>
> (While talking with Ludovic we realized that his code has this problem.)

The code I had in mind is GnuTLS [0], but it's a slightly more specific
scenario and I now don't think the problem applies there.

In GnuTLS, there are "session" objects; session objects can have a
Scheme port attached to them, and the `session-record-port' procedure
returns that port.  What we want is:

  (eq? (session-record-port s) (session-record-port s))

IOW, there must be a mapping from the session to the port so that we
don't create a new port each time `session-record-port' is called.

Here's how it's achieved.  Let `s' be the C session object, `S' the
corresponding SMOB, and `P' the port (an `SCM').  We have the following
object graph:

         SCM_STREAM(P)
  S <-------------------- P
  |                       ^
  |SCM_SMOB_DATA(S)       |
  |                       |
  |  _____________________'
  | /  gnutls_session_get_ptr(s)
  v/
  s

The mark procedure of `S' marks `P'.  Thus, as long as `S' is reachable,
`P' is reachable.  In addition, as long as `P' is reachable, `S' is
reachable.

The important difference with the generalized scheme you described is
that when `S' becomes unreferenced by Scheme code, there's no way `s'
can suddenly reappear at the Scheme level because GnuTLS doesn't have
any function that would return `s'.  Thus, the race condition you
described cannot happen.

The key insight here is that `S' and `s' "aggregate" `P', i.e., the
lifetime of `S' and `s' is always greater than or equal to that of `P'.


I presume that this scheme is applicable to many (most?) object-oriented
APIs.  It's actually what lead to the inception of the `aggregated'
typespec in G-Wrap [1].

Now, I haven't considered call-backs.  But maybe a call-back can be seen
as a procedure that's aggregated by some object; in turn, the procedure
refer to other objects in its environment, such that the lifetime of the
objects involved is similarly hierarchical.

Sorry for the digression but I think it's important to know whether
Guile's API intrinsically makes it hard to handle such common use cases.

Thanks,
Ludo'.

[0] 
http://git.savannah.gnu.org/gitweb/?p=gnutls.git;a=blob;f=guile/src/core.c#l42
[1] http://www.nongnu.org/g-wrap/manual/Wrapping-a-C-Function.html





reply via email to

[Prev in Thread] Current Thread [Next in Thread]