Discussion:
[Interest] Survey: do you override QCoreApplication::notify? Why?
Thiago Macieira
2015-04-15 23:45:57 UTC
Permalink
Hello

We're running into problems with QCoreApplication::notify() and auxiliary
threads in Qt. Details can be found in [1] and [2].

As part of trying to design the solution, I'd like to know what people
override QCoreApplication::notify() for.

So, if you do override, do you:
1) use it to log exceptions that were caught?
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
3) log/profile/debug events being delivered?
4) filter events being delivered (remove from queue / compress)?
5) insert events somehow
6) something else (please explain)

If you're doing #3, have you tried GammaRay? Is that notify() enabled for
production builds?

And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?

[1] http://lists.qt-project.org/pipermail/development/2015-April/021053.html
[2] https://codereview.qt-project.org/110325
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
John Weeks
2015-04-16 01:23:35 UTC
Permalink
Post by Thiago Macieira
4) filter events being delivered (remove from queue / compress)?
We do this.
We also maintain our own z-order window list and use the notify event to intercept WindowActivated and WindowDeactivated events.
The application includes a programming language that users can use to create, destroy and modify objects and do arbitrary computations. It's sufficiently powerful that our customers often implement scientific computations for things that aren't provided as built-ins, and they create their own GUIs for various kinds of scientific endeavors. During user code execution we need fine-grained control of events, and it's not always possible to identify an object to which a filter can be attached.

The decision to use notify() was made very early in our use of Qt- it's conceivable that we would have designed it differently if we were starting from our present knowledge of Qt. But maybe not. It was based in part on reading C++ GUI Programming with Qt 4.
Post by Thiago Macieira
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
This too.
Post by Thiago Macieira
And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?
Main thread only. Much of our use of notify() is for more fine-grained control of event delivery, where QEventLoop::ExcludeUserInputEvents excludes too much.

-John Weeks
Alejandro Exojo
2015-04-17 21:46:25 UTC
Permalink
Post by John Weeks
Post by Thiago Macieira
4) filter events being delivered (remove from queue / compress)?
We do this.
Could you elaborate a bit on how do you do it?

Filtering events is easy, but when I searched a bit in the past about this, I
found that there is no public API for accessing the queue. Only way it ocurs
to me right now is keeping some kind of count for the custom event, so your
handler sees the count and runs only once. I haven't attempted to do it,
though. Some feature requests on JIRA:

https://bugreports.qt.io/browse/QTBUG-2688
https://bugreports.qt.io/browse/QTBUG-44293
--
Alex (a.k.a. suy) | GPG ID 0x0B8B0BC2
http://barnacity.net/ | http://disperso.net
John Weeks
2015-04-17 22:07:27 UTC
Permalink
Post by Alejandro Exojo
Post by John Weeks
Post by Thiago Macieira
4) filter events being delivered (remove from queue / compress)?
We do this.
Could you elaborate a bit on how do you do it?
My answer was a bit short, wasn't it? I was responding to the part about filtering. We use only the ability to return true from the notify() function to mean "block this event". We don't try to remove anything from the queue.

In fact, sometimes this isn't enough- at least on Macintosh, a click in a window's title bar that activates a window doesn't pass through notify(), you only see the resulting windowActivated and windowDeactivated events.

We have a feature in which our customers can create an "almost modal" window- it's modal except that some other window is allowed interaction. This was done so that a customer can create a control panel (window with controls, like a modeless dialog) that allows the user of his control panel to interact with a graph window and with the control panel, in an otherwise modal state. So we filter mouse events (and other UI events) for windows other than the control panel or graph window.

Also, code in our internal language prevents UI interaction, except that certain keys or a click on an Abort button can cancel execution. That allows stopping an infinite loop, or a complex computation that might go on for a long time (one of our customers was asking for optimization tips because his code ran all night and didn't finish).

-John Weeks
alexander golks
2015-04-16 06:11:08 UTC
Permalink
hi,
Post by Thiago Macieira
As part of trying to design the solution, I'd like to know what people
override QCoreApplication::notify() for.
we have 3rd party plugins - beside our own crude code, sometimes - called in threads and in q(core)application in various situations, which throw exceptions. errors, yes, but we have to deal with it.
so 1)-3) are applied. normally we continue execution after catched exceptions.

i am pretty sure, by redesigning our software we could remove this "use" cases, but this is work for years, thus no real option currently.
Post by Thiago Macieira
If you're doing #3, have you tried GammaRay? Is that notify() enabled for
production builds?
this is definitly enabled in production code, too, as we have found plugins to behave different in debug and release. and i can't walk to our customers and run a gammaray session in production environment.

4) is used in gui thread, to filter events.
i tried to use 4) and 5) to simulate events, for which i haven't found time yet to finish it successfully.
Post by Thiago Macieira
And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?
all.

hope this helps abit.

alex
--
/*
* panic("Unable to find empty mailbox for aha1542.\n");
* linux-2.2.16/drivers/scsi/aha1542.c
*/
Björn Piltz
2015-04-16 08:28:51 UTC
Permalink
To catch and abort.
Post by alexander golks
hi,
Post by Thiago Macieira
As part of trying to design the solution, I'd like to know what people
override QCoreApplication::notify() for.
we have 3rd party plugins - beside our own crude code, sometimes - called
in threads and in q(core)application in various situations, which throw
exceptions. errors, yes, but we have to deal with it.
so 1)-3) are applied. normally we continue execution after catched exceptions.
i am pretty sure, by redesigning our software we could remove this "use"
cases, but this is work for years, thus no real option currently.
Post by Thiago Macieira
If you're doing #3, have you tried GammaRay? Is that notify() enabled for
production builds?
this is definitly enabled in production code, too, as we have found
plugins to behave different in debug and release. and i can't walk to our
customers and run a gammaray session in production environment.
4) is used in gui thread, to filter events.
i tried to use 4) and 5) to simulate events, for which i haven't found
time yet to finish it successfully.
Post by Thiago Macieira
And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?
all.
hope this helps abit.
alex
--
/*
* panic("Unable to find empty mailbox for aha1542.\n");
* linux-2.2.16/drivers/scsi/aha1542.c
*/
_______________________________________________
Interest mailing list
http://lists.qt-project.org/mailman/listinfo/interest
Harri Porten
2015-04-16 09:02:18 UTC
Permalink
Post by Thiago Macieira
1) use it to log exceptions that were caught?
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
3) log/profile/debug events being delivered?
We do something like 3)
Post by Thiago Macieira
4) filter events being delivered (remove from queue / compress)?
5) insert events somehow
6) something else (please explain)
If you're doing #3, have you tried GammaRay? Is that notify() enabled for
production builds?
And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?
Only for the main thread. In fact, on the day the first event from another
thread arrived we were caught be surprise :}

Harri.
Boudewijn Rempt
2015-04-16 10:35:36 UTC
Permalink
Post by Thiago Macieira
Hello
We're running into problems with QCoreApplication::notify() and auxiliary
threads in Qt. Details can be found in [1] and [2].
As part of trying to design the solution, I'd like to know what people
override QCoreApplication::notify() for.
We do in Calligra and Krita.
Post by Thiago Macieira
1) use it to log exceptions that were caught?
Yes
Post by Thiago Macieira
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
We don't continue after an exception, but catch, log and abort.
Post by Thiago Macieira
3) log/profile/debug events being delivered?
No
Post by Thiago Macieira
4) filter events being delivered (remove from queue / compress)?
No
Post by Thiago Macieira
5) insert events somehow
No
Post by Thiago Macieira
6) something else (please explain)
If you're doing #3, have you tried GammaRay?
Is that notify() enabled for
production builds?
And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?
For all threads.
Post by Thiago Macieira
[1] http://lists.qt-project.org/pipermail/development/2015-April/021053.html
[2] https://codereview.qt-project.org/110325
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Thiago Macieira
2015-04-16 16:16:15 UTC
Permalink
Post by Boudewijn Rempt
Post by Thiago Macieira
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
We don't continue after an exception, but catch, log and abort.
Like I replied to Björn, std::terminate already does that.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
André Somers
2015-04-17 06:41:35 UTC
Permalink
Post by Thiago Macieira
Post by Boudewijn Rempt
Post by Thiago Macieira
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
We don't continue after an exception, but catch, log and abort.
Like I replied to Björn, std::terminate already does that.
Including the logging part?

André
Thiago Macieira
2015-04-17 06:51:54 UTC
Permalink
Post by André Somers
Post by Thiago Macieira
Post by Boudewijn Rempt
Post by Thiago Macieira
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
We don't continue after an exception, but catch, log and abort.
Like I replied to Björn, std::terminate already does that.
Including the logging part?
It prints the exception type to stderr. If you want to log something different,
install a different terminate handler.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Guido Seifert
2015-04-17 15:27:39 UTC
Permalink
Post by Thiago Macieira
It prints the exception type to stderr. If you want to log something different,
install a different terminate handler.
Does this work? I don't see how a terminate handler gets the thrown object. A terminate
handler takes no parameter and returns void. I am using notify only with use case 1.
During development when I implement an exception, but are too lazy to do the exception
handling immediately. The exception gets a 'FIXME:', which is nicely shown in QtC.
If it is against my expectations thrown, a log output from notify shows me where and why
it was thrown. Before release the FIXMEs are fixed and the try/catch around notify does
not matter anymore. I could live without it, but find it very convenient.

Guido
Thiago Macieira
2015-04-17 15:37:00 UTC
Permalink
Post by Guido Seifert
Post by Thiago Macieira
It prints the exception type to stderr. If you want to log something
different, install a different terminate handler.
Does this work? I don't see how a terminate handler gets the thrown object.
There's a function to get the current exception somewhere. Please take a look
at your C++ standard library runtime documentation. I have no need of knowing
which functions those are and how they operate because I don't use exceptions,
so I can't help further.
Post by Guido Seifert
A terminate handler takes no parameter and returns void. I am using notify
only with use case 1. During development when I implement an exception, but
are too lazy to do the exception handling immediately. The exception gets a
'FIXME:', which is nicely shown in QtC. If it is against my expectations
thrown, a log output from notify shows me where and why it was thrown.
Before release the FIXMEs are fixed and the try/catch around notify does
not matter anymore. I could live without it, but find it very convenient.
You don't need a log output for that. If you don't catch the exception, it
will cause the application to terminate (with a core dump, if you have that
enabled), so you can not only get the exception name, you get the exact
backtrace of how you got there and the state of the variables leading to the
throwing.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Guido Seifert
2015-04-17 15:53:40 UTC
Permalink
Post by Thiago Macieira
I have no need of knowing
which functions those are and how they operate because I don't use exceptions,
so I can't help further.
:-)
And I don't because I usually use Qt. And in the few of my projects, which did not use qt,
exceptions were forbidden.
Post by Thiago Macieira
You don't need a log output for that. If you don't catch the exception, it
will cause the application to terminate (with a core dump, if you have that
enabled), so you can not only get the exception name, you get the exact
backtrace of how you got there and the state of the variables leading to the
throwing.
I know, but it still is not too convenient. In the console I get only something
like "terminate called after throwing an instance of '<whatever>'. No indication
where the exception was thrown. To see this I have to find and examine the core,
or I have to run the program in the QtC debugger, which I don't do very often.
As I said: Such a catch all around notify with a few qDebugs in it is nice to
have. At least for my current development style.

Guido
Thiago Macieira
2015-04-17 16:03:08 UTC
Permalink
Post by Guido Seifert
I know, but it still is not too convenient. In the console I get only
something like "terminate called after throwing an instance of
'<whatever>'. No indication where the exception was thrown. To see this I
have to find and examine the core, or I have to run the program in the QtC
debugger, which I don't do very often. As I said: Such a catch all around
notify with a few qDebugs in it is nice to have. At least for my current
development style.
You could install a terminate handler that would launch gdb -pid <insert pid
here> and tell it to print a full backtrace, before exiting the application.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Thiago Macieira
2015-04-17 18:13:13 UTC
Permalink
Post by Thiago Macieira
Post by Guido Seifert
I know, but it still is not too convenient. In the console I get only
something like "terminate called after throwing an instance of
'<whatever>'. No indication where the exception was thrown. To see this I
have to find and examine the core, or I have to run the program in the QtC
debugger, which I don't do very often. As I said: Such a catch all around
notify with a few qDebugs in it is nice to have. At least for my current
development style.
You could install a terminate handler that would launch gdb -pid <insert pid
here> and tell it to print a full backtrace, before exiting the application.
In fact, you can also do that with a signal handler for SIGABRT, SIGSEGV and
SIGBUS and catch more situations.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Guido Seifert
2015-04-17 18:48:26 UTC
Permalink
Thanks, got it.... Just a bit different than you proposed :-)

My problem was to get the thrown object in the terminate handler.
I searched for that, but it looks like there really is no such
function.

However, with this trick in the custom terminate it is possible
std::exception_ptr exptr = std::current_exception();
try {
std::rethrow_exception(exptr);
}
catch (MyErrorObject &error) {
qDebug() << "Uncaught exception" << error.message;
}
Though a std::exception_ptr exptr cannot be cast directly into the thrown
object type, it can be rethrowen in the terminate handler and immediately
caught as the expected error object.

Your other solution looks plausible, Thiago, but with the above
method I don't need to change the workflow I am used to at all.
Instead of try/catching around notify, I just add above terminate
handler. Problem solved. :-)

Guido
Nikos Chantziaras
2015-04-16 12:46:57 UTC
Permalink
Post by Thiago Macieira
As part of trying to design the solution, I'd like to know what people
override QCoreApplication::notify() for.
I override QApplication::notify() in order to catch media keys (volume
up/down, stop, play, etc.) on the application level, regardless of which
window in the application has the current keyboard focus.
Post by Thiago Macieira
And additional question: do you need this for the main thread only, for
auxiliary threads only or for all threads?
Main thread only.
Adam Light
2015-04-16 13:26:45 UTC
Permalink
John Weeks and I are working on the same application, so don't double count
Post by Thiago Macieira
2) use it to catch exceptions and continue execution?
or use it to catch and abort?
If we catch an uncaught exception from our QApplication::notify()
reimplementation, we give the user the option to save his work. Depending
on the reason for the uncaught exception, this may or may not actually
succeed, but we at least allow for the possibility. In my experience, it
typically is successful.

Then, whether or not he chose to save the work, we call quit().

Adam
Thiago Macieira
2015-04-17 23:25:38 UTC
Permalink
Post by Thiago Macieira
Hello
We're running into problems with QCoreApplication::notify() and auxiliary
threads in Qt. Details can be found in [1] and [2].
[1] http://lists.qt-project.org/pipermail/development/2015-April/021053.html
[2] https://codereview.qt-project.org/110325
Thanks to all that replied. The solution being implemented can be seen in
https://codereview.qt-project.org/110643

It's private API only, so it will not affect your current uses of
QCoreApplication::notify(), unless you're trying to catch events from Qt's own
threads. The solution I'm implementing will make it so Qt's own threads do not
go through QCoreApplication::notify().

However, be advised that you need to ensure ALL threads stop delivering events
before your application object begins destruction. That includes threads you
did not directly start, but were started on your behalf inside other libraries
(and anywhere I didn't catch in Qt). If you can't guarantee that, stop
overriding notify() -- there's no other possible solution.

This is not a new requirement. It's been there since Qt 3.0, but no one
noticed until now. It is undefined behaviour[*] if you fail to do that.

For that reason, Qt 6.0, whenever that happens, will stop calling notify()
outside the main thread. In Qt 5.0, we did that for event filters installed in
the main application. See the notices in
https://codereview.qt-project.org/110644

[*] understand "undefined behaviour" in the C++ standard terms: *anything* can
happen, from nothing to defrosting your fridge to launching a nuclear attack.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Loading...