On Thu, Dec 14, 2023 at 12:03:55 +0000, John Levon wrote:
On Thu, Dec 14, 2023 at 12:18:27PM +0100, Peter Krempa wrote:
> While I have no problems with virErrorPreserveLast() as that's just
> syntax sugar on top of existing public functions, I don't think that
> it's a good idea to expose virErrorRestore() as that gives the access to
> previously unexposed virSetError(). This gives the users possibility to
> set arbitrary errors due to the error struct being public as noted
> above.
This sounds very much like a "don't do that then" scenario.
> Saving an error to a custom error object should be enough and I don't
> really see a point in making libvirt carry it around with the
> possibility of it being overwritten at any point by another library
> call.
Please note that virErrorRestore() is used (almost [1]) exclusively
inside libvirt's library code, thus *before* the error itself gets
raised to the caller of a public libvirt API.
Also TBH I'm not a fan of the passing of errors via the thread local
variable because, while it's convenient in the simple cases, for any
more complicated cases it just creates headaches (even internally).
As in your original problem statement it also makes problems when you
want to associate the error itself with the function call that caused
it.
I'm not very clear on your suggestion. If I can't restore the
libvirt
error in the error callback, how would the eventual API call return have
the right error?
Are you suggesting I have to have custom logic to save the error to some
thread-local location, and change every single API call handling to look there,
ignoring the API return value and error object?
If you need any form of more complex logic in your application for error
reporting (ab)using libvirt's thread local variable to store the error
for other functions in your application will not bring too much
simplification of the logic itself.
Additionally care would still have to be taken to use e.g. libvirt's
cleanup functions which would still reset the thread local error.
Applications which wish to do delayed error reporting have the means to
do so by having their own instance of virError, either per process (as
virsh does), or any other granularity, including a thread local one if
they wish to do so.
To use such error reporting you can use virSaveLastError(), which
retrieves the proper error object and then pass it via your own
structures with known lifetimes and without the possibly surprising
resetting of the error.
Using the global error handler function is not a very good idea in
multithreaded applications, so I'd really suggest to have a generic
handler function that you'll call after receiving a failure code from
any of the libvirt APIs you care about and that will preserve/raise the
error in your application.
Additionally for handling disconnects libvirt provides a connection
close callback registrable via virConnectRegisterCloseCallback(), which
can be registered multiple times with private data for each instance.
That might help you getting rid of the generic error handler's duty to
catch disconnects.
I understand that the error reporting situation is not ideal but I'm
still very sceptical that having the ability to reset the error would
help much.
Or do you have a suggestion I'm missing that is more elegant than
this?
I think it's pretty illustrative that the library itself uses these calls
everywhere.
[1] There is one use in virsh and one use in virt-admin code, which I'll
be addressing.