[Libguestfs] [PATCH v3 3/5] threads: Use thread-local storage for errors.
Daniel P. Berrange
berrange at redhat.com
Tue Jul 11 10:47:34 UTC 2017
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 at 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 :|
More information about the Libguestfs
mailing list