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 502924 - Only ref() event members if they are still referenced after the callback returns
Only ref() event members if they are still referenced after the callback returns
Status: RESOLVED OBSOLETE
Product: pyatspi2
Classification: Applications
Component: general
unspecified
Other Linux
: Normal normal
: ---
Assigned To: At-spi maintainer(s)
At-spi maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2007-12-10 21:07 UTC by Eitan Isaacson
Modified: 2021-07-05 12:36 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Proposed changes (4.19 KB, patch)
2007-12-10 21:12 UTC, Eitan Isaacson
none Details | Review
Proposed changes (3.21 KB, patch)
2008-01-18 09:09 UTC, Eitan Isaacson
none Details | Review

Description Eitan Isaacson 2007-12-10 21:07:48 UTC
Event callbacks receive references to a number of remote accessible objects through an Event structure. The remote objects are not ref()ed because the are only "borrowed" by the callback, if the AT wishes to use any of the remote objects at a later date after the callback returns, they must be ref()ed.

In the status quo the remote objects are reffed unconditionally. This introduces a certain traffic overhead since every time an event callback is called, even if it is empty the member objects are implicitly ref()ed and unref()ed.
Comment 1 Eitan Isaacson 2007-12-10 21:12:58 UTC
Created attachment 100713 [details] [review]
Proposed changes

This patch determines weather a reference is being heldby the remote objects after the callbacks return. If there are still references, it does a ref().

This patch depends on a pyorbit weakref support patch found in bug 502925.
Comment 2 Eitan Isaacson 2008-01-18 09:09:33 UTC
Created attachment 103125 [details] [review]
Proposed changes

This patch gets rid of the weakref scheme, and simply uses sys.getrefcout instead.
Comment 3 Peter Parente 2008-01-19 17:49:59 UTC
Comment on attachment 103125 [details] [review]
Proposed changes

Some a general questions:

What happens if the user has given async=True to Registry.start()? Alternatively, what happens if the client is doing some for of decoupling where all events received are stored for later dispatch to avoid blocking the bridge? In both of these cases, the Python ref count *all* events received will increase by 1 by design, regardless of whether they are used later or not. But what about the accessibles attached to the events? Just storing an event doesn't increase the ref count of the accessibles automatically does it? So will these accessibles be improperly discarded while the event is being held in the dispatch queue?

>+
>+    # Record the current reference count of the event object and it's
>+    # remote-object structure members.
>+    prev_refs = {'event': sys.getrefcount(ev)}
>+    for attrib in ('source', 'any_data', 'host_application'):
>+      refrencable = getattr(ev, attrib, None)
>+      if isinstance(refrencable, Accessibility.Accessible):
>+        refrencable.dont_unref = True
>+        prev_refs[attrib] = sys.getrefcount(refrencable)

I worry a bit about the performance of creating a dictionary, looping, and hashing for every event received. It might be worth exploring some optimizations like unrolling the loop, keeping separate vars for the four known fields, etc. Need to profile.

>+    # If there is an extra reference to the event object we need to ref()
>+    # all the member objects.
>+    ref_all =  sys.getrefcount(ev) - prev_refs['event'] > 0
>+    
>+    # If there is an extra reference to any remote object - ref() it.
>+    for attrib in prev_refs:
>+      refrencable = getattr(ev, attrib, None)
>+      if refrencable is not None:
>+        if ref_all or \
>+           sys.getrefcount(refrencable) - prev_refs[attrib] > 0:
>+          refrencable.ref()
>+          refrencable.dont_unref = False

Again, some performance concerns about iterating for every event. More importantly, the question about storing the Python event, but never explicitly touching its accessible member variables applies here. Will they be properly ORBit ref counted?

>-  SLOTS = ('_icache', '_property_cache', '_user_data')
>+  SLOTS = ('_icache', '_property_cache', '_user_data', 'dont_unref')

dont_unref should start with a _ like the other properties.
Comment 4 Eitan Isaacson 2008-01-21 20:59:34 UTC
(In reply to comment #3)
> What happens if the user has given async=True to Registry.start()?
> Alternatively, what happens if the client is doing some for of decoupling where
> all events received are stored for later dispatch to avoid blocking the bridge?
> In both of these cases, the Python ref count *all* events received will
> increase by 1 by design, regardless of whether they are used later or not. 

Yup, if async is True or if the client is doing it's own decoupling then we don't get any of the "borrowing" benefit. And the objects are always ref()ed.
The only time when this will be a possible optimization is if the client is doing the decoupling, but it is also dropping events that don't meet certain criteria, maybe if the event.hot_application is not the right app.

> But what about the accessibles attached to the events? Just storing an event
> doesn't increase the ref count of the accessibles automatically does it? So
> will these accessibles be improperly discarded while the event is being held 
> in the dispatch queue?
If the event instance is stored then all of the remote object members will be ref()ed:
ref_all =  sys.getrefcount(ev) - prev_refs['event'] > 0

> It might be worth exploring some
> optimizations like unrolling the loop, keeping separate vars for the four known
> fields, etc. Need to profile.

Yeah, that shouldn't be a problem, we could just unroll it. Overall the question is does this add a layer of complexity that will get us in trouble later, or maybe all the extra logic makes it not worthwhile for performance.

> More
> importantly, the question about storing the Python event, but never explicitly
> touching its accessible member variables applies here. Will they be properly
> ORBit ref counted?
>

I believe so. I ran a few automated Orca tests and the output (braille/speech) results are identical with or without the patch. I also tested this by storing every other event and seeing if it ref()ed everything it needed to. It did.
 
> dont_unref should start with a _ like the other properties.

I figured not to prefix it with _ because it was a public attribute. I think it is ugly in general, I would like to find a more elegant solution.
 

Comment 5 André Klapper 2012-02-26 10:41:34 UTC
[Resetting QA Contact to newly introduced "at-spi-maint@gnome.bugs". 
Reason: So far it was impossible to watch changes in at-spi bug reports without following all the specific persons (Li Yuan, Bill Haneman, Jeff Wai, ...) and also their activity outside of at-spi reports.

IMPORTANT: Anyone interested in following all bug activity (including all maintainers) must watch the "at-spi-maint@gnome.bugs" dummy user by adding it to the 'Users to watch' list under Preferences->Email preferences. This is also the default procedure nowadays in GNOME when setting up new products.]
Comment 6 André Klapper 2013-08-14 10:04:24 UTC
[Mass-resetting default assignee, see bug 705890. Please reclaim this bug report by setting the assignee to yourself if you still plan to work on this. Thanks!]
Comment 7 GNOME Infrastructure Team 2021-07-05 12:36:49 UTC
GNOME is going to shut down bugzilla.gnome.org in favor of gitlab.gnome.org.
As part of that, we are mass-closing older open tickets in bugzilla.gnome.org
which have not seen updates for a longer time (resources are unfortunately
quite limited so not every ticket can get handled).

If you can still reproduce the situation described in this ticket in a recent
and supported software version, then please follow
  https://wiki.gnome.org/GettingInTouch/BugReportingGuidelines
and create a new ticket at
  https://gitlab.gnome.org/GNOME/pyatspi2/-/issues/

Thank you for your understanding and your help.