After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 658650 - reference cycle in {ContactList,Individual}Store
reference cycle in {ContactList,Individual}Store
Status: RESOLVED OBSOLETE
Product: empathy
Classification: Core
Component: Contact List
2.33.x
Other Linux
: Normal normal
: ---
Assigned To: empathy-maint
empathy-maint
: 659780 660209 (view as bug list)
Depends on:
Blocks: 658596
 
 
Reported: 2011-09-09 12:50 UTC by Guillaume Desmottes
Modified: 2018-05-22 15:03 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
individual-store: store GtkTreeIter rather than GtkTreeRowReference in the cache (7.31 KB, patch)
2011-09-14 07:52 UTC, Guillaume Desmottes
committed Details | Review
contact-list-store: store GtkTreeIter rather than GtkTreeRowReference in the cache (7.02 KB, patch)
2011-09-14 07:52 UTC, Guillaume Desmottes
committed Details | Review
Remove unused variables (1.80 KB, patch)
2011-09-14 19:46 UTC, Alban Crequy
committed Details | Review
EmpathyIndividualView-658650.patch (2.21 KB, patch)
2011-09-19 18:02 UTC, Alban Crequy
none Details | Review

Description Guillaume Desmottes 2011-09-09 12:50:26 UTC
The fix for bug #657086 introduced a reference cycle:
- The store keeps hash tables containing GtkTreeRowReference
- The GtkTreeRowReference keeps a reference on the store

An easy way to experience this cycle:
- Join a XMPP muc
- Open and close the "Invite participant" dialog
- The EmpathyContactListStore is never freed

I'm not sure of the right way to fix this.
Xavier, Alban: any thoughts?

Depending on the way we break this cycle, we may want to remove the fix for bug #658644
Comment 1 Xavier Claessens 2011-09-09 13:18:47 UTC
Adding Kris in CC since he knows much better Gtk trees.

So the problem is we have our GtkTreeStore subclass which contains contacts. Each contact can be in multiple groups so could have multiple rows. When a contact change we need a quick way to lookup all GtkTreeIter where that contact is to update info.

We speedup that lookup by having a hashtable of contact->GtkTreeRowReference inside our store but then the store keeps the rowref and the rowref keeps the store => ref cycle => impossible to free the store.

Maybe we are doing something totally wrong?

Kris: Suggestions?
Comment 2 Kristian Rietveld 2011-09-11 09:39:45 UTC
I guess this is the expected behavior ... A GtkTreeView will release its reference on a GtkTreeModel when it is done with it.  In your case, the store will only  be finalized once you have first released all of the row references inside store.

As far as I know it is not really common to have row references to the same model inside the model. I guess you would typically keep a pointer to the internal data structure instead of a row reference.  Or if the iterators are persistent, you could keep the iterator (however, then you do not get the behavior that the iter is automatically reset when the row is removed, like with GtkTreeRowReference).
Comment 3 Xavier Claessens 2011-09-12 14:05:19 UTC
Iters are not persistent when adding/removing rows above the row we want to ref, right? GtkTreeRowReference does that by updating the path each time rows are added/removed above it.

We cannot access GtkTreeStore's internal neither.

So I guess what we have left is implementing our own GtkTreeModel, or our own GtkTreeRowReference that does not take ref on the store. Shouldn't be too difficult to keep paths up-to-date when contacts are inserted/removed in the store.
Comment 4 Kristian Rietveld 2011-09-12 14:50:21 UTC
(In reply to comment #3)
> Iters are not persistent when adding/removing rows above the row we want to
> ref, right? 

If the model sets the ITERS_PERSIST flag, the iterators should be persistent, also on adds/removes.

TreeStore uses GNode and sets user_data to an allocated GNode.  For adds/removes above the row to refer to, a new GNode is created and the links are updated.  So the GNode pointer stored in user_data for current rows should not be touched and is thus persistent.


(In reply to comment #3)
> So I guess what we have left is implementing our own GtkTreeModel, or our own
> GtkTreeRowReference that does not take ref on the store. Shouldn't be too
> difficult to keep paths up-to-date when contacts are inserted/removed in the
> store.

Note that for the GtkTreeRowReference implementation, we had to employ a custom signal marshaller (if I remember correctly) to keep the path updates consistent.  So it is not as trivial as it may seem (at least for the general case).
Comment 5 Xavier Claessens 2011-09-13 09:36:17 UTC
Ok, so GtkTreeStore actually have persistent iters, so we can just keep GtkTreeIter in our cache and be done. Much easier and even faster since we don't have to keep GtkTreeRowReference that keeps updating internal path on each model modification and convert path->iter for each access.

Thanks Kris for your answer :)
Comment 6 Guillaume Desmottes 2011-09-14 07:52:21 UTC
Created attachment 196470 [details] [review]
individual-store: store GtkTreeIter rather than GtkTreeRowReference in the cache

GtkTreeRowReference keeps a ref on the store introducing a ref cycle.
Comment 7 Guillaume Desmottes 2011-09-14 07:52:24 UTC
Created attachment 196471 [details] [review]
contact-list-store: store GtkTreeIter rather than GtkTreeRowReference in the cache

GtkTreeRowReference keeps a ref on the store introducing a ref cycle.
Comment 8 Xavier Claessens 2011-09-14 07:59:53 UTC
looks good, I reviewed only the one for individual though.

Please make sure contact updates are still working fine even after some other contacts got deleted above, to be sure.
Comment 9 Alban Crequy 2011-09-14 19:46:03 UTC
Created attachment 196544 [details] [review]
Remove unused variables

The two patches from Guillaume are good to me. Here is an additional patch to clean unused variables.
Comment 10 Guillaume Desmottes 2011-09-15 07:50:14 UTC
Attachment 196470 [details] pushed as 7561e27 - individual-store: store GtkTreeIter rather than GtkTreeRowReference in the cache
Attachment 196471 [details] pushed as e5eefe6 - contact-list-store: store GtkTreeIter rather than GtkTreeRowReference in the cache
Comment 11 Alban Crequy 2011-09-19 18:02:49 UTC
Created attachment 196979 [details] [review]
EmpathyIndividualView-658650.patch

I tested with GDB-breakpoints in empathy-chat on empathy_individual_view_init() and individual_view_dispose() and they are called successfully in the "Invite participant" dialog.

But I get the following segfault sometimes when closing the invite dialog (after trying about 5 times successively). It seems the view is already disposed but signal callbacks are still called.

I tried the attached patch but it still crash. 


(empathy-chat:3543): GLib-GObject-WARNING **: invalid unclassed pointer in cast to `EmpathyIndividualView'

Program received signal SIGSEGV, Segmentation fault.
individual_view_filter_visible_func (model=0x986b510, iter=0xbfffe000, user_data=0x86fc898)
    at empathy-individual-view.c:1788
1788	  if (priv->custom_filter != NULL)
(gdb) bt
  • #0 individual_view_filter_visible_func
    at empathy-individual-view.c line 1788
  • #1 gtk_tree_model_filter_real_visible
    at gtktreemodelfilter.c line 1255
  • #2 gtk_tree_model_filter_visible
    at gtktreemodelfilter.c line 1285
  • #3 gtk_tree_model_filter_row_changed
    at gtktreemodelfilter.c line 2036
  • #4 _gtk_marshal_VOID__BOXED_BOXED
    at gtkmarshalers.c line 1310
  • #5 g_closure_invoke
    at gclosure.c line 774
  • #6 signal_emit_unlocked_R
    at gsignal.c line 3272
  • #7 g_signal_emit_valist
    at gsignal.c line 3003
  • #8 g_signal_emit
    at gsignal.c line 3060
  • #9 gtk_tree_model_row_changed
    at gtktreemodel.c line 1803
  • #10 gtk_tree_store_set_valist
    at gtktreestore.c line 1164
  • #11 gtk_tree_store_set
    at gtktreestore.c line 1193
  • #12 individual_store_contact_update
    at empathy-individual-store.c line 778
  • #13 g_cclosure_marshal_VOID__PARAM
    at gmarshal.c line 539
  • #14 g_closure_invoke
    at gclosure.c line 774
  • #15 signal_emit_unlocked_R
    at gsignal.c line 3272
  • #16 g_signal_emit_valist
    at gsignal.c line 3003
  • #17 g_signal_emit
    at gsignal.c line 3060
  • #18 g_object_dispatch_properties_changed
    at gobject.c line 925
  • #19 g_object_notify_dispatcher
    at gobject.c line 331
  • #20 g_object_notify_queue_thaw
    at gobjectnotifyqueue.c line 132
  • #21 g_object_thaw_notify
    at gobject.c line 1113
  • #22 __lambda25_
    at /home/alban/dev/git/folks/folks/individual.vala line 1242
  • #23 ___lambda25__folks_individual_single_valued_property_setter
    at /home/alban/dev/git/folks/folks/individual.vala line 1211
  • #24 _folks_individual_update_single_valued_property
    at /home/alban/dev/git/folks/folks/individual.vala line 1147
  • #25 _folks_individual_update_presence
    at /home/alban/dev/git/folks/folks/individual.vala line 1211
  • #26 g_cclosure_marshal_VOID__PARAM
    at gmarshal.c line 539
  • #27 g_closure_invoke
    at gclosure.c line 774
  • #28 signal_emit_unlocked_R
    at gsignal.c line 3272
  • #29 g_signal_emit_valist
    at gsignal.c line 3003
  • #30 g_signal_emit
    at gsignal.c line 3060
  • #31 g_object_dispatch_properties_changed
    at gobject.c line 925
  • #32 g_object_notify_dispatcher
    at gobject.c line 331
  • #33 g_object_notify_queue_thaw
    at gobjectnotifyqueue.c line 132
  • #34 g_object_notify_by_spec_internal
    at gobject.c line 983
  • #35 g_object_notify
    at gobject.c line 1024
  • #36 tpf_persona_real_set_presence_type
    at /home/alban/dev/git/folks/backends/telepathy/lib/tpf-persona.vala line 90
  • #37 folks_presence_details_set_presence_type
    at /home/alban/dev/git/folks/folks/presence-details.vala line 91
  • #38 _tpf_persona_contact_notify_presence_type
    at /home/alban/dev/git/folks/backends/telepathy/lib/tpf-persona.vala line 500
  • #39 g_cclosure_marshal_VOID__PARAM
    at gmarshal.c line 539
  • #40 g_closure_invoke
    at gclosure.c line 774
  • #41 signal_emit_unlocked_R
    at gsignal.c line 3272
  • #42 g_signal_emit_valist
    at gsignal.c line 3003
  • #43 g_signal_emit
    at gsignal.c line 3060
  • #44 g_object_dispatch_properties_changed
    at gobject.c line 925
  • #45 g_object_notify_dispatcher
    at gobject.c line 331
  • #46 g_object_notify_queue_thaw
    at gobjectnotifyqueue.c line 132
  • #47 g_object_notify_by_spec_internal
    at gobject.c line 983
  • #48 g_object_notify
    at gobject.c line 1024
  • #49 contact_maybe_set_simple_presence
    at contact.c line 2273
  • #50 contacts_presences_changed
  • #51 _tp_cli_connection_interface_simple_presence_invoke_callback_for_presences_changed
    at _gen/tp-cli-connection-body.h line 16339
  • #52 tp_proxy_signal_invocation_run
    at proxy-signals.c line 266
  • #53 g_idle_dispatch
    at gmain.c line 4512
  • #54 g_main_dispatch
    at gmain.c line 2388
  • #55 g_main_context_dispatch
    at gmain.c line 2926
  • #56 g_main_context_iterate
    at gmain.c line 3001
  • #57 g_main_context_iteration
    at gmain.c line 3062
  • #58 g_application_run
    at gapplication.c line 1320
  • #59 main
    at empathy-chat.c line 160
$1 = (EmpathyIndividualViewPriv *) 0xaaaaaaaa
(gdb)
Comment 12 Fabio Durán Verdugo 2011-09-22 01:52:54 UTC
*** Bug 659780 has been marked as a duplicate of this bug. ***
Comment 13 Guillaume Desmottes 2011-09-27 07:28:59 UTC
*** Bug 660209 has been marked as a duplicate of this bug. ***
Comment 14 GNOME Infrastructure Team 2018-05-22 15:03:57 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/empathy/issues/429.