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 730886 - Avoid false change notifications with GSettings bindings
Avoid false change notifications with GSettings bindings
Status: RESOLVED WONTFIX
Product: glib
Classification: Platform
Component: gsettings
2.40.x
Other Linux
: Normal normal
: ---
Assigned To: Allison Karlitskaya (desrt)
gtkdev
Depends on:
Blocks:
 
 
Reported: 2014-05-28 12:45 UTC by Milan Crha
Modified: 2017-09-26 02:53 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
proposed glib patch (1.74 KB, patch)
2014-05-28 12:45 UTC, Milan Crha
none Details | Review

Description Milan Crha 2014-05-28 12:45:47 UTC
Created attachment 277383 [details] [review]
proposed glib patch

False change notifications issued by GSettings bindings can cause UI freezes in particular cases. This had been spot by evolution, but can sometimes be triggered by gnome-shell as well. I did not notice any other applications, but that can also because Evolution uses GSettings bindings heavily. The root cause of these false notifications is dconf, when it notifies of the root path change (the path is "/"), while there did not change anything.

I do not think it's possible to have each user of GSettings bindings check for a property change, especially when the binding is only a bridge between a GtkWidget descendant property and a GSettings key value. g_object_set() also doesn't help much with change notifications, but that's another issue.

The attached is a simple glib patch to remember and test values before passing them to the GObject property or to the GSettings key within the GSettings binding, simply avoiding false notifications when the value did not change.
Comment 1 Allison Karlitskaya (desrt) 2014-05-31 12:55:03 UTC
GSettings already does explicit loop-breaking for the direct case of a notify received when changing the property -- this is the problem caused by g_object_set() automatically notifying.

As for other cases, it's the usual behaviour for property setters to check for this and not emit the notify if no change occurred.  I'd argue that this patch is more or less covering up bugs in those classes that don't do this...

Is there a fundamental reason that this can't be fixed there, or is it just a case of being too much work to fix all the cases?
Comment 2 Milan Crha 2014-06-02 10:23:16 UTC
(In reply to comment #1)
> Is there a fundamental reason that this can't be fixed there, or is it just a
> case of being too much work to fix all the cases?

I'd not call that "too much work to fix", it's rather about "too hard to identify all the places where it strikes, especially when the problem is caused by a used library, when the library consumer has absolutely no influence on.

Also note that having the change checker on one central place makes more sense than having it all around the code, duplicated. Some change listeners are also dependent only to trigger some rebuilds of UI, thus they are not real setters, but they connect directly to GSettings, which does false change notifications, the same as the GObject. Writing the "value-really-changed" code for such listeners involves certain burden.
Comment 3 Matthias Clasen 2014-06-03 12:16:41 UTC
The patch causes extra overhead - you make us store a (possibly large) gvariant for each binding. Instead, the check should be done where you already have the old and the new value available in the same place - that is the setter of the property.
Comment 4 Allison Karlitskaya (desrt) 2014-06-03 12:18:51 UTC
We both seem to agree here -- so WONTFIXed, sorry :/
Comment 5 Milan Crha 2014-06-03 16:43:54 UTC
(In reply to comment #3)
> The patch causes extra overhead - you make us store a (possibly large) gvariant
> for each binding. Instead, the check should be done where you already have the
> old and the new value available in the same place - that is the setter of the
> property.

That doesn't work. I just caught a backtrace where the setter is not involved at all. My setter properly checks the change and avoids the notification, but the GSettingsBinding calls g_object_set_property(), which does the notification "for me", and thus my signal connector on "notify::property-name" signal, which relies on correct notifications and has no ability to check for changes, because it's another objects which updates yet another objects when certain property of the source object changes.

I do not know whether it's understood from the above, but the chain is this:
a) false change notification from dconf, which causes
b) false change notification from GSettings, which causes
c) false change notification from GSettingsBinding, which causes
d) false change notification from GObject's set_property(), which causes
e) call of "notify::property-name" callback, which relies on true
   notifications, because it runs flood of expensive operations when
   the property changes.

The backtrace I talk about, with debuginfo for eds and evo only, from 3.8.5 of both:

Thread 1 (Thread 0x7fd475052a40 (LWP 13349))

  • #0 WebCore::CachedResource::addClientToSet(WebCore::CachedResourceClient*)
    from /lib64/libwebkitgtk-3.0.so.0
  • #1 WebCore::CachedResource::addClient(WebCore::CachedResourceClient*)
    from /lib64/libwebkitgtk-3.0.so.0
  • #2 WebCore::MainResourceLoader::load(WebCore::ResourceRequest const&, WebCore::SubstituteData const&)
    from /lib64/libwebkitgtk-3.0.so.0
  • #3 WebCore::DocumentLoader::startLoadingMainResource()
    from /lib64/libwebkitgtk-3.0.so.0
  • #4 WebCore::FrameLoader::continueLoadAfterNavigationPolicy(WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, bool)
    from /lib64/libwebkitgtk-3.0.so.0
  • #5 WebCore::FrameLoader::callContinueLoadAfterNavigationPolicy(void*, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, bool)
    from /lib64/libwebkitgtk-3.0.so.0
  • #6 WebCore::PolicyCallback::call(bool)
    from /lib64/libwebkitgtk-3.0.so.0
  • #7 WebCore::PolicyChecker::continueAfterNavigationPolicy(WebCore::PolicyAction)
    from /lib64/libwebkitgtk-3.0.so.0
  • #8 WebKit::FrameLoaderClient::dispatchDecidePolicyForNavigationAction(void (WebCore::PolicyChecker::*)(WebCore::PolicyAction), WebCore::NavigationAction const&, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>)
    from /lib64/libwebkitgtk-3.0.so.0
  • #9 WebCore::PolicyChecker::checkNavigationPolicy(WebCore::ResourceRequest const&, WebCore::DocumentLoader*, WTF::PassRefPtr<WebCore::FormState>, void (*)(void*, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, bool), void*)
    from /lib64/libwebkitgtk-3.0.so.0
  • #10 WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader*, WebCore::FrameLoadType, WTF::PassRefPtr<WebCore::FormState>)
    from /lib64/libwebkitgtk-3.0.so.0
  • #11 WebCore::FrameLoader::reloadWithRequest(WebCore::ResourceRequest const&, bool)
    from /lib64/libwebkitgtk-3.0.so.0
  • #12 WebCore::FrameLoader::reload(bool)
    from /lib64/libwebkitgtk-3.0.so.0
  • #13 e_web_view_reload
    at e-web-view.c line 1836
  • #14 e_mail_display_load_images
    at e-mail-display.c line 2084
  • #15 formatter_image_loading_policy_changed_cb
    at e-mail-display.c line 169
  • #16 g_closure_invoke
    from /lib64/libgobject-2.0.so.0
  • #17 signal_emit_unlocked_R
    from /lib64/libgobject-2.0.so.0
  • #18 g_signal_emit_valist
    from /lib64/libgobject-2.0.so.0
  • #19 g_signal_emit
    from /lib64/libgobject-2.0.so.0
  • #20 g_object_dispatch_properties_changed
    from /lib64/libgobject-2.0.so.0
  • #21 g_object_notify_queue_thaw
    from /lib64/libgobject-2.0.so.0
  • #22 g_object_set_property
    from /lib64/libgobject-2.0.so.0
  • #23 on_source_notify
    from /lib64/libgobject-2.0.so.0
  • #24 g_closure_invoke
    from /lib64/libgobject-2.0.so.0
  • #25 signal_emit_unlocked_R
    from /lib64/libgobject-2.0.so.0
  • #26 g_signal_emit_valist
    from /lib64/libgobject-2.0.so.0
  • #27 g_signal_emit
    from /lib64/libgobject-2.0.so.0
  • #28 g_object_dispatch_properties_changed
    from /lib64/libgobject-2.0.so.0
  • #29 g_object_notify_queue_thaw
    from /lib64/libgobject-2.0.so.0
  • #30 g_object_set_property
    from /lib64/libgobject-2.0.so.0
  • #31 g_settings_binding_key_changed
    from /lib64/libgio-2.0.so.0
  • #32 g_cclosure_marshal_VOID__STRINGv
    from /lib64/libgobject-2.0.so.0
  • #33 _g_closure_invoke_va
    from /lib64/libgobject-2.0.so.0
  • #34 g_signal_emit_valist
    from /lib64/libgobject-2.0.so.0
  • #35 g_signal_emit
    from /lib64/libgobject-2.0.so.0
  • #36 g_settings_real_change_event
    from /lib64/libgio-2.0.so.0
  • #37 ffi_call_unix64
    from /lib64/libffi.so.6
  • #38 ffi_call
    from /lib64/libffi.so.6
  • #39 g_cclosure_marshal_generic_va
    from /lib64/libgobject-2.0.so.0
  • #40 _g_closure_invoke_va
    from /lib64/libgobject-2.0.so.0
  • #41 g_signal_emit_valist
    from /lib64/libgobject-2.0.so.0
  • #42 g_signal_emit
    from /lib64/libgobject-2.0.so.0
  • #43 settings_backend_path_changed
    from /lib64/libgio-2.0.so.0
  • #44 g_settings_backend_invoke_closure
    from /lib64/libgio-2.0.so.0
  • #45 g_main_context_dispatch
    from /lib64/libglib-2.0.so.0
  • #46 g_main_context_iterate.isra.22
    from /lib64/libglib-2.0.so.0
  • #47 g_main_loop_run
    from /lib64/libglib-2.0.so.0
  • #48 gtk_main
    from /lib64/libgtk-3.so.0
  • #49 main
    at main.c line 707

Comment 6 Allison Karlitskaya (desrt) 2014-06-03 17:46:11 UTC
But this is really just a bug in GObject that you're talking about now -- the fact that _set() sends notify unconditionally.  That's something that is fixed by GProperty, fwiw..
Comment 7 Matthew Barnes 2014-06-03 19:50:01 UTC
(In reply to comment #5)

I think you're just going to have to handle these things case-by-case.

In the example you mentioned, EMailDisplay should stash the last-used image loading policy internally and check it against EMailFormatter's current policy at the beginning of its "notify" handler.  If there is no actual change, have the handler return without doing anything.
Comment 8 Milan Crha 2014-06-04 06:25:29 UTC
(In reply to comment #7)
> I think you're just going to have to handle these things case-by-case.

That's the problem, anything I do will be a workaround for these GObject/GSettingsBindings/dconf false notifications. This case is even simple, but there can be tens to hundreds of such cases in the code.
Comment 9 Allison Karlitskaya (desrt) 2014-06-04 11:09:36 UTC
I agree that a fix is needed here -- but it is to GObject, not GSettings.
Comment 10 Allison Karlitskaya (desrt) 2014-06-04 11:20:07 UTC
I've opened bug 731200 to deal with this issue separately.  No reason we can't do a fix this cycle.