On Thu, Dec 17, 2009 at 10:24:15AM +0100, Daniel Veillard wrote:
On Wed, Dec 16, 2009 at 06:46:52PM +0000, Daniel P. Berrange wrote:
> GNUTLS uses gcrypt for its crypto functions. gcrypt requires
> that the app/library initializes threading before using it.
> We don't want to force apps using libvirt to know about
> gcrypt, so we make virInitialize init threading on their
> behalf. This location also ensures libvirtd has initialized
> it correctly. This initialization is required even if libvirt
> itself were only using one thread, since another non-libvirt
> library (eg GTK-VNC) could also be using gcrypt from another
> thread
>
> * src/libvirt.c: Register thread functions for gcrypt
> * configure.in: Add -lgcrypt to linker flags
> ---
> build-aux/.gitignore | 2 +
> configure.in | 4 ++-
> src/libvirt.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 58 insertions(+), 1 deletions(-)
>
> diff --git a/build-aux/.gitignore b/build-aux/.gitignore
> index 72e8ffc..a1b5d3b 100644
> --- a/build-aux/.gitignore
> +++ b/build-aux/.gitignore
> @@ -1 +1,3 @@
> *
> +/link-warning.h
> +/mktempd
> diff --git a/configure.in b/configure.in
> index 6ed2efd..c86ee97 100644
> --- a/configure.in
> +++ b/configure.in
> @@ -547,7 +547,9 @@ if test "$GNUTLS_FOUND" = "no"; then
> test $fail = 1 &&
> AC_MSG_ERROR([You must install the GnuTLS library in order to compile and run
libvirt])
>
> - GNUTLS_LIBS=$LIBS
> + dnl Not all versions of gnutls include -lgcrypt, and so we add
> + dnl it explicitly for the calls to gcry_control/check_version
> + GNUTLS_LIBS="$LIBS -lgcrypt"
> LIBS="$old_libs"
> fi
>
> diff --git a/src/libvirt.c b/src/libvirt.c
> index 103b331..cad33c2 100644
> --- a/src/libvirt.c
> +++ b/src/libvirt.c
> @@ -22,6 +22,7 @@
> #include <sys/wait.h>
> #endif
> #include <time.h>
> +#include <gcrypt.h>
>
> #include <libxml/parser.h>
> #include <libxml/xpath.h>
> @@ -251,6 +252,55 @@ winsock_init (void)
> }
> #endif
>
> +static int virTLSMutexInit (void **priv)
> +{ \
> + virMutexPtr lock = NULL;
> +
> + if (VIR_ALLOC(lock) < 0)
> + return ENOMEM;
> +
> + if (virMutexInit(lock) < 0) {
> + VIR_FREE(lock);
> + return errno;
> + }
> +
> + *priv = lock;
> + return 0;
> +}
> +
> +static int virTLSMutexDestroy(void **priv)
> +{
> + virMutexPtr lock = *priv;
> + virMutexDestroy(lock);
> + VIR_FREE(lock);
> + return 0;
> +}
> +
> +static int virTLSMutexLock(void **priv)
> +{
> + virMutexPtr lock = *priv;
> + virMutexLock(lock);
> + return 0;
> +}
> +
> +static int virTLSMutexUnlock(void **priv)
> +{
> + virMutexPtr lock = *priv;
> + virMutexUnlock(lock);
> + return 0;
> +}
> +
> +static struct gcry_thread_cbs virTLSThreadImpl = {
> + (GCRY_THREAD_OPTION_PTHREAD | (GCRY_THREAD_OPTION_VERSION << 8)),
> + NULL,
> + virTLSMutexInit,
> + virTLSMutexDestroy,
> + virTLSMutexLock,
> + virTLSMutexUnlock,
> + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
> +};
> +
> +
> /**
> * virInitialize:
> *
> @@ -273,6 +323,9 @@ virInitialize(void)
> virRandomInitialize(time(NULL) ^ getpid()))
> return -1;
>
> + gcry_control(GCRYCTL_SET_THREAD_CBS, &virTLSThreadImpl);
> + gcry_check_version(NULL);
> +
> virLogSetFromEnv();
>
> DEBUG0("register drivers");
Ah, subtle, I wonder how you realized that though :-)
If you don't have any thread callbacks set, libgcrypt has some assert()
code which attempts to detect if you use it from multiple threads. It is
inherantly racey, but their assert code will abort() your app a reasonable
amount of the time. We started seeing aborts of virt-manager in F12 since
it more heavily uses multiple threads, particularly because GTK-VNC also
uses thread and lots of libvirt & GTK-VNC stuff happends in separate
threads.
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|