On Mon, Jul 10, 2017 at 01:48:13PM +0200, Pino Toscano wrote:
On Tuesday, 27 June 2017 13:55:57 CEST Richard W.M. Jones wrote:
> We permit the following constructs in libguestfs code:
>
> if (guestfs_some_call (g) == -1) {
> fprintf (stderr, "failed: error is %s\n", guestfs_last_error (g));
> }
>
> and:
>
> guestfs_push_error_handler (g, NULL, NULL);
> guestfs_some_call (g);
> guestfs_pop_error_handler (g);
>
> Neither of these would be safe if we allowed the handle to be used
> from threads concurrently, since the error string or error handler
> could be changed by another thread.
>
> Solve this in approximately the same way that libvirt does: by making
> the error, current error handler, and stack of error handlers use
> thread-local storage (TLS).
>
> The implementation is not entirely straightforward, mainly because
> POSIX doesn't give us useful destructor behaviour, so effectively we
> end up creating our own destructor using a linked list.
I'm not sure which behaviour you are referring to, but it should work
just fine -- in the destructor function, cast the void* argument to the
error_data struct, and free the linked list associated.
The only problem is that the tls gnulib implementation on Windows
(actually, on mingw) makes no use for the destructor function, but
a) we don't have a working Windows port ATM (not even on other
non-Linux Unices)
b) using pthread or pth on mingw would solve this
For libvirt we decided to exclusively support pthread (thus requiring use
of the mingw winpthreads package for Win32.
I'd just use the destructor function approach, so there is less
complexity involved, and the per-thread resources are properly free'd
on thread exit (and not piling up until the handle destruction).
There is one critical gotcha with destructors and libraries - if your
library can be loaded via 'dlopen' (eg because its imported from a
language binding) you must guarantee that is resident in memory
*forever*. If you don't do this, then something can dlclose() you,
unloading the code that contains the destructor. You'll then crash
when a thread exits trying to invoke the destructor that is no longer
resident.
The workaround for this is to link the library with '-z nodelete',
which prevents you ever being unloaded from memory, even after a
dlclose(). We did this in libvirt in
commit 8e44e5593eb9b89fbc0b54fde15f130707a0d81e
Author: Daniel P. Berrange <berrange(a)redhat.com>
Date: Thu Sep 1 17:57:06 2011 +0100
Prevent crash from dlclose() of libvirt.so
Regards,
Daniel
--
|:
https://berrange.com -o-
https://www.flickr.com/photos/dberrange :|
|:
https://libvirt.org -o-
https://fstop138.berrange.com :|
|:
https://entangle-photo.org -o-
https://www.instagram.com/dberrange :|