This is the mail archive of the guile@cygnus.com mailing list for the guile project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Russ McManus <russell.mcmanus@gs.com> writes: > Marius Vollmer <mvo@zagadka.ping.de> writes: > > > Let me drone on a little bit. > > I read your discussion with great interest, because I have given this > problem a bit of thought myself in the context of some of the programs > I've written that use guile, and that also have to play nice with > external systems that do their own resource management. Yes, one of my motivations was to solve this problem in general, even if in the specific situation involving Gtk+ there might be cheaper copouts. I was reasonably happy once I discovered a theoretically pleasing and sound method so I just implemented that and stopped thinking too hard about possible trade-offs between efficiency and elegance. Should the counting and tracing prove to have an unacceptable overhead, I might have to revisit this issue, but for now I'm going for perfectionism. > What is interesting to me about your strategy is that it attempts to > share the responsibility for the lifetime of an object between the > Scheme world and the outside world. Generally I have given up and > given ultimate control of an object's lifetime to one of the two > worlds. From your description, it sounds like the in-between strategy > can work, with a signficant amount of additional complexity. I'm not sure if the additional complexity is really significant. I have not profiled the thing, and now that I think about it, there might be one combinatorial explosion in the code that could be avoided, but even when you have a CList with 10000 entries (widgets) the GC pauses are barely noticable. There is a certain additional `mental' complexity in the algorithm, but that shouldn't matter much. > GTK widgets are an interesting application for this idea, because > AFAIK, the object's lifetimes really are determined outside of the > Scheme world's domain, because the user can tell the X server to nuke > a particular window at any time. A Gtk widget leads a complicated life, especially when getting retired. When the users tells a widget to go away, it is "destroyed". This destruction is a normal event, like a button click, as far as Scheme is concerned. The widget looses its XWindow and most of its useful functionality, but it is still there. It still has state and can be queried about it, for example. The reference count of the widget controls only the `internal' resources, like the memory for the struct of the widget, the GtkStyle that hangs off of it, and so on. When the last reference count is removed, the widget is `finalized', which amounts to really freeing the underlying memory. [There is now an additional action called `shutdown' which I don't understand.] So, even when a widget has been destroyed, the user (regardless whether C or Scheme) can still deal with that widget just fine. He can still query the state of the thing. In fact, the distinction between destruction and finalization is more important to C than to Scheme or any other language binding that has proxies. C needs to have a way to keep a widget struct from disappearing so that it can store pointers to it and be sure that they don't go away. Originally, destruction and finalization were combined in Gtk+ and thus you could either keep a widget struct around, or allow the XWindow to go away. Not a nice situation. > What does it mean then to have a live Scheme object representing a > GTK widget, if that widget's window is gone? At that point, a > nonzero reference count still doesn't leave you with a useful > object. You have still a valid widget, but one that is in a `destroyed' state (there is even a flag you can test). I'm not sure if the destroyed state is well defined, tho, because I'm not sure if you can haul a widget back into life by `realizing' it again or some such and if Gtk+ can sanely deal with attempts to do so. > What about the situation when the lifetime of the object is decided > outside of Scheme? Then it's possible, or even likely that captured > references to these object will become stale at some point. The > approach I have adopted is stolen from Emacs's buffer handling. The Gtk+ approach is about the same, using the `destroyed' state of a widget. I found it to be the cleanest approach when proxy and widget live and die together so that they can really be treated as an atomic unit. For example, you can put the proxy into a weak hash table and it will stay there as long as the widget is in use by the GUI even if there are no other references to it from Scheme. I think it is important that this works, but when the link from the widget to the proxy is weak, your proxy can be collected prematurly. On the other hand, a dying proxy should take the widget with it, when there are no other references to the widget. Consider the case where the user creates a widget and then does absolutely nothing with it. The proxy gets collected and the widget needs to go, too, but when the link from proxy to the widget is weak, it can't do that because it wouldn't be enough to keep the widget alive in the first place. So, both links need to be `strong', which would be no problem if Gtk+ would use a tracing collector as well (and Guile's and Gtk's collector could be made to cooperate), but it only has ref counting, so we need to look out for cycles, which leads to the complicated machinery described in my previous post. > So if I were writing a GTK interface, I would have just used > 'widget-live?' or some such. Maybe this is a loser for some reasons > that I'm missing, but the strategy has worked for me in other > contexts. I started out this way, too. The predicate was called `gtk-destroyed?', I think. I'm not really sure if the argumentation for requiring both links to be strong is really `forcing', but for now I have pretty much convinced myself that anything else has worse problems. - Marius -- GNOME: First Church of Appliantology