* [PATCH] Marking weak alist vectors @ 2005-11-08 17:22 Ludovic Courtès 2005-11-08 23:51 ` Marius Vollmer ` (2 more replies) 0 siblings, 3 replies; 35+ messages in thread From: Ludovic Courtès @ 2005-11-08 17:22 UTC (permalink / raw) Hi, The patch below fixes a bug in the garbage collection process of weak alist vectors. Without the patch, a value attached to a weak key (or the opposite) may be freed just _before_ the weak key in question is freed. The problem stems from the fact that `scm_i_mark_weak_vector_non_weaks ()' would not mark a value attached to a weak key if that weak key is unmarked. Therefore, both the weak key and its associated value become unmarked during the very same mark phase. And since the order in which they are swept during the subsequent sweep phase is undefined, we have a problem. The patch fixes `scm_i_mark_weak_vector_non_weaks ()'. This way, a value attached to a weak key will only become unmarked during the mark phase _after_ the mark phase during which its weak key became unmarked. You might want to re-read this sentence carefully. ;-) I wrote a test case for this which is to be installed as `test-suite/standalone/test-weaks.c'. It uses object properties. This patch has an undesired side effect: it makes `gc.test' fail. I'll have to dig into this. But we probably had better treat this problem independently given this (using Guile CVS): $ guile guile> (gc-live-object-stats) Segmentation fault (core dumped) BTW, in `scm_init_properties ()', SCM_PROPERTIES_WHASH was not made permanent, which looks like an error. Thanks, Ludovic. libguile/ChangeLog 2005-11-08 Ludovic Courtès <ludovic.courtes@laas.fr> * gc-mark.c (scm_mark_all): Removed C++/C99-style comment. * properties.c (scm_init_properties): Make SCM_PROPERTIES_WHASH a permanent object. * weaks.c (weak_vectors): Initialize it to `SCM_EOL'. (scm_i_mark_weak_vector_non_weaks): When WEAK_KEYS is false and KEY is unmarked, mark it recursively. Likewise, when WEAK_VALUES if false and VALUE is unmarked, mark it recursively. (scm_i_remove_weaks): Don't only check whether the first pair in ALIST is unmarked: check whether either its KEY (when WEAK_KEYS is true) or VALUE (when WEAK_VALUES is true) is unmarked. test-suite/ChangeLog 2005-11-08 Ludovic Courtès <ludovic.courtes@laas.fr> * standalone/Makefile.am (TESTS): Added `test-weaks'. (check_PROGRAMS): Likewise. * standalone/test-weaks.c: New file. \f --- orig/libguile/gc-mark.c +++ mod/libguile/gc-mark.c @@ -74,7 +74,7 @@ scm_i_init_weak_vectors_for_gc (); scm_i_init_guardians_for_gc (); - + scm_i_clear_mark_space (); /* Mark every thread's stack and registers */ @@ -138,12 +138,9 @@ break; } - //fprintf (stderr, "%d loops\n", loops); - - /* Remove all unmarked entries from the weak vectors. - */ + /* Remove all unmarked entries from the weak vectors. */ scm_i_remove_weaks_from_weak_vectors (); - + /* Bring hashtables upto date. */ scm_i_scan_weak_hashtables (); --- orig/libguile/properties.c +++ mod/libguile/properties.c @@ -125,6 +125,7 @@ scm_init_properties () { scm_properties_whash = scm_make_weak_key_hash_table (SCM_UNDEFINED); + scm_properties_whash = scm_permanent_object (scm_properties_whash); #include "libguile/properties.x" } --- orig/libguile/weaks.c +++ mod/libguile/weaks.c @@ -205,7 +205,11 @@ #define UNMARKED_CELL_P(x) (SCM_NIMP(x) && !SCM_GC_MARK_P (x)) -static SCM weak_vectors; +/* A list of live weak vectors, updated each time a weak vector is marked (in + `scm_i_mark_weak_vector ()') and cleared at the beginning of each mark + phase (in `scm_mark_all ()' which calls + `scm_i_init_weak_vectors_for_gc ()'). */ +static SCM weak_vectors = SCM_EOL; void scm_i_init_weak_vectors_for_gc () @@ -264,14 +268,18 @@ { SCM key = SCM_CAR (elt); SCM value = SCM_CDR (elt); - - if (!((weak_keys && UNMARKED_CELL_P (key)) - || (weak_values && UNMARKED_CELL_P (value)))) + + if ((!weak_keys) && (UNMARKED_CELL_P (key))) + scm_gc_mark (key); + + if ((!weak_values) && (UNMARKED_CELL_P (value))) + scm_gc_mark (value); + + if ((!UNMARKED_CELL_P (key)) + && (!UNMARKED_CELL_P (value))) { - /* The item should be kept. We need to mark it - recursively. - */ - scm_gc_mark (elt); + /* The whole pair should be kept. */ + SCM_SET_GC_MARK (elt); again = 1; } } @@ -323,6 +331,8 @@ { SCM *ptr = SCM_I_WVECT_GC_WVELTS (w); size_t n = SCM_I_WVECT_LENGTH (w); + int weak_keys = SCM_IS_WHVEC (w) || SCM_IS_WHVEC_B (w); + int weak_values = SCM_IS_WHVEC_V (w) || SCM_IS_WHVEC_B (w); size_t i; if (!SCM_IS_WHVEC_ANY (w)) @@ -343,8 +353,13 @@ alist = *fixup; while (scm_is_pair (alist) && !SCM_GC_MARK_P (alist)) { - if (UNMARKED_CELL_P (SCM_CAR (alist))) + SCM elt = SCM_CAR (alist); + SCM key = SCM_CAR (elt), value = SCM_CDR (elt); + + if ((weak_keys && UNMARKED_CELL_P (key)) + || (weak_values && UNMARKED_CELL_P (value))) { + /* Remove this pair from ALIST. */ *fixup = SCM_CDR (alist); delta++; } --- orig/test-suite/standalone/Makefile.am +++ mod/test-suite/standalone/Makefile.am @@ -74,6 +74,13 @@ check_PROGRAMS += test-conversion TESTS += test-conversion +# test-weaks +test_weaks_SOURCES = test-weaks.c +test_weaks_CFLAGS = ${test_cflags} +test_weaks_LDADD = ${top_builddir}/libguile/libguile.la +check_PROGRAMS += test-weaks +TESTS += test-weaks + all-local: cd ${srcdir} && chmod u+x ${check_SCRIPTS} \f test-weaks.c: --8<---------------cut here---------------start------------->8--- /* Copyright (C) 2005 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This test case targets garbage collection of weak hash tables. It does so by using object properties (which are currently implemented using weak hash tables) and verifying that properties attached to an object are always GC'd _after_ the object itself has been freed. In order to do so, `test_weak_gc ()' creates a number of SMOBs. The C structure underlying those SMOBs explicitly maintains a reference counter for each instance. This reference counter is: 1. incremented each time a SMOB is attached to another SMOB (by means of object properties); 2. decremented each time a SMOB that was attached to another SMOB is freed. For instance if A is attached to B, when B is GC'd, A's reference counter is decremented. The invariant that we check is: any SMOB that is GC'd must have its reference count equal to zero. */ #include "libguile.h" #include <stdio.h> #include <assert.h> /* Number of time a `my-object' SMOB was freed. */ static unsigned free_count = 0; static scm_t_bits my_object_type = 0; static SCM some_property = SCM_BOOL_F; static SCM my_object_new_smob_proc = SCM_BOOL_F, attach_object_proc = SCM_BOOL_F; typedef struct my_object { struct my_object *attached_to; unsigned ref_count; int freed; } my_object_t; static void my_object_init (my_object_t *obj) { obj->attached_to = NULL; obj->ref_count = 0; obj->freed = 0; } static size_t my_object_free (SCM obj) { my_object_t *my_object = (my_object_t *)SCM_SMOB_DATA (obj); if (my_object->attached_to) { /* Decrease the reference count of the object MY_OBJECT is attached to. */ assert (my_object->attached_to->ref_count > 0); my_object->attached_to->ref_count--; } /* MY_OBJECT must not have been already freed and there must be no pending references to it. */ assert (!my_object->freed); assert (my_object->ref_count == 0); my_object->freed = 1; free_count++; return 0; } \f /* Return a new `my-object' SMOB. */ static SCM my_object_new_smob (void) { my_object_t *obj; obj = scm_malloc (sizeof (*obj)); my_object_init (obj); SCM_RETURN_NEWSMOB (my_object_type, obj); } /* Attach TO_BE_ATTACHED to OBJ. */ static SCM attach_object (SCM obj, SCM to_be_attached) { my_object_t *c_obj, *c_to_be_attached; assert (SCM_SMOB_PREDICATE (my_object_type, obj)); assert (SCM_SMOB_PREDICATE (my_object_type, to_be_attached)); /* TO_BE_ATTACHED is attached as a property of OBJ. As such, OBJ will get GC'd _before_ TO_BE_ATTACHED. */ scm_primitive_property_set_x (some_property, obj, to_be_attached); c_obj = (my_object_t *)SCM_SMOB_DATA (obj); c_to_be_attached = (my_object_t *)SCM_SMOB_DATA (to_be_attached); /* Because TO_BE_ATTACHED is to be freed _after_ OBJ, we can increase its reference count and it should be zero by the time it is freed. */ c_to_be_attached->ref_count++; c_obj->attached_to = c_to_be_attached; return obj; } \f /* Instantiate a number of `my-object' SMOBs, attached some of them together, invoke the GC, and wait until all of these SMOBs have been freed. */ static void test_weak_gc (void) { #define PAIRS 500 unsigned pair_count, total; for (pair_count = 0, total = 0; pair_count < PAIRS; pair_count++) { SCM obj, attached; obj = my_object_new_smob (); attached = my_object_new_smob (); #if 0 printf ("%p attached to %p\n", SCM_SMOB_DATA (obj), SCM_SMOB_DATA (attached)); #endif attach_object (obj, attached); my_object_new_smob (); total += 3; obj = attached = SCM_BOOL_F; } while (free_count < total) { unsigned i; scm_gc (); for (i = 0; i < 1000; i++) scm_cons (SCM_I_MAKINUM (0), SCM_I_MAKINUM (0)); } } \f int main (int argc, char *argv[]) { scm_init_guile (); my_object_type = scm_make_smob_type ("test-object", 0); scm_set_smob_free (my_object_type, my_object_free); some_property = scm_primitive_make_property (SCM_BOOL_F); my_object_new_smob_proc = scm_c_make_gsubr ("make-my-object", 0, 0, 0, my_object_new_smob); attach_object_proc = scm_c_make_gsubr ("attach-object!", 0, 0, 0, attach_object); test_weak_gc (); return 0; } --8<---------------cut here---------------end--------------->8--- _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-08 17:22 [PATCH] Marking weak alist vectors Ludovic Courtès @ 2005-11-08 23:51 ` Marius Vollmer 2005-11-09 9:03 ` Ludovic Courtès 2005-11-09 10:28 ` Han-Wen Nienhuys 2005-11-17 13:21 ` [PATCH] Fixing `gc-live-object-stats' Ludovic Courtès 2 siblings, 1 reply; 35+ messages in thread From: Marius Vollmer @ 2005-11-08 23:51 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > The problem stems from the fact that > `scm_i_mark_weak_vector_non_weaks ()' would not mark a value > attached to a weak key if that weak key is unmarked. Therefore, > both the weak key and its associated value become unmarked during > the very same mark phase. And since the order in which they are > swept during the subsequent sweep phase is undefined, we have a > problem. I still have to read your patch carefully, but just from your description of the problem, I would say that nothing is actually wrong. We don't make any guarantees about the sequence in which objects are 'freed' that are unreachable. This should only matter for smobs with their user written FREE procedures. The manual says: The FREE procedure must deallocate all resources that are directly associated with the smob instance OBJ. It must assume that all `SCM' values that it references have already been freed and are thus invalid. It must also not call any libguile function or macro except `scm_gc_free', `SCM_SMOB_FLAGS', `SCM_SMOB_DATA', `SCM_SMOB_DATA_2', and `SCM_SMOB_DATA_3'. No? > $ guile > guile> (gc-live-object-stats) > Segmentation fault (core dumped) > > BTW, in `scm_init_properties ()', SCM_PROPERTIES_WHASH was not made > permanent, which looks like an error. I'll look at these two issues first. -- GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405 _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-08 23:51 ` Marius Vollmer @ 2005-11-09 9:03 ` Ludovic Courtès 2005-12-06 23:55 ` Marius Vollmer 0 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-11-09 9:03 UTC (permalink / raw) Cc: guile-devel Hi Marius, Marius Vollmer <mvo@zagadka.de> writes: > I still have to read your patch carefully, but just from your > description of the problem, I would say that nothing is actually > wrong. We don't make any guarantees about the sequence in which > objects are 'freed' that are unreachable. > > This should only matter for smobs with their user written FREE > procedures. The manual says: [About SMOBs' being freed] The relevant part of the manual with respect to this issue is the following (in node `Weak References'): Weak references let you attach bookkeeping information to data so that the additional information automatically disappears when the original data is no longer in use and gets garbage collected. In a weak key hash, the hash entry for that key disappears as soon as the key is no longer referenced from anywhere else. Likewise (in `Object Properties'): Internally, object properties are implemented using a weak key hash table. This means that, as long as a Scheme value with property values is protected from garbage collection, its property values are also protected. When the Scheme value is collected, its entry in the property table is removed and so the (ex-) property values are no longer protected by the table. IOW, property values are to be "collected" _after_ the Scheme value to which they are attached has been collected. Admittedly, the manual is quite fuzzy as to whether "after" means "during the next round of mark/sweep" or "maybe during the same round of mark/sweep but at least property values are swept after the Scheme value has been swept". In any case, if a value P is attached as a property of some object O, then O should be "collected" _before_ P. In practice, if both O and P are SMOBs, then this means that O should be "freed" before P. Please, have a look at the `test-weaks.c' file I posted. It attaches SMOBs as properties of other SMOBs. And it's maybe clearer than long explanations. ;-) Thanks, Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-09 9:03 ` Ludovic Courtès @ 2005-12-06 23:55 ` Marius Vollmer 2005-12-07 10:33 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Marius Vollmer @ 2005-12-06 23:55 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > IOW, property values are to be "collected" _after_ the Scheme value to > which they are attached has been collected. The manual talks from the perspective of a Scheme program here. For a Scheme program, the important information is that some object is not collected _before_ some condition is true. Thus, the wording in the manual should be read as 'not before' instead of as 'strictly after'. Maybe we should change the manual accordingly. C code can observe the GC doing its thing (via the smob free functions). In order not to overconstrain the implementation of the GC (which is pretty constrained already anyway), we have the additional rule that there is no guarantee about the order in which objects are swept during the sweep phase. Why do you need this guarantee? (If you really need this feature, I will start talking you into using guardians to enforce some order on finalization.) > In any case, if a value P is attached as a property of some object O, > then O should be "collected" _before_ P. Why? Isn't it enough to say 'P is not collected before O is unreachable'? GC's usually don't make any guarantee about what happens with an object it has become unreachable. For example, once O and P become unreachable, it would be totally acceptable for a GC to collect P but to never get around to actually collect O. (The GC could be generational: O could be in the oldest generation and P in the youngest. The youngest generation might be collected every MiB of allocated memory, but the oldest generation might only be collected on weekends and during national holidays. :) -- GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405 _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-12-06 23:55 ` Marius Vollmer @ 2005-12-07 10:33 ` Ludovic Courtès 2005-12-13 23:45 ` Marius Vollmer 0 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-12-07 10:33 UTC (permalink / raw) Cc: guile-devel Marius Vollmer <mvo@zagadka.de> writes: > C code can observe the GC doing its thing (via the smob free > functions). In order not to overconstrain the implementation of the > GC (which is pretty constrained already anyway), we have the > additional rule that there is no guarantee about the order in which > objects are swept during the sweep phase. Relaxing such constraints may work for Scheme objects that are entirely under Guile's control, but it certainly isn't acceptable when SMOBs come into play: SMOBs _will_ from time to time be victims of this, resulting in double-frees and the likes. SMOBs shouldn't ever have the impression that a value attached to a weak key is freed _before_ that weak key. From the SMOB programmer viewpoint that is really an error, no matter if it's "before but during the same phase" or not. > Why do you need this guarantee? For a concrete example, you may want to look at `test-weaks.c' which I posted when this discussion started, i.e. a long time ago. ;-) For a more general example where this is an issue: http://lists.nongnu.org/archive/html/g-wrap-dev/2005-09/msg00006.html (see at the bottom). > (If you really need this feature, I will start talking you into using > guardians to enforce some order on finalization.) I hadn't look into this so far, and indeed, that looks interesting! That's a nice reflexive approach to GC. I don't think it solves my very problem though. >> In any case, if a value P is attached as a property of some object O, >> then O should be "collected" _before_ P. > > Why? Isn't it enough to say 'P is not collected before O is unreachable'? If user-definable objects (SMOBs) didn't exist, that would be perfectly fine. But the mere existence of SMOBs prevents such optimizations. Why would we like to retain such sloppy semantics which are problematic to the C (SMOB) programmer? Thanks, Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-12-07 10:33 ` Ludovic Courtès @ 2005-12-13 23:45 ` Marius Vollmer 2005-12-14 9:30 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Marius Vollmer @ 2005-12-13 23:45 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > Marius Vollmer <mvo@zagadka.de> writes: > >> C code can observe the GC doing its thing (via the smob free >> functions). In order not to overconstrain the implementation of the >> GC (which is pretty constrained already anyway), we have the >> additional rule that there is no guarantee about the order in which >> objects are swept during the sweep phase. > > Relaxing such constraints may work for Scheme objects that are entirely > under Guile's control, but it certainly isn't acceptable when SMOBs come > into play: SMOBs _will_ from time to time be victims of this, resulting > in double-frees and the likes. Yes, SMOBs could profit from a guarantee about the order of finalization, but I don't think that guarantee can be implemented cheaply enough. (Or can it?) So, my current point of view is that smobs have to suffer in order to make live easier for the GC. > SMOBs shouldn't ever have the impression that a value attached to a weak > key is freed _before_ that weak key. This would not only apply to weak keys etc, but to all kinds of references, right? I.e., all SCM values belonging to a smob would be guaranteed to be valid when the free function for that smob is called. Thus, we are not only talking about your patch for weak hash tables, but about big changes to the GC in general, right? >> Why do you need this guarantee? > > For a concrete example, you may want to look at `test-weaks.c' which I > posted when this discussion started, i.e. a long time ago. ;-) Heh, that is not an example, that is a test case. :-) > For a more general example where this is an issue: > http://lists.nongnu.org/archive/html/g-wrap-dev/2005-09/msg00006.html > (see at the bottom). (I only read the article you linked to directly, not the thread.) So you have a C API that requires a certain order for freeing objects and that order needs to be honored by the smobs that wrap the objects, right? My immediate reaction is to suggest to fix this by layering something on top of the C API, such as the reference counting that you mention in your article. (Refcounting is acceptable since cycles must be prevented anyway.) I agree that it would be nice to have Guile help with that, if only by providing proven example code. >> (If you really need this feature, I will start talking you into using >> guardians to enforce some order on finalization.) > > I hadn't look into this so far, and indeed, that looks interesting! > That's a nice reflexive approach to GC. > > I don't think it solves my very problem though. Yeah, you might be right... > Why would we like to retain such sloppy semantics which are problematic > to the C (SMOB) programmer? Because we would need to change the GC significantly... that's the only reason I can think of. But note that the thing we are talking about now is very different from what you started out with: now we are not talking about in which run of the GC a value belonging to a weak key is collected (i.e., the key in run n, the value in run n+1), but in what order objects are finalized within a single run of the GC (if I am not confused now). -- GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405 _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-12-13 23:45 ` Marius Vollmer @ 2005-12-14 9:30 ` Ludovic Courtès 0 siblings, 0 replies; 35+ messages in thread From: Ludovic Courtès @ 2005-12-14 9:30 UTC (permalink / raw) Cc: guile-devel Hi Marius, Marius Vollmer <mvo@zagadka.de> writes: > Yes, SMOBs could profit from a guarantee about the order of > finalization, but I don't think that guarantee can be implemented > cheaply enough. (Or can it?) > > So, my current point of view is that smobs have to suffer in order to > make live easier for the GC. IMO, it's not just a fancy improvement for SMOBs but a requirement. That is, if we cannot provide this guarantee, then we have to either completely remove SMOBs (hmm, not sure this is a good idea ;-)) or disallow their use in weak vectors. Again, for the SMOB programmer viewpoint, the order of "finalization" is something that should be taken seriously. >> SMOBs shouldn't ever have the impression that a value attached to a weak >> key is freed _before_ that weak key. > > This would not only apply to weak keys etc, but to all kinds of > references, right? I.e., all SCM values belonging to a smob would be > guaranteed to be valid when the free function for that smob is called. > Thus, we are not only talking about your patch for weak hash tables, > but about big changes to the GC in general, right? Well, maybe you're extrapolating too much. ;-) Of course, this issue is very similar to the one I raised initially. However, a SMOB that embeds SCM values knows that it is responsible for marking them. Therefore, when a SMOB is freed (because it hasn't been marked), it knows that the SCM values under its control may have remained unmarked as well and may have been GC'd. So I think the semantics here are different: you cannot reasonably expect SCM values embedded within a SMOB to be freed after the SMOB. > Heh, that is not an example, that is a test case. :-) Yeah, but it's pretty close to an example. ;-) >> For a more general example where this is an issue: >> http://lists.nongnu.org/archive/html/g-wrap-dev/2005-09/msg00006.html >> (see at the bottom). > > (I only read the article you linked to directly, not the thread.) > > So you have a C API that requires a certain order for freeing objects > and that order needs to be honored by the smobs that wrap the objects, > right? Right. > My immediate reaction is to suggest to fix this by layering something > on top of the C API, such as the reference counting that you mention > in your article. (Refcounting is acceptable since cycles must be > prevented anyway.) Sure, reference counting is the usual way to solve that problem (for instance, that's how glib, gnet, etc. solve this). But I was convinced that using object properties would achieve the same goal much more easily. > But note that the thing we are talking about now is very different > from what you started out with: now we are not talking about in which > run of the GC a value belonging to a weak key is collected (i.e., the > key in run n, the value in run n+1), but in what order objects are > finalized within a single run of the GC (if I am not confused now). As stated earlier, I think your attempt to generalize the problem is unfruitful. ;-) I.e., IMO, the general issue of the order of finalization within a single run of the GC isn't an actual issue. We can really tackle the first problem (i.e., "in which run a value belonging to the GC is collected") without having to worry about the order of finalization in general. Furthermore, I think the patch shows that the first issue can be fixed without introducing a significant performance cost. The second version of the patch introduces _some_ overhead in `scm_i_remove_weaks ()', because it needs to iterate on MARK_QUEUE, but that doesn't seem to be too much of a burden. In [0], this issue is not even mentioned. In fact, I believe it is quite specific to Guile since other Scheme implementations maybe don't have such a large C API. Further research suggests that this is also an issue in languages such as SmallTalk where finalization is visible to the application [1,2]. The Java specs (almost) clearly state that a weak reference is only finalized after the object it refers to has become "weakly reachable" (well, in the end it says nothing about the finalization of the object itself...) [3]. Thanks, Ludovic. [0] http://www.haible.de/bruno/papers/cs/weak/WeakDatastructures-writeup.html [1] http://mail.python.org/pipermail/python-dev/2003-November/040299.html [2] http://www.mimuw.edu.pl/~sl/teaching/00_01/Delfin_EC/Overviews/WeakReferencesAndFinalization.htm [3] http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ref/WeakReference.html _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-08 17:22 [PATCH] Marking weak alist vectors Ludovic Courtès 2005-11-08 23:51 ` Marius Vollmer @ 2005-11-09 10:28 ` Han-Wen Nienhuys 2005-11-09 16:28 ` Ludovic Courtès 2005-11-17 13:21 ` [PATCH] Fixing `gc-live-object-stats' Ludovic Courtès 2 siblings, 1 reply; 35+ messages in thread From: Han-Wen Nienhuys @ 2005-11-09 10:28 UTC (permalink / raw) Ludovic Courtès wrote: > The patch fixes `scm_i_mark_weak_vector_non_weaks ()'. This way, a > value attached to a weak key will only become unmarked during the mark > phase _after_ the mark phase during which its weak key became unmarked. > You might want to re-read this sentence carefully. ;-) Does your patch solve the problem that cyclical structures (values that point back to keys) should also be GC-ed? > /* Attach TO_BE_ATTACHED to OBJ. */ > static SCM > attach_object (SCM obj, SCM to_be_attached) > { > my_object_t *c_obj, *c_to_be_attached; > > assert (SCM_SMOB_PREDICATE (my_object_type, obj)); > assert (SCM_SMOB_PREDICATE (my_object_type, to_be_attached)); > > /* TO_BE_ATTACHED is attached as a property of OBJ. As such, OBJ will get > GC'd _before_ TO_BE_ATTACHED. */ > scm_primitive_property_set_x (some_property, obj, to_be_attached); Why are you storing SCM references as properties? It's more efficient both in time and space to use a SCM member in my_object_t. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-09 10:28 ` Han-Wen Nienhuys @ 2005-11-09 16:28 ` Ludovic Courtès 2005-11-09 18:36 ` Han-Wen Nienhuys ` (2 more replies) 0 siblings, 3 replies; 35+ messages in thread From: Ludovic Courtès @ 2005-11-09 16:28 UTC (permalink / raw) Cc: guile-devel Han-Wen Nienhuys <hanwen@xs4all.nl> writes: > Does your patch solve the problem that cyclical structures (values that > point back to keys) should also be GC-ed? I guess you're talking about cyclical structures in doubly-weak alist vectors. If so, it apparently does since if both WEAK_VALUES and WEAK_KEYS are false in both functions, then neither the key nor the value will ever be marked by those functions. Actually, I've spent some time re-reviewing this patch and I'm having starting to have a headache. But anyway, here are a few thoughts. 1. The tests in `weaks.test' are broken in several ways, not only because "we have no way of knowing for certain that the object is really dead" as stated there. * First, they assume that (begin (hashq-set! h "a string" 123) (hashq-ref h "a string)) returns true. This is wrong since `hashq-ref' uses `eq?' to compare keys, and `(eq? "a string" "a string")' returns #f. Instead, it could use `hash-map->list'. * Second, it should perform a `(read-disable 'positions)' since source properties rely on a weakly-keyed hash table where keys are source expressions. 2. The C test I submitted, unlike `weaks.test', can *reliably* determine whether an object was swept. However, it is clearly not as complete as `weaks.test'. 3. Given the level of non-determinism I've been able to observe, I'm afraid leaks are causing us difficulties. For instance, while testing weakly-key alist vectors "by hand" in a REPL, it occurred to me that the weak-key pair would reliably die, *unless* the hash table was written (I mean using `write'): guile> (define h (make-doubly-weak-alist-vector 12)) guile> (hashq-set! h "sdf" "paf") guile> (hashq-set! h "hello" "world") guile> (gc) guile> h #w(() () () () () () () () () () () ()) The same but print H before calling `gc': guile> (hashq-set! h "sdf" "paf") guile> (hashq-set! h "hello" "world") guile> h #w((("hello" . "world") ("sdf" . "paf")) () () () () () () () () () () ()) guile> (gc) guile> (gc) guile> (gc) guile> h #w((("hello" . "world") ("sdf" . "paf")) () () () () () () () () () () ()) 4. Looking a Bruno Haible's paper[0] on this topic, it seems that getting it right is, well, pretty hard. ;-) > Why are you storing SCM references as properties? It's more efficient > both in time and space to use a SCM member in my_object_t. That's the whole point of the test: object properties are used because they involve weak hash tables. Thanks, Ludovic. [0] http://www.haible.de/bruno/papers/cs/weak/WeakDatastructures-writeup.html _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-09 16:28 ` Ludovic Courtès @ 2005-11-09 18:36 ` Han-Wen Nienhuys 2005-11-09 21:11 ` Kevin Ryde 2005-11-23 10:19 ` [PATCH] Marking weak alist vectors, #2 Ludovic Courtès 2 siblings, 0 replies; 35+ messages in thread From: Han-Wen Nienhuys @ 2005-11-09 18:36 UTC (permalink / raw) Cc: guile-devel Ludovic Courtès wrote: >>Does your patch solve the problem that cyclical structures (values that >>point back to keys) should also be GC-ed? > > > I guess you're talking about cyclical structures in doubly-weak alist > vectors. If so, it apparently does since if both WEAK_VALUES and > WEAK_KEYS are false in both functions, then neither the key nor the > value will ever be marked by those functions. Actually, I was talking about tables with only weak keys, but strong values. > 1. The tests in `weaks.test' are broken in several ways, not only > because "we have no way of knowing for certain that the object is > really dead" as stated there. You can detect whether objects died; just generate a lot of them, and see what happens to the stats the output of (gc-live-object-stats) after a few GCs. > 3. Given the level of non-determinism I've been able to observe, I'm > afraid leaks are causing us difficulties. For instance, while > testing weakly-key alist vectors "by hand" in a REPL, it occurred to > me that the weak-key pair would reliably die, *unless* the hash > table was written (I mean using `write'): Curious; why does this happen? > That's the whole point of the test: object properties are used because > they involve weak hash tables. In that case, I'm missing the point completely; why do you need this functionality? -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-09 16:28 ` Ludovic Courtès 2005-11-09 18:36 ` Han-Wen Nienhuys @ 2005-11-09 21:11 ` Kevin Ryde 2005-11-09 22:45 ` Marius Vollmer 2005-11-10 9:47 ` [PATCH] Reference leak in `iprin1 ()' Ludovic Courtès 2005-11-23 10:19 ` [PATCH] Marking weak alist vectors, #2 Ludovic Courtès 2 siblings, 2 replies; 35+ messages in thread From: Kevin Ryde @ 2005-11-09 21:11 UTC (permalink / raw) Cc: Han-Wen Nienhuys ludovic.courtes@laas.fr (Ludovic Courtès) writes: > > For instance, while > testing weakly-key alist vectors "by hand" in a REPL, it occurred to > me that the weak-key pair would reliably die, *unless* the hash > table was written (I mean using `write'): I may have struck that or something similar a while back. Mikael explained it was a reference held in the print data of the output port, or something. Used to detect cyclic structures, or something. I don't think I understood why such a reference ought to persist once outside the print, I'd suspect it'd be better if it didn't, if that could be arranged. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-09 21:11 ` Kevin Ryde @ 2005-11-09 22:45 ` Marius Vollmer 2005-11-10 12:11 ` Han-Wen Nienhuys 2005-11-10 9:47 ` [PATCH] Reference leak in `iprin1 ()' Ludovic Courtès 1 sibling, 1 reply; 35+ messages in thread From: Marius Vollmer @ 2005-11-09 22:45 UTC (permalink / raw) Cc: Han-Wen Nienhuys Kevin Ryde <user42@zip.com.au> writes: > ludovic.courtes@laas.fr (Ludovic Courtès) writes: >> >> For instance, while >> testing weakly-key alist vectors "by hand" in a REPL, it occurred to >> me that the weak-key pair would reliably die, *unless* the hash >> table was written (I mean using `write'): > > I may have struck that or something similar a while back. Mikael > explained it was a reference held in the print data of the output > port, or something. Used to detect cyclic structures, or something. > I don't think I understood why such a reference ought to persist once > outside the print, I'd suspect it'd be better if it didn't, if that > could be arranged. If I remember right, I have been in exactly this spot as well, but I couldn't really fix this. I don't remember why, unfortunately... -- GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3 331E FAF8 226A D5D4 E405 _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors 2005-11-09 22:45 ` Marius Vollmer @ 2005-11-10 12:11 ` Han-Wen Nienhuys 0 siblings, 0 replies; 35+ messages in thread From: Han-Wen Nienhuys @ 2005-11-10 12:11 UTC (permalink / raw) Marius Vollmer wrote: >>I may have struck that or something similar a while back. Mikael >>explained it was a reference held in the print data of the output >>port, or something. Used to detect cyclic structures, or something. >>I don't think I understood why such a reference ought to persist once >>outside the print, I'd suspect it'd be better if it didn't, if that >>could be arranged. > > > If I remember right, I have been in exactly this spot as well, but I > couldn't really fix this. I don't remember why, unfortunately... Isn't this a matter of clearing the print state at the end of scm_prin1() ? -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] Reference leak in `iprin1 ()' 2005-11-09 21:11 ` Kevin Ryde 2005-11-09 22:45 ` Marius Vollmer @ 2005-11-10 9:47 ` Ludovic Courtès 2005-11-12 9:23 ` Neil Jerram 1 sibling, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-11-10 9:47 UTC (permalink / raw) Cc: Han-Wen Nienhuys Hi, Kevin Ryde <user42@zip.com.au> writes: > I may have struck that or something similar a while back. Mikael > explained it was a reference held in the print data of the output > port, or something. Used to detect cyclic structures, or something. Thanks: you put me on the right track! So this issue is now gone. :-) Ludovic. 2005-11-10 Ludovic Courtès <ludovic.courtes@laas.fr> * print.c (EXIT_NESTED_DATA): Before popping from the stack, reset the value at its top. This fixes a reference leak. --- orig/libguile/print.c +++ mod/libguile/print.c @@ -136,7 +136,13 @@ PUSH_REF(pstate, obj); \ } while(0) -#define EXIT_NESTED_DATA(pstate) { --pstate->top; } +#define EXIT_NESTED_DATA(pstate) \ +do \ +{ \ + PSTATE_STACK_SET (pstate, pstate->top, SCM_UNDEFINED); \ + --pstate->top; \ +} \ +while (0) SCM scm_print_state_vtable = SCM_BOOL_F; static SCM print_state_pool = SCM_EOL; @@ -144,8 +150,8 @@ #ifdef GUILE_DEBUG /* Used for debugging purposes */ -SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0, - (), +SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0, + (void), "Return the current-pstate -- the car of the\n" "@code{print_state_pool}. @code{current-pstate} is only\n" "included in @code{--enable-guile-debug} builds.") _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Reference leak in `iprin1 ()' 2005-11-10 9:47 ` [PATCH] Reference leak in `iprin1 ()' Ludovic Courtès @ 2005-11-12 9:23 ` Neil Jerram 2005-11-14 9:58 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Neil Jerram @ 2005-11-12 9:23 UTC (permalink / raw) Cc: Han-Wen Nienhuys ludovic.courtes@laas.fr (Ludovic Courtès) writes: > * print.c (EXIT_NESTED_DATA): Before popping from the stack, > reset the value at its top. This fixes a reference leak. Nice work, but it looks to me that PUSH_REF sets the value of the (pstate->top)th element _before_ incrementing pstate->top. So shouldn't your fix do the decrement first and then set the slot to undefined? (Note that your fix will still prevent most reference leaks, just not the outermost one. So that's why it may appear to be working already.) Also, is the () -> (void) change strictly related? Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Reference leak in `iprin1 ()' 2005-11-12 9:23 ` Neil Jerram @ 2005-11-14 9:58 ` Ludovic Courtès 2005-11-16 21:18 ` Neil Jerram 0 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-11-14 9:58 UTC (permalink / raw) Cc: Han-Wen Nienhuys, guile-devel Hello, Neil Jerram <neil@ossau.uklinux.net> writes: > Nice work, but it looks to me that PUSH_REF sets the value of the > (pstate->top)th element _before_ incrementing pstate->top. So > shouldn't your fix do the decrement first and then set the slot to > undefined? Yes, you're perfectly right. > (Note that your fix will still prevent most reference leaks, just not > the outermost one. So that's why it may appear to be working > already.) Exactly. > Also, is the () -> (void) change strictly related? In fact, it's strictly unrelated, but while we're at it (really `(void)' was meant here, not `()')... Below is an updated patch. I modified `PUSH_REF ()' as well so that it does PSTATE->TOP++ _after_ using the `PSTATE_STACK_SET ()' macro: this is safer. And, well, I couldn't resist the desire to "beautifully backslashify" `ENTER_NESTED_DATA ()' as well. :-) I hope this is not too much pollution for you. Thanks, Ludovic. 2005-11-14 Ludovic Courtès <ludovic.courtes@laas.fr> * print.c (EXIT_NESTED_DATA): Before popping from the stack, reset the value at its top. This fixes a reference leak. (PUSH_REF): Perform `pstate->top++' after calling `PSTATE_STACK_SET ()' in order to avoid undesired side effects. (scm_current_pstate): Replaced `()' by `(void)'. --- orig/libguile/print.c +++ mod/libguile/print.c @@ -112,31 +112,40 @@ * time complexity (O (depth * N)), The printer code can be * rewritten to be O(N). */ -#define PUSH_REF(pstate, obj) \ -do { \ - PSTATE_STACK_SET (pstate, pstate->top++, obj); \ - if (pstate->top == pstate->ceiling) \ - grow_ref_stack (pstate); \ +#define PUSH_REF(pstate, obj) \ +do \ +{ \ + PSTATE_STACK_SET (pstate, pstate->top, obj); \ + pstate->top++; \ + if (pstate->top == pstate->ceiling) \ + grow_ref_stack (pstate); \ } while(0) -#define ENTER_NESTED_DATA(pstate, obj, label) \ -do { \ - register unsigned long i; \ - for (i = 0; i < pstate->top; ++i) \ - if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \ - goto label; \ - if (pstate->fancyp) \ - { \ - if (pstate->top - pstate->list_offset >= pstate->level) \ - { \ - scm_putc ('#', port); \ - return; \ - } \ - } \ - PUSH_REF(pstate, obj); \ +#define ENTER_NESTED_DATA(pstate, obj, label) \ +do \ +{ \ + register unsigned long i; \ + for (i = 0; i < pstate->top; ++i) \ + if (scm_is_eq (PSTATE_STACK_REF (pstate, i), (obj))) \ + goto label; \ + if (pstate->fancyp) \ + { \ + if (pstate->top - pstate->list_offset >= pstate->level) \ + { \ + scm_putc ('#', port); \ + return; \ + } \ + } \ + PUSH_REF(pstate, obj); \ } while(0) -#define EXIT_NESTED_DATA(pstate) { --pstate->top; } +#define EXIT_NESTED_DATA(pstate) \ +do \ +{ \ + --pstate->top; \ + PSTATE_STACK_SET (pstate, pstate->top, SCM_UNDEFINED); \ +} \ +while (0) SCM scm_print_state_vtable = SCM_BOOL_F; static SCM print_state_pool = SCM_EOL; @@ -144,8 +153,8 @@ #ifdef GUILE_DEBUG /* Used for debugging purposes */ -SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0, - (), +SCM_DEFINE (scm_current_pstate, "current-pstate", 0, 0, 0, + (void), "Return the current-pstate -- the car of the\n" "@code{print_state_pool}. @code{current-pstate} is only\n" "included in @code{--enable-guile-debug} builds.") _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Reference leak in `iprin1 ()' 2005-11-14 9:58 ` Ludovic Courtès @ 2005-11-16 21:18 ` Neil Jerram 2005-11-17 9:54 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Neil Jerram @ 2005-11-16 21:18 UTC (permalink / raw) Cc: Han-Wen Nienhuys ludovic.courtes@laas.fr (Ludovic Courtès) writes: > Hello, > > Neil Jerram <neil@ossau.uklinux.net> writes: > >> Nice work, but it looks to me that PUSH_REF sets the value of the >> (pstate->top)th element _before_ incrementing pstate->top. So >> shouldn't your fix do the decrement first and then set the slot to >> undefined? > > Yes, you're perfectly right. Thanks. (It's always better to have other people check and agree!) >> Also, is the () -> (void) change strictly related? > > In fact, it's strictly unrelated, but while we're at it (really `(void)' > was meant here, not `()')... Why? Does () have any symptoms that we should be concerned about? > Below is an updated patch. I modified `PUSH_REF ()' as well so that it > does PSTATE->TOP++ _after_ using the `PSTATE_STACK_SET ()' macro: this > is safer. Why is it safer? My inclination is that it's usually safer to change less code, other things being equal. > And, well, I couldn't resist the desire to "beautifully > backslashify" `ENTER_NESTED_DATA ()' as well. :-) I hope this is not > too much pollution for you. No, I'm happy to go along with that one! Regards, Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Reference leak in `iprin1 ()' 2005-11-16 21:18 ` Neil Jerram @ 2005-11-17 9:54 ` Ludovic Courtès 2005-11-17 18:52 ` Neil Jerram 0 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-11-17 9:54 UTC (permalink / raw) Cc: Han-Wen Nienhuys, guile-devel Hi Neil, Neil Jerram <neil@ossau.uklinux.net> writes: > Why? Does () have any symptoms that we should be concerned about? Well, nothing to be really "concerned" about, mostly consistency. In a declaration, `()' has a different meaning than `(void)', but not in the definition. According to section 6.7.5.3 or ISO/IEC 9899:1999: 10 The special case of an unnamed parameter of type void as the only item in the list specifies that the function has no parameters. [...] 14 An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.124) Since, the declarations in `print.h' use `(void)', there's nothing really serious here. >> Below is an updated patch. I modified `PUSH_REF ()' as well so that it >> does PSTATE->TOP++ _after_ using the `PSTATE_STACK_SET ()' macro: this >> is safer. > > Why is it safer? Because of the side effects these macros may introduce, as described in http://gcc.gnu.org/onlinedocs/gcc-4.0.2/cpp/Duplication-of-Side-Effects.html#Duplication-of-Side-Effects . As far as `PUSH_REF ()' is concerned, without knowing all the definitions of all the macros it uses, one can't be sure that PSTATE->TOP won't be incremented more than once. > My inclination is that it's usually safer to change > less code, other things being equal. Agreed. But that must not prevent us from discussing existing code and modifying it when we see fit, i.e. when there is improvement to gain. ;-) Thanks, Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Reference leak in `iprin1 ()' 2005-11-17 9:54 ` Ludovic Courtès @ 2005-11-17 18:52 ` Neil Jerram 0 siblings, 0 replies; 35+ messages in thread From: Neil Jerram @ 2005-11-17 18:52 UTC (permalink / raw) Cc: Han-Wen Nienhuys ludovic.courtes@laas.fr (Ludovic Courtès) writes: > Well, nothing to be really "concerned" about, mostly consistency. In a > declaration, `()' has a different meaning than `(void)', but not in the > definition. According to section 6.7.5.3 or ISO/IEC 9899:1999: > > 10 The special case of an unnamed parameter of type void as the only > item in the list specifies that the function has no parameters. > > [...] > > 14 An identifier list declares only the identifiers of the parameters > of the function. An empty list in a function declarator that is > part of a definition of that function specifies that the function > has no parameters. The empty list in a function declarator that is > not part of a definition of that function specifies that no > information about the number or types of the parameters is > supplied.124) > > Since, the declarations in `print.h' use `(void)', there's nothing > really serious here. Thanks. But in the absence of any actual problem, I think I'll leave this as is for now. >>> Below is an updated patch. I modified `PUSH_REF ()' as well so that it >>> does PSTATE->TOP++ _after_ using the `PSTATE_STACK_SET ()' macro: this >>> is safer. >> >> Why is it safer? > > Because of the side effects these macros may introduce, as described in > http://gcc.gnu.org/onlinedocs/gcc-4.0.2/cpp/Duplication-of-Side-Effects.html#Duplication-of-Side-Effects . Yes of course, silly me. I misread what you said you had done as changing PSTATE->TOP++ to ++(PSTATE->TOP). This is definitely a good change. This patch is now in CVS. Thanks for all your effort on this. Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, #2 2005-11-09 16:28 ` Ludovic Courtès 2005-11-09 18:36 ` Han-Wen Nienhuys 2005-11-09 21:11 ` Kevin Ryde @ 2005-11-23 10:19 ` Ludovic Courtès 2005-11-24 0:59 ` Han-Wen Nienhuys ` (2 more replies) 2 siblings, 3 replies; 35+ messages in thread From: Ludovic Courtès @ 2005-11-23 10:19 UTC (permalink / raw) Cc: guile-devel Hi, Below is an improved version of the patch I originally sent. The goal of the original patch (and associated test case) was to ensure that an object associated to a weak key (resp. a weak value) is GC'd _after_ that key (resp. value). However, as Han-Wen pointed out earlier in this thread, with the original patch, cyclical structures within a weak-key (or weak-value) alist vectors would never become unmarked. By "cyclical structure", I mean something like: key A is associated to B key B is associated to C Here (assuming a weakly-keyed alist vector), object B is used both as a key and a value, resulting in a "cyclical structure". The patch below fixes this. It also fixes `weaks.test' and adds a test case for cyclical structures (called "cascading weak keys die"). Looking at `weaks.test' gives an idea of how hard it is to work around reference "leaks". Certainly, not all of them are actual leaks, but some of them may be so. The funniest example is the `(+ 1 2 3)' call before calls to `(gc)' to ensure that the C stack no longer holds references that were used by the *previous* call of `ceval ()'. Another neat trick is used in "cascading weak keys die": if K2 and K3 are initialized within the init forms of `let', then things won't work (i.e. references to K2 and K3 are held somewhere). I suspect this is a leak in `let' but I was unable to find out what happens exactly. So there is room for further debugging. ;-) I'd be glad to have feedback about all this. Thanks, Ludovic. libguile/ChangeLog 2005-11-23 Ludovic Courtès <ludovic.courtes@laas.fr> * gc-mark.c (scm_mark_all): Removed C++/C99-style comment. * properties.c (scm_init_properties): Make SCM_PROPERTIES_WHASH a permanent object. * weaks.c (weak_vectors): Initialize it to `SCM_EOL'. (scm_i_mark_weak_vector_non_weaks): Cosmetic changes. (scm_i_remove_weaks): When an element of a pair is weak, add its non-weak element to a "mark queue". Before returning, mark all the elements in this queue so that they will only become unmarked during the next mark phase. test-suite/ChangeLog 2005-11-23 Ludovic Courtès <ludovic.courtes@laas.fr> * standalone/Makefile.am (TESTS): Added `test-weaks'. (check_PROGRAMS): Likewise. * standalone/test-weaks.c: New file. * tests/weaks.test: Overhauled the test. Added the "cascading weak key dies"test case. \f --- orig/libguile/gc-mark.c +++ mod/libguile/gc-mark.c @@ -74,7 +74,7 @@ scm_i_init_weak_vectors_for_gc (); scm_i_init_guardians_for_gc (); - + scm_i_clear_mark_space (); /* Mark every thread's stack and registers */ @@ -138,12 +138,9 @@ break; } - //fprintf (stderr, "%d loops\n", loops); - - /* Remove all unmarked entries from the weak vectors. - */ + /* Remove all unmarked entries from the weak vectors. */ scm_i_remove_weaks_from_weak_vectors (); - + /* Bring hashtables upto date. */ scm_i_scan_weak_hashtables (); --- orig/libguile/weaks.c +++ mod/libguile/weaks.c @@ -205,7 +205,11 @@ #define UNMARKED_CELL_P(x) (SCM_NIMP(x) && !SCM_GC_MARK_P (x)) -static SCM weak_vectors; +/* A list of live weak vectors, updated each time a weak vector is marked (in + `scm_i_mark_weak_vector ()') and cleared at the beginning of each mark + phase (in `scm_mark_all ()' which calls + `scm_i_init_weak_vectors_for_gc ()'). */ +static SCM weak_vectors = SCM_EOL; void scm_i_init_weak_vectors_for_gc () @@ -264,13 +268,12 @@ { SCM key = SCM_CAR (elt); SCM value = SCM_CDR (elt); - + if (!((weak_keys && UNMARKED_CELL_P (key)) || (weak_values && UNMARKED_CELL_P (value)))) { - /* The item should be kept. We need to mark it - recursively. - */ + /* The whole pair should be kept, as well as its + CAR and CDR, recursively. */ scm_gc_mark (elt); again = 1; } @@ -323,6 +326,8 @@ { SCM *ptr = SCM_I_WVECT_GC_WVELTS (w); size_t n = SCM_I_WVECT_LENGTH (w); + int weak_keys = SCM_IS_WHVEC (w) || SCM_IS_WHVEC_B (w); + int weak_values = SCM_IS_WHVEC_V (w) || SCM_IS_WHVEC_B (w); size_t i; if (!SCM_IS_WHVEC_ANY (w)) @@ -334,8 +339,15 @@ else { size_t delta = 0; + SCM *mark_queue; + size_t mark_queue_len = 0; - for (i = 0; i < n; ++i) + if (weak_keys && weak_values) + mark_queue = alloca (2 * n * sizeof (*mark_queue)); + else + mark_queue = alloca (n * sizeof (*mark_queue)); + + for (i = 0; i < n; i++) { SCM alist, *fixup; @@ -343,8 +355,20 @@ alist = *fixup; while (scm_is_pair (alist) && !SCM_GC_MARK_P (alist)) { - if (UNMARKED_CELL_P (SCM_CAR (alist))) + SCM elt = SCM_CAR (alist); + SCM key = SCM_CAR (elt), value = SCM_CDR (elt); + + if ((weak_keys && UNMARKED_CELL_P (key)) + || (weak_values && UNMARKED_CELL_P (value))) { + /* Remove this pair from ALIST. However, mark its elements + so that they will only become unreachable during the + next mark phase. */ + if (!weak_values) + mark_queue[mark_queue_len++] = value; + if (!weak_keys) + mark_queue[mark_queue_len++] = key; + *fixup = SCM_CDR (alist); delta++; } @@ -354,11 +378,21 @@ fixup = SCM_CDRLOC (alist); } alist = *fixup; + + elt = key = value = SCM_BOOL_F; } } + + for (i = 0; i < mark_queue_len; i++) + { + scm_gc_mark (mark_queue[i]); + mark_queue[i] = SCM_UNSPECIFIED; + } + #if 0 if (delta) - fprintf (stderr, "vector %p, delta %d\n", w, delta); + fprintf (stderr, "vector %p, delta %d, post-marked %d\n", + w, delta, mark_queue_len); #endif SCM_I_SET_WVECT_DELTA (w, delta); } --- orig/test-suite/tests/weaks.test +++ mod/test-suite/tests/weaks.test @@ -36,7 +36,8 @@ (use-modules (test-suite lib) (ice-9 weak-vector)) -;;; Creation functions + +;;; Creation functions (with-test-prefix @@ -105,7 +106,7 @@ ;;; Normal weak vectors (let ((x (make-weak-vector 10 #f)) (bar "bar")) - (with-test-prefix + (with-test-prefix "weak-vector" (pass-if "lives" (begin @@ -123,10 +124,10 @@ (throw 'unresolved)))))) (let ((x (make-weak-key-alist-vector 17)) - (y (make-weak-value-alist-vector 17)) - (z (make-doubly-weak-alist-vector 17)) - (test-key "foo") - (test-value "bar")) + (y (make-weak-value-alist-vector 17)) + (z (make-doubly-weak-alist-vector 17)) + (test-key "foo") + (test-value "bar")) (with-test-prefix "weak-hash" (pass-if "lives" @@ -140,50 +141,71 @@ (hashq-ref y test-key) (hashq-ref z test-key) #t))) + (pass-if "weak-key dies" (begin - (hashq-set! x "this" "is") - (hashq-set! x "a" "test") - (hashq-set! x "of" "the") - (hashq-set! x "emergency" "weak") - (hashq-set! x "key" "hash system") - (gc) - (and - (or (not (hashq-ref x "this")) - (not (hashq-ref x "a")) - (not (hashq-ref x "of")) - (not (hashq-ref x "emergency")) - (not (hashq-ref x "key"))) - (hashq-ref x test-key) - #t))) + ;; We use `string-copy' because the `SCM_IM_BEGIN' structure + ;; holds a reference to the strings that were read so these + ;; strings would not be GC'd until the `begin' expression is. + (hashq-set! x (string-copy "this") "is") + (hashq-set! x (string-copy "a") "test") + (hashq-set! x (string-copy "of") "the") + (hashq-set! x (string-copy "emergency") "weak") + (hashq-set! x (string-copy "key") "hash system") + + ;; This has the effect of cleaning up the C stack because the + ;; stack space between `ceval ()' and `scm_gc ()' may contain + ;; references to the arguments of the last `hashq-set!' call + ;; above. + (+ 1 2 3) + (gc) (gc) (gc) + + ;; X must now contain nothing more than the + ;; `(test-key . test-value)' pair. + (equal? (hash-map->list cons x) + (list (cons test-key test-value))))) + + (pass-if "cascading weak keys die" + (let ((h (make-weak-key-alist-vector 17))) + (let ((k2 #f) + (k3 #f)) + ;; Here, K2 and K3 are used both as keys and values. Garbage + ;; collection of these two objects is expected to occur in a + ;; ``cascading'' fashion: K2 becomes unmarked, so K3 becomes + ;; unmarked. + (set! k2 (string-copy "a shared key/value")) + (set! k3 (string-copy "another shared key/value")) + (hashq-set! h (string-copy "a key") k2) + (hashq-set! h k2 k3) + (hashq-set! h k3 (string-copy "some value")) + (set! k2 #f) + (set! k3 #f) + (+ 1 2 3)) + + (gc) (gc) (gc) + (null? (hash-map->list cons h)))) (pass-if "weak-value dies" (begin - (hashq-set! y "this" "is") - (hashq-set! y "a" "test") - (hashq-set! y "of" "the") - (hashq-set! y "emergency" "weak") - (hashq-set! y "value" "hash system") - (gc) - (and (or (not (hashq-ref y "this")) - (not (hashq-ref y "a")) - (not (hashq-ref y "of")) - (not (hashq-ref y "emergency")) - (not (hashq-ref y "value"))) - (hashq-ref y test-key) - #t))) + (hashq-set! y "this" (string-copy "is")) + (hashq-set! y "a" (string-copy "test")) + (hashq-set! y "of" (string-copy "the")) + (hashq-set! y "emergency" (string-copy "weak")) + (hashq-set! y "value" (string-copy "hash system")) + (+ 1 2 3) + (gc) (gc) (gc) + (equal? (hash-map->list cons y) + (list (cons test-key test-value))))) + (pass-if "doubly-weak dies" (begin - (hashq-set! z "this" "is") - (hashq-set! z "a" "test") - (hashq-set! z "of" "the") - (hashq-set! z "emergency" "weak") - (hashq-set! z "all" "hash system") - (gc) - (and (or (not (hashq-ref z "this")) - (not (hashq-ref z "a")) - (not (hashq-ref z "of")) - (not (hashq-ref z "emergency")) - (not (hashq-ref z "all"))) - (hashq-ref z test-key) - #t))))) + (hashq-set! z (string-copy "this") (string-copy "is")) + (hashq-set! z (string-copy "a") (string-copy "test")) + (hashq-set! z (string-copy "of") (string-copy "the")) + (hashq-set! z (string-copy "emergency") (string-copy "weak")) + (hashq-set! z (string-copy "all") (string-copy "hash system")) + (+ 1 2 3) + (gc) (gc) (gc) + (equal? (hash-map->list cons z) + (list (cons test-key test-value))))))) + --- orig/test-suite/standalone/Makefile.am +++ mod/test-suite/standalone/Makefile.am @@ -74,6 +74,13 @@ check_PROGRAMS += test-conversion TESTS += test-conversion +# test-weaks +test_weaks_SOURCES = test-weaks.c +test_weaks_CFLAGS = ${test_cflags} +test_weaks_LDADD = ${top_builddir}/libguile/libguile.la +check_PROGRAMS += test-weaks +TESTS += test-weaks + all-local: cd ${srcdir} && chmod u+x ${check_SCRIPTS} \f New file `test-suite/standalone/test-weaks.c': /* Copyright (C) 2005 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This test case targets garbage collection of weak hash tables. It does so by using object properties (which are currently implemented using weak hash tables) and verifying that properties attached to an object are always GC'd _after_ the object itself has been freed. In order to do so, `test_weak_gc ()' creates a number of SMOBs. The C structure underlying those SMOBs explicitly maintains a reference counter for each instance. This reference counter is: 1. incremented each time a SMOB is attached to another SMOB (by means of object properties); 2. decremented each time a SMOB that was attached to another SMOB is freed. For instance if A is attached to B, when B is GC'd, A's reference counter is decremented. The invariant that we check is: any SMOB that is GC'd must have its reference count equal to zero. */ #include "libguile.h" #include <stdio.h> #include <assert.h> /* Number of time a `my-object' SMOB was freed. */ static unsigned free_count = 0; static scm_t_bits my_object_type = 0; static SCM some_property = SCM_BOOL_F; static SCM my_object_new_smob_proc = SCM_BOOL_F, attach_object_proc = SCM_BOOL_F; typedef struct my_object { struct my_object *attached_to; unsigned ref_count; int freed; } my_object_t; static void my_object_init (my_object_t *obj) { obj->attached_to = NULL; obj->ref_count = 0; obj->freed = 0; } static size_t my_object_free (SCM obj) { my_object_t *my_object = (my_object_t *)SCM_SMOB_DATA (obj); if (my_object->attached_to) { /* Decrease the reference count of the object MY_OBJECT is attached to. */ assert (my_object->attached_to->ref_count > 0); my_object->attached_to->ref_count--; } /* MY_OBJECT must not have been already freed and there must be no pending references to it. */ assert (!my_object->freed); assert (my_object->ref_count == 0); my_object->freed = 1; free_count++; return 0; } \f /* Return a new `my-object' SMOB. */ static SCM my_object_new_smob (void) { my_object_t *obj; obj = scm_malloc (sizeof (*obj)); my_object_init (obj); SCM_RETURN_NEWSMOB (my_object_type, obj); } /* Attach TO_BE_ATTACHED to OBJ. */ static SCM attach_object (SCM obj, SCM to_be_attached) { my_object_t *c_obj, *c_to_be_attached; assert (SCM_SMOB_PREDICATE (my_object_type, obj)); assert (SCM_SMOB_PREDICATE (my_object_type, to_be_attached)); /* TO_BE_ATTACHED is attached as a property of OBJ. As such, OBJ will get GC'd _before_ TO_BE_ATTACHED. */ scm_primitive_property_set_x (some_property, obj, to_be_attached); c_obj = (my_object_t *)SCM_SMOB_DATA (obj); c_to_be_attached = (my_object_t *)SCM_SMOB_DATA (to_be_attached); /* Because TO_BE_ATTACHED is to be freed _after_ OBJ, we can increase its reference count and it should be zero by the time it is freed. */ c_to_be_attached->ref_count++; c_obj->attached_to = c_to_be_attached; return obj; } \f /* Instantiate a number of `my-object' SMOBs, attached some of them together, invoke the GC, and wait until all of these SMOBs have been freed. */ static void test_weak_gc (void) { #define PAIRS 700 unsigned pair_count, total; for (pair_count = 0, total = 0; pair_count < PAIRS; pair_count++) { size_t noise, i; SCM obj, attached; obj = my_object_new_smob (); attached = my_object_new_smob (); #if 0 printf ("%p attached to %p\n", SCM_SMOB_DATA (obj), SCM_SMOB_DATA (attached)); #endif attach_object (obj, attached); total += 2; obj = attached = SCM_BOOL_F; for (i = 0, noise = random () % 10; i < noise; i++) { my_object_new_smob (); total++; } } while (free_count < total) { unsigned i; scm_gc (); for (i = 0; i < 1000; i++) scm_cons (SCM_I_MAKINUM (0), SCM_I_MAKINUM (0)); } } \f int main (int argc, char *argv[]) { scm_init_guile (); my_object_type = scm_make_smob_type ("test-object", 0); scm_set_smob_free (my_object_type, my_object_free); some_property = scm_primitive_make_property (SCM_BOOL_F); my_object_new_smob_proc = scm_c_make_gsubr ("make-my-object", 0, 0, 0, my_object_new_smob); attach_object_proc = scm_c_make_gsubr ("attach-object!", 0, 0, 0, attach_object); test_weak_gc (); return 0; } _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, #2 2005-11-23 10:19 ` [PATCH] Marking weak alist vectors, #2 Ludovic Courtès @ 2005-11-24 0:59 ` Han-Wen Nienhuys 2005-11-24 9:01 ` Ludovic Courtès 2005-11-26 0:49 ` Kevin Ryde 2006-01-09 14:51 ` [PATCH] Marking weak alist vectors, epilogue Ludovic Courtès 2 siblings, 1 reply; 35+ messages in thread From: Han-Wen Nienhuys @ 2005-11-24 0:59 UTC (permalink / raw) Cc: guile-devel Ludovic Courtès wrote: > Hi, > > Below is an improved version of the patch I originally sent. The goal > of the original patch (and associated test case) was to ensure that an > object associated to a weak key (resp. a weak value) is GC'd _after_ > that key (resp. value). > > However, as Han-Wen pointed out earlier in this thread, with the > original patch, cyclical structures within a weak-key (or weak-value) > alist vectors would never become unmarked. By "cyclical structure", I > mean something like: > > key A is associated to B > key B is associated to C > > Here (assuming a weakly-keyed alist vector), object B is used both as a > key and a value, resulting in a "cyclical structure". No, this is not cyclic. The problem is a situation where key A is associated to key A, eg. (define x (cons 1 2)) (set-cdr! x s) (weak-key-hash-table-set! table s x) x points back to s, and s is a key in the table. (I haven't looked at how your patch deals with this, just clarifying your text) -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, #2 2005-11-24 0:59 ` Han-Wen Nienhuys @ 2005-11-24 9:01 ` Ludovic Courtès 0 siblings, 0 replies; 35+ messages in thread From: Ludovic Courtès @ 2005-11-24 9:01 UTC (permalink / raw) Cc: guile-devel Hi, Han-Wen Nienhuys <hanwen@xs4all.nl> writes: > No, this is not cyclic. The problem is a situation where key A is > associated to key A, eg. > > (define x (cons 1 2)) > (set-cdr! x s) > (weak-key-hash-table-set! table s x) > > x points back to s, and s is a key in the table. Ah, alright. Well yes, the new patch does handle it, the previous one didn't. The issue at hand was similar to the one which showed up in my "cascading weak keys" example. $ ../pre-inst-guile --no-debug guile> (use-modules (ice-9 weak-vector)) guile> (define t (make-weak-key-alist-vector 12)) guile> (define s (string-copy "chbouib")) guile> (hashq-set! t s (cons s 1)) ("chbouib" . 1) guile> (set! s #f) guile> (gc) guile> t #wh(() () () () () () () () () () () ()) Thanks, Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, #2 2005-11-23 10:19 ` [PATCH] Marking weak alist vectors, #2 Ludovic Courtès 2005-11-24 0:59 ` Han-Wen Nienhuys @ 2005-11-26 0:49 ` Kevin Ryde 2006-01-09 14:51 ` [PATCH] Marking weak alist vectors, epilogue Ludovic Courtès 2 siblings, 0 replies; 35+ messages in thread From: Kevin Ryde @ 2005-11-26 0:49 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > > * gc-mark.c (scm_mark_all): Removed C++/C99-style comment. Thanks, I made that change. But it's much easier if you post nitpicks separate from new stuff. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, epilogue 2005-11-23 10:19 ` [PATCH] Marking weak alist vectors, #2 Ludovic Courtès 2005-11-24 0:59 ` Han-Wen Nienhuys 2005-11-26 0:49 ` Kevin Ryde @ 2006-01-09 14:51 ` Ludovic Courtès 2006-01-09 19:29 ` Neil Jerram 2 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2006-01-09 14:51 UTC (permalink / raw) Cc: guile-devel Hi all, ludovic.courtes@laas.fr (Ludovic Courtès) writes: > Below is an improved version of the patch I originally sent. The goal > of the original patch (and associated test case) was to ensure that an > object associated to a weak key (resp. a weak value) is GC'd _after_ > that key (resp. value). > > However, as Han-Wen pointed out earlier in this thread, with the > original patch, cyclical structures within a weak-key (or weak-value) > alist vectors would never become unmarked. I'm afraid no one cares but this second patch is somewhat broken, too, in that its delayed marking phase (iterating through MARK_QUEUE) is "not deferred enough". Iterating though MARK_QUEUE should be done after _all_ weak vectors have been traversed in `scm_i_remove_weaks ()'. Implementing it would require to know the total number of weak vectors so that, at the beginning of `scm_i_remove_weaks ()' we can allocate (on the stack) a vector of such "mark queues" and only iterate through it before exiting. I'm not going to do it I guess (i) because it is getting complicated and (ii) well, because apparently no one feels concerned by the issue I was trying to solve, so maybe it's just unimportant after all. ;-) Conclusions: 1. If we're not going to solve this problem, at least it should be very well documented. 2. The test case currently in CVS is broken and could be either removed or replaced by something along the lines of what I posted earlier (I mean `weaks.test'). 3. I had posted the tiny fix below which still seems valuable. Thanks, Ludovic. --- orig/libguile/properties.c +++ mod/libguile/properties.c @@ -125,6 +125,7 @@ scm_init_properties () { scm_properties_whash = scm_make_weak_key_hash_table (SCM_UNDEFINED); + scm_properties_whash = scm_permanent_object (scm_properties_whash); #include "libguile/properties.x" } _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, epilogue 2006-01-09 14:51 ` [PATCH] Marking weak alist vectors, epilogue Ludovic Courtès @ 2006-01-09 19:29 ` Neil Jerram 2006-01-10 8:21 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Neil Jerram @ 2006-01-09 19:29 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > --- orig/libguile/properties.c > +++ mod/libguile/properties.c > @@ -125,6 +125,7 @@ > scm_init_properties () > { > scm_properties_whash = scm_make_weak_key_hash_table (SCM_UNDEFINED); > + scm_properties_whash = scm_permanent_object (scm_properties_whash); > #include "libguile/properties.x" > } What is the symptom of the fact that we are currently missing this line? (And sorry that I don't know enough to comment on the wider GC issues.) Regards, Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, epilogue 2006-01-09 19:29 ` Neil Jerram @ 2006-01-10 8:21 ` Ludovic Courtès 2006-01-10 9:33 ` Neil Jerram 0 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2006-01-10 8:21 UTC (permalink / raw) Cc: guile-devel Neil Jerram <neil@ossau.uklinux.net> writes: > ludovic.courtes@laas.fr (Ludovic Courtès) writes: > >> --- orig/libguile/properties.c >> +++ mod/libguile/properties.c >> @@ -125,6 +125,7 @@ >> scm_init_properties () >> { >> scm_properties_whash = scm_make_weak_key_hash_table (SCM_UNDEFINED); >> + scm_properties_whash = scm_permanent_object (scm_properties_whash); >> #include "libguile/properties.x" >> } > > What is the symptom of the fact that we are currently missing this > line? You mean: does it actually yield a fault at run-time? Well, it doesn't /seem/ to (i.e., I haven't identified any reproducible "bug" caused by this), but I think it /could/. ;-) All other such global variables are, understandably, explicitly made non-collectable. For instance, in `srcprop.c', SCM_SOURCE_WHASH is non-collectable because it is bound to a top-level binding. In `symbols.c', the SYMBOLS weak hash table is made permanent via a call to `scm_permanent_object ()'. Thanks, Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, epilogue 2006-01-10 8:21 ` Ludovic Courtès @ 2006-01-10 9:33 ` Neil Jerram 2006-01-10 15:43 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Neil Jerram @ 2006-01-10 9:33 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > Neil Jerram <neil@ossau.uklinux.net> writes: > >> ludovic.courtes@laas.fr (Ludovic Courtès) writes: >> >>> + scm_properties_whash = scm_permanent_object (scm_properties_whash); >> >> What is the symptom of the fact that we are currently missing this >> line? > > You mean: does it actually yield a fault at run-time? Well, it doesn't > /seem/ to (i.e., I haven't identified any reproducible "bug" caused by > this), but I think it /could/. ;-) > > All other such global variables are, understandably, explicitly made > non-collectable. For instance, in `srcprop.c', SCM_SOURCE_WHASH is > non-collectable because it is bound to a top-level binding. In > `symbols.c', the SYMBOLS weak hash table is made permanent via a call to > `scm_permanent_object ()'. I just looked into this. scm_properties_whash is actually OK, because it is defined like this in root.h: #define scm_properties_whash scm_sys_protects[10] and the elements of scm_sys_protects are handled specially in gc-mark.c. Regards, Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Marking weak alist vectors, epilogue 2006-01-10 9:33 ` Neil Jerram @ 2006-01-10 15:43 ` Ludovic Courtès 0 siblings, 0 replies; 35+ messages in thread From: Ludovic Courtès @ 2006-01-10 15:43 UTC (permalink / raw) Cc: guile-devel Neil Jerram <neil@ossau.uklinux.net> writes: > I just looked into this. scm_properties_whash is actually OK, because > it is defined like this in root.h: > > #define scm_properties_whash scm_sys_protects[10] > > and the elements of scm_sys_protects are handled specially in > gc-mark.c. Ok, I had completely overlooked this other way of making objects non-collectable. Thanks! Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH] Fixing `gc-live-object-stats' 2005-11-08 17:22 [PATCH] Marking weak alist vectors Ludovic Courtès 2005-11-08 23:51 ` Marius Vollmer 2005-11-09 10:28 ` Han-Wen Nienhuys @ 2005-11-17 13:21 ` Ludovic Courtès 2005-11-17 14:12 ` Han-Wen Nienhuys 2005-11-30 8:54 ` Ludovic Courtès 2 siblings, 2 replies; 35+ messages in thread From: Ludovic Courtès @ 2005-11-17 13:21 UTC (permalink / raw) Hi, ludovic.courtes@laas.fr (Ludovic Courtès) writes: > $ guile > guile> (gc-live-object-stats) > Segmentation fault (core dumped) The patch below fixes this problem. Basically, what happens when doing this is that `scm_i_card_statistics ()' gets called on yet uninitialized cards. This is normal because cards are initialized lazily at sweep time by `scm_i_sweep_some_cards ()' which calls `scm_i_init_card_freelist ()' if needed. BTW, looking at the code of `scm_i_sweep_some_cards ()', it looks like cards can be initialized more than once in the event where THRESHOLD is reached before NEXT_FREE reached the upper boundary of SEG. In such a case, SEG->FIRST_TIME will remain equal to 1, and thus, the next time this function is called on SEG, `scm_i_init_card_freelist ()' will be called again for each of SEG's cards. Did I miss something? Thanks, Ludovic. 2005-11-17 Ludovic Courtès <ludovic.courtes@laas.fr> * gc-card.c (scm_i_card_statistics): Return if BITVEC is NULL. This was typically hit when running `gc-live-object-stats' right after starting Guile. --- orig/libguile/gc-card.c +++ mod/libguile/gc-card.c @@ -306,6 +306,10 @@ int span = seg->span; int offset = SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span); + if (!bitvec) + /* Card P hasn't been initialized yet by `scm_i_init_card_freelist ()'. */ + return; + for (p += offset; p < end; p += span, offset += span) { scm_t_bits tag = -1; _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Fixing `gc-live-object-stats' 2005-11-17 13:21 ` [PATCH] Fixing `gc-live-object-stats' Ludovic Courtès @ 2005-11-17 14:12 ` Han-Wen Nienhuys 2005-11-30 8:54 ` Ludovic Courtès 1 sibling, 0 replies; 35+ messages in thread From: Han-Wen Nienhuys @ 2005-11-17 14:12 UTC (permalink / raw) Ludovic Courtès wrote: > BTW, looking at the code of `scm_i_sweep_some_cards ()', it looks like > cards can be initialized more than once in the event where THRESHOLD is > reached before NEXT_FREE reached the upper boundary of SEG. In such a > case, SEG->FIRST_TIME will remain equal to 1, and thus, the next time > this function is called on SEG, `scm_i_init_card_freelist ()' will be > called again for each of SEG's cards. > > Did I miss something? Yes. Sweeping always starts with NEXT_FREE, which is incremented for each call, so each card from the segment is only passed over once with FIRST_TIME. FIRST_TIME refers to the fact that no GC has taken place for the segment at hand. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Fixing `gc-live-object-stats' 2005-11-17 13:21 ` [PATCH] Fixing `gc-live-object-stats' Ludovic Courtès 2005-11-17 14:12 ` Han-Wen Nienhuys @ 2005-11-30 8:54 ` Ludovic Courtès 2005-11-30 23:45 ` Han-Wen Nienhuys 1 sibling, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-11-30 8:54 UTC (permalink / raw) Hi, ludovic.courtes@laas.fr (Ludovic Courtès) writes: > 2005-11-17 Ludovic Courtès <ludovic.courtes@laas.fr> > > * gc-card.c (scm_i_card_statistics): Return if BITVEC is NULL. > This was typically hit when running `gc-live-object-stats' right > after starting Guile. Can this be applied? Thanks, Ludovic. _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Fixing `gc-live-object-stats' 2005-11-30 8:54 ` Ludovic Courtès @ 2005-11-30 23:45 ` Han-Wen Nienhuys 2005-12-03 19:31 ` Neil Jerram 0 siblings, 1 reply; 35+ messages in thread From: Han-Wen Nienhuys @ 2005-11-30 23:45 UTC (permalink / raw) Ludovic Courtès wrote: > Hi, > > ludovic.courtes@laas.fr (Ludovic Courtès) writes: > > >>2005-11-17 Ludovic Courtès <ludovic.courtes@laas.fr> >> >> * gc-card.c (scm_i_card_statistics): Return if BITVEC is NULL. >> This was typically hit when running `gc-live-object-stats' right >> after starting Guile. > > > Can this be applied? Yes, I think so. -- Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Fixing `gc-live-object-stats' 2005-11-30 23:45 ` Han-Wen Nienhuys @ 2005-12-03 19:31 ` Neil Jerram 2005-12-05 8:50 ` Ludovic Courtès 0 siblings, 1 reply; 35+ messages in thread From: Neil Jerram @ 2005-12-03 19:31 UTC (permalink / raw) Cc: guile-devel Han-Wen Nienhuys <hanwen@xs4all.nl> writes: > Ludovic Courtès wrote: >> Hi, >> ludovic.courtes@laas.fr (Ludovic Courtès) writes: >> >>>2005-11-17 Ludovic Courtès <ludovic.courtes@laas.fr> >>> >>> * gc-card.c (scm_i_card_statistics): Return if BITVEC is NULL. >>> This was typically hit when running `gc-live-object-stats' right >>> after starting Guile. >> Can this be applied? > > Yes, I think so. Ludovic, if you can post the patch again, I'll commit it. Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Fixing `gc-live-object-stats' 2005-12-03 19:31 ` Neil Jerram @ 2005-12-05 8:50 ` Ludovic Courtès 2005-12-06 19:14 ` Neil Jerram 0 siblings, 1 reply; 35+ messages in thread From: Ludovic Courtès @ 2005-12-05 8:50 UTC (permalink / raw) Cc: guile-devel Hi, Neil Jerram <neil@ossau.uklinux.net> writes: > Ludovic, if you can post the patch again, I'll commit it. Thanks Neil, I appreciate your involvement. Ludovic. 2005-11-17 Ludovic Courtès <ludovic.courtes@laas.fr> * gc-card.c (scm_i_card_statistics): Return if BITVEC is NULL. This was typically hit when running `gc-live-object-stats' right after starting Guile. --- orig/libguile/gc-card.c +++ mod/libguile/gc-card.c @@ -306,6 +306,10 @@ int span = seg->span; int offset = SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span); + if (!bitvec) + /* Card P hasn't been initialized yet by `scm_i_init_card_freelist ()'. */ + return; + for (p += offset; p < end; p += span, offset += span) { scm_t_bits tag = -1; _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH] Fixing `gc-live-object-stats' 2005-12-05 8:50 ` Ludovic Courtès @ 2005-12-06 19:14 ` Neil Jerram 0 siblings, 0 replies; 35+ messages in thread From: Neil Jerram @ 2005-12-06 19:14 UTC (permalink / raw) ludovic.courtes@laas.fr (Ludovic Courtès) writes: > 2005-11-17 Ludovic Courtès <ludovic.courtes@laas.fr> > > * gc-card.c (scm_i_card_statistics): Return if BITVEC is NULL. > This was typically hit when running `gc-live-object-stats' right > after starting Guile. This is in CVS now. Neil _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel ^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2006-01-10 15:43 UTC | newest] Thread overview: 35+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-11-08 17:22 [PATCH] Marking weak alist vectors Ludovic Courtès 2005-11-08 23:51 ` Marius Vollmer 2005-11-09 9:03 ` Ludovic Courtès 2005-12-06 23:55 ` Marius Vollmer 2005-12-07 10:33 ` Ludovic Courtès 2005-12-13 23:45 ` Marius Vollmer 2005-12-14 9:30 ` Ludovic Courtès 2005-11-09 10:28 ` Han-Wen Nienhuys 2005-11-09 16:28 ` Ludovic Courtès 2005-11-09 18:36 ` Han-Wen Nienhuys 2005-11-09 21:11 ` Kevin Ryde 2005-11-09 22:45 ` Marius Vollmer 2005-11-10 12:11 ` Han-Wen Nienhuys 2005-11-10 9:47 ` [PATCH] Reference leak in `iprin1 ()' Ludovic Courtès 2005-11-12 9:23 ` Neil Jerram 2005-11-14 9:58 ` Ludovic Courtès 2005-11-16 21:18 ` Neil Jerram 2005-11-17 9:54 ` Ludovic Courtès 2005-11-17 18:52 ` Neil Jerram 2005-11-23 10:19 ` [PATCH] Marking weak alist vectors, #2 Ludovic Courtès 2005-11-24 0:59 ` Han-Wen Nienhuys 2005-11-24 9:01 ` Ludovic Courtès 2005-11-26 0:49 ` Kevin Ryde 2006-01-09 14:51 ` [PATCH] Marking weak alist vectors, epilogue Ludovic Courtès 2006-01-09 19:29 ` Neil Jerram 2006-01-10 8:21 ` Ludovic Courtès 2006-01-10 9:33 ` Neil Jerram 2006-01-10 15:43 ` Ludovic Courtès 2005-11-17 13:21 ` [PATCH] Fixing `gc-live-object-stats' Ludovic Courtès 2005-11-17 14:12 ` Han-Wen Nienhuys 2005-11-30 8:54 ` Ludovic Courtès 2005-11-30 23:45 ` Han-Wen Nienhuys 2005-12-03 19:31 ` Neil Jerram 2005-12-05 8:50 ` Ludovic Courtès 2005-12-06 19:14 ` Neil Jerram
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).