Re: libatspi and event processing





On 05.03.2015 05:14, Mike Gorse wrote:
Not really an answer, but the call to process_deferred_messages() is the
interesting bit here. When an AT-SPI event is received, it is queued for
later processing via process_deferred_messages, which is executed either
in an idle handler or at the end of a method call. Iirc this is done in
order to control the order in which events are sent, as it will not
recurse.

Yes, I also think that events order is essential for capturing proper application state. However I have a feeling that this order has to be kept only for dbus signals messages (like state-changed, children-changes, value-change etc). Messages that are response to method calls can be processed beforehead dbus signals with, I suppose, no harm to atspi object tree state. But its only a guess :)

I'm not sure if the process_deferred_messages() calls at the ends of
these AT-SPI functions need to be there. Perhaps they should be removed,
although I'd be hesitant to remove them for 3.16 this late in the
cycle--the code has worked that way for a long time... Feel free to file
a bug if you'd like it to be tracked that way.

I'm not really in position of pointing that it is a bug or not. It's just an issue I have encountered in my code, which causes very rare, hard to reproduce and to debug bugs. It just changed flow of my program in a way that I was not expecting. There is no single sentence in documentation that says about triggering events in atspi functions, so I considered it must just block and wait for response - however not only. So my final thought is: 1. Just fix a docs and let accessibility apps programmers deal with it. 2. Rearrange dbus message processing order (it might break something, but I don't know atspi so well to deduced what)

On Tue, 3 Mar 2015, Lukasz Stanislawski wrote:

Hey, thank Tou for quick answer.

On 02.03.2015 18:39, Alejandro Piñeiro wrote:
On 02/03/15 18:08, Lukasz Stanislawski wrote:
Hello everyone,

Currently, I'm developing small C application using libatspi and
encountered some problems with event processing.

What I have is two event listeners A and B registered with
atspi_event_listener_register() on different at-spi events. Inside
main loop assume that A listener can invoke callback a() on some atspi
event. Inside a() callback there are some calls to
atspi_accessible_get_* functions.

What I have noticed is that calling functins like.
atspi_accessible_get_name() triggers further dbus events processing
what result in different listeners to be invoked.

Those get functions need to trigger those dbus events, as the
information is usually not stored (except if it is already cached) at
libatspi. It needs to be requested to the client (the application). So
it is not possible to avoid that dbus triggering, as is the only way to
get the info you request.

Yeah, it is not possible to avoid dbus triggering when method is
invoked, however is it possible not to process mismatching events?
(eg. whem atspi_accessibile_get_name method is invoked only dbus
message matching returning name will be processed) Can rest of events
gathered while waiting for answer be queued and processed when main
loop enters idle state?

As the result code of b() callback can be invoked (and sometimes is in
my application) during execution of a() callback code.called

About getting the other callback called because a different listener is
invoked: it is complicated to understand your problem at a so abstract
level. Could you give a example of what event is triggered when
atspi_accessible_get_<something> that invokes the second callback?

My real life example is a bit different and more complex however I
will try to explain it in details. I have an accessibility application
allowing users to navigate only over specific type of widgets etc,
with some various policies.

To do this, first of all I have to be able to track what window have
currently input focus. I'm doing it by registering listener on
"window:active" and "object:state-changed:focused". When any of these
events occurs on_window_activate callback is called.

Secondly. when window receives focus I have to gather all interesting
information from accessibility tree and build my own cache from data
that is not cached by atspi like positions and sizes. It occurred that
there are some performance issues with it, (main loop is blocked too
long not allowing other events to be processed), so I have decided to
fetch data partially using idlers.

When my own data cache is done I start to process it and through the
processing of data a call to atspi_accessibile_get_role is made. This
causes the issues which I have mentioned earlier. When new
"window:active" signal was send, it will process it and call
on_window_activate callback which in my code - invalidates my cache.

When atspi_accessible_get_role returns my cache is already invalid.
This resulted in cache errors and I couldn't find out what is
happening unless i have looked into atspi source code.

This situations mostly happens when application right after gaining
focus on window creates new window and focuses. This is a result
backtrace, please check frame #14, #9 and #0 :

#0 on_window_activate (data=0x0, window=0xaf560)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/navigator.c:822
#1 0x0000e4f4 in _on_atspi_window_cb (event=0xd1ff8)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/window_tracker.c:18
#2 0xb6d9a638 in remove_datum (event=<optimized out>,
user_data=<optimized out>) at atspi-event-listener.c:56
#3 0xb6d9afd0 in _atspi_send_event (e=0xbefff8d8)
at atspi-event-listener.c:849
#4 0xb6d9b1c2 in _atspi_dbus_handle_event (bus=<optimized out>,
message=<optimized out>, data=<optimized out>)
at atspi-event-listener.c:979
#5 0xb6d9d2e0 in process_deferred_message (closure=0xc65a8)
at atspi-misc.c:748
#6 process_deferred_messages () at atspi-misc.c:787
#7 process_deferred_messages () at atspi-misc.c:777
#8 0xb6d9d6f2 in _atspi_dbus_call (obj=<optimized out>,
interface=<optimized out>, method=0xb6da4fc0 "GetRole", error=0x0,
type=0xb6da4fc8 "=>u") at atspi-misc.c:1152
#9 0xb6d98c3a in atspi_accessible_get_role (obj=0xc2718,
error=<optimized out>) at atspi-accessible.c:473
#10 0x0000dae0 in _filter_role_cb (container=<optimized out>,
data=<optimized out>, fdata=0x_on_cache_buildedc2718)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:153
--Type <return> to continue, or q <return> to quit--
#11 0x0000da92 in _accessible_list_split_with_filter (list=0x5a8e8,
cb=0xdac5 <_filter_role_cb>, user_data=0x11e0c <interesting_roles>)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:112
#12 0x0000dc34 in _flat_review_candidates_get (root=<optimized out>)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:213
#13 flat_navi_context_create (root=<optimized out>)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/flat_navi.c:257
#14 0x0000fa4e in _on_cache_builded (data=<optimized out>)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/navigator.c:802
#15 0x0000e878 in _do_cache (data=<optimized out>)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/object_cache.c:173
#16 _do_cache (data=<optimized out>)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/object_cache.c:163
#17 0xb6e05860 in _ecore_call_task_cb (data=<optimized out>,
func=<optimized out>) at ecore_private.h:272
#18 _ecore_idler_all_call () at ecore_idler.c:119
#19 0xb6e067c6 in _ecore_main_loop_spin_core () at ecore_main.c:1746
#20 0xb6e069d8 in _ecore_main_loop_spin_timers () at ecore_main.c:1780
#21 _ecore_main_loop_iterate_internal (once_only=0) at ecore_main.c:1903
#22 0xb6e06dc0 in ecore_main_loop_begin () at ecore_main.c:956
#23 0xb6fa5ab6 in appcore_efl_main () from /usr/lib/libappcore-efl.so.1
#24 0x0000bfcc in main (argc=1, argv=0xbefffdc4)
at /usr/src/debug/org.tizen.smart-navigator-0.0.1/src/main.c:71

I have managed to solve my issues by simple removing all calls to
atspi_accessible_get_* in my cache processing code. However I was
carious if I'm doing something wrong or just atspi programmer have to
be aware that this can happen. Maybe shouldn't it be better if it
worked as I wrote in first at the begining, What do You think?


I find this very inconvenient because every atspi_accessible_get_*
related call in callback a() have to be wrapped with some 'rollback'
logic in my application, because events of listener B can occur.

So my questions are:

1. What is a preferred way of handling such cases? I want every
callback to process sequentially and not to introduce new race
conditions in my application. Such APIs makes my code hard to write
because "everything can happen everywhere".

As mentioned, if in your callback you call new atspi methods, they would
need to use dbus to get that info. But it would be good to have a real
example in order to know why this is problematic.

2. Shouldn't it be better to dispatch all deferred events when main
loop enters idle state? Mayby there is a reasoning for such design
that I'm not familiar of.

You seem to suggest the addition of an asynchronous API. If that is the
case, it is true that there are some attempts to include an asynchronous
API in order to solve some issues of the classic libatspi synchronous
API. But in most cases, libatspi is still an asynchronous API.

BR

_______________________________________________
gnome-accessibility-list mailing list
gnome-accessibility-list gnome org
https://mail.gnome.org/mailman/listinfo/gnome-accessibility-list



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]