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