[libvirt] PATCH: 4/28: Thread safety for test driver

Daniel P. Berrange berrange at redhat.com
Mon Dec 1 17:44:14 UTC 2008


On Mon, Dec 01, 2008 at 06:26:03PM +0100, Daniel Veillard wrote:
> On Sun, Nov 30, 2008 at 11:27:14PM +0000, Daniel P. Berrange wrote:
> > This patch makes the test driver thread safe, adding a global driver lock,
> > and the neccessary locking calls on domain/network/storagepool objects.
> > 
> > You'll notice there are many calls to
> > 
> >  virDomainObjUnlock
> > 
> > but very few corresponding  calls to
> > 
> >    virDomainObjLock
> > 
> > This is because the contract of  virDomainFindByUUID declares that the
> > object it returns is already locked.
> > 
> > Methods which create / delete virDomainObj instances have to keep the
> > global driver lock held for their whole duration, but others can drop
> > it immediately after getting the virDomainObjPtr instance.
> 
>   Okay, what about virDomainFindByID and virDomainFindByName ? They lock
>   too or we are just avoiding them ?

All the virXXXXFindByYYY methods return a locked object. I'll be
documenting writing a doc about the threading rules for the internal
code to explain this more clearlyl....

> 
> > +++ b/src/test.c
> > @@ -58,6 +58,8 @@ typedef struct _testCell *testCellPtr;
> >  #define MAX_CELLS 128
> >  
> >  struct _testConn {
> > +    PTHREAD_MUTEX_T(lock);
> > +
> 
>   hum, 
> [...]
> > +
> > +static void testDriverLock(testConnPtr driver)
> > +{
> > +    pthread_mutex_lock(&driver->lock);
> > +}
> > +
> > +static void testDriverUnlock(testConnPtr driver)
> > +{
> > +    pthread_mutex_unlock(&driver->lock);
> > +}
> >
> >  static virCapsPtr
> >  testBuildCapabilities(virConnectPtr conn) {
> > @@ -200,6 +212,8 @@ static int testOpenDefault(virConnectPtr
> >          return VIR_DRV_OPEN_ERROR;
> >      }
> >      conn->privateData = privconn;
> > +    pthread_mutex_init(&privconn->lock, NULL);
> 
>   Can we abstract the mutex types and ops a little ? if libvirt were
> to be ported to a platform/compiler where pthreads are not available
> they would be able to fallback to xmlMutexPtr from libvirt which is
> ported to all platforms where libxml2 is usable (as far as I know).

The internal.h header already arranges for all this to compile
away to nothing if pthread.h is not present, so there's no need
for any wrappers. xmlMutexPtr is not sufficient, because other
in the code also use condition variables for which there are no
wrappers in libxml. That said, all modern UNIX, Linux, OS-X
and Windows have pthread libraries available, so I don't think
there's any important platform where we'll need to disable this.

> 
> > +    testDriverLock(privconn);
> >  
> >      if (gettimeofday(&tv, NULL) < 0) {
> >          testError(NULL, VIR_ERR_INTERNAL_ERROR, "%s", _("getting time of day"));
> > @@ -232,6 +246,7 @@ static int testOpenDefault(virConnectPtr
> >      domobj->def->id = privconn->nextDomID++;
> >      domobj->state = VIR_DOMAIN_RUNNING;
> >      domobj->persistent = 1;
> > +    virDomainObjUnlock(domobj);
> 
>   the locking path is unclear here testOpenDefault uses
>   virDomainAssignDef which then relies on virDomainFindByName() which
>   would lock the domain object, right ?

Yes, the virXXXXAssignDef method is declared to return a locked object.

> 
> [...]
> > @@ -797,10 +859,14 @@ static int testDestroyDomain (virDomainP
> >      if (!privdom->persistent) {
> >          virDomainRemoveInactive(&privconn->domains,
> >                                  privdom);
> 
>   will virDomainRemoveInactive also  remove the lock before destroying
>   the object ? the answer is surely in a later patch

You are required to hold both the driver lock, and the privdom
lock when calling this. It will unlock the domain object and
then free it. It may seemm redudant for the caller to lock the
privdom, and then have virDomainRemoveInactive immediately
unlock it again, but this ensures no other thread still has an
active lock on the object & cannot re-acquire one since we hold
the global driver lock.

> > @@ -884,9 +959,17 @@ static int testShutdownDomain (virDomain
> >      privdom->state = VIR_DOMAIN_SHUTOFF;
> >      domain->id = -1;
> >      privdom->def->id = -1;
> > +    if (!privdom->persistent) {
> > +        virDomainRemoveInactive(&privconn->domains,
> > +                                privdom);
> > +        privdom = NULL;
> > +    }
> >      ret = 0;
> 
>   hum, not specific to threading, we are improving the driver here.

Yes, i noticed that bug while fixing this.

> > diff --git a/tests/virsh-all b/tests/virsh-all
> > --- a/tests/virsh-all
> > +++ b/tests/virsh-all
> > @@ -22,6 +22,7 @@ fi
> >  fi
> >  
> >  test -z "$srcdir" && srcdir=$(pwd)
> > +test -z "$abs_top_srcdir" && abs_top_srcdir=$(pwd)/..
> >  . "$srcdir/test-lib.sh"
> 
>   ???

It allows you to rnu the test by just doing

   ./virsh-all

Rather than tedious

    make check TESTS=virsh-all


> I hope it's worth the effort, it's a lot of complexity added.
> One of the things which worries me is that detecting errors will be
> hard, you end up with a locked server that can be far from trivial
> to debug.
> I'm really wondering how we could automate testing or at least ease the
> debug,

It occurred to me that a static analysis tool like CIL really ought to
be able to check correctness fairly easily. Rich has discussed this a
little before

  http://et.redhat.com/~rjones/cil-analysis-of-libvirt/

Basically since we have a known set of functions which lock the object
and CIL can give us the code flow within a method, we ought to be able
to write something that looks at each call of virDomainFindByUUID,
and then traces the code paths to functiuon return, and validates that
the unlock call was made. It could likewise check for people calling
things before acquiring the lock.

Would be an interesting project..... :-)

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 :|




More information about the libvir-list mailing list