mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-23 03:42:19 +00:00
docs: more on qemu locking patterns
* src/qemu/THREADS.txt: Improve documentation.
This commit is contained in:
parent
0b864eb103
commit
0fa17ff52a
@ -4,7 +4,7 @@
|
|||||||
This document describes how thread safety is ensured throughout
|
This document describes how thread safety is ensured throughout
|
||||||
the QEMU driver. The criteria for this model are:
|
the QEMU driver. The criteria for this model are:
|
||||||
|
|
||||||
- Objects must never be exclusively locked for any pro-longed time
|
- Objects must never be exclusively locked for any prolonged time
|
||||||
- Code which sleeps must be able to time out after suitable period
|
- Code which sleeps must be able to time out after suitable period
|
||||||
- Must be safe against dispatch asynchronous events from monitor
|
- Must be safe against dispatch asynchronous events from monitor
|
||||||
|
|
||||||
@ -36,11 +36,11 @@ There are a number of locks on various objects
|
|||||||
|
|
||||||
Once the lock is held, you must *NOT* try to lock the driver. You must
|
Once the lock is held, you must *NOT* try to lock the driver. You must
|
||||||
release all virDomainObjPtr locks before locking the driver, or deadlock
|
release all virDomainObjPtr locks before locking the driver, or deadlock
|
||||||
*WILL* occurr.
|
*WILL* occur.
|
||||||
|
|
||||||
If the lock needs to be dropped & then re-acquired for a short period of
|
If the lock needs to be dropped & then re-acquired for a short period of
|
||||||
time, the reference count must be incremented first using virDomainObjRef().
|
time, the reference count must be incremented first using virDomainObjRef().
|
||||||
If the reference count is incremented in this way, it is not neccessary
|
If the reference count is incremented in this way, it is not necessary
|
||||||
to have the driver locked when re-acquiring the dropped locked, since the
|
to have the driver locked when re-acquiring the dropped locked, since the
|
||||||
reference count prevents it being freed by another thread.
|
reference count prevents it being freed by another thread.
|
||||||
|
|
||||||
@ -51,15 +51,20 @@ There are a number of locks on various objects
|
|||||||
|
|
||||||
* qemuMonitorPrivatePtr: Job condition
|
* qemuMonitorPrivatePtr: Job condition
|
||||||
|
|
||||||
Since virDomainObjPtr lock must not be held during sleeps, the job condition
|
Since virDomainObjPtr lock must not be held during sleeps, the job
|
||||||
provides additional protection for code making updates.
|
condition provides additional protection for code making updates.
|
||||||
|
|
||||||
Immediately after acquiring the virDomainObjPtr lock, any method which intends
|
Immediately after acquiring the virDomainObjPtr lock, any method
|
||||||
to update state, must acquire the job condition. The virDomainObjPtr lock
|
which intends to update state must acquire the job condition. The
|
||||||
is released while blocking on this condition variable. Once the job condition
|
virDomainObjPtr lock is released while blocking on this condition
|
||||||
is acquired a method can safely release the virDomainObjPtr lock whenever it
|
variable. Once the job condition is acquired, a method can safely
|
||||||
hits a piece of code which may sleep/wait, and re-acquire it after the sleep/
|
release the virDomainObjPtr lock whenever it hits a piece of code
|
||||||
wait.
|
which may sleep/wait, and re-acquire it after the sleep/wait.
|
||||||
|
|
||||||
|
Since the virDomainObjPtr lock was dropped while waiting for the
|
||||||
|
job condition, it is possible that the domain is no longer active
|
||||||
|
when the condition is finally obtained. The monitor lock is only
|
||||||
|
safe to grab after verifying that the domain is still active.
|
||||||
|
|
||||||
|
|
||||||
* qemuMonitorPtr: Mutex
|
* qemuMonitorPtr: Mutex
|
||||||
@ -110,13 +115,15 @@ To acquire the job mutex
|
|||||||
|
|
||||||
qemuDomainObjBeginJob() (if driver is unlocked)
|
qemuDomainObjBeginJob() (if driver is unlocked)
|
||||||
- Increments ref count on virDomainObjPtr
|
- Increments ref count on virDomainObjPtr
|
||||||
- Wait qemuDomainObjPrivate condition 'jobActive != 0' using virDomainObjPtr mutex
|
- Wait qemuDomainObjPrivate condition 'jobActive != 0' using
|
||||||
|
virDomainObjPtr mutex
|
||||||
- Sets jobActive to 1
|
- Sets jobActive to 1
|
||||||
|
|
||||||
qemuDomainObjBeginJobWithDriver() (if driver needs to be locked)
|
qemuDomainObjBeginJobWithDriver() (if driver needs to be locked)
|
||||||
- Unlocks driver
|
- Unlocks driver
|
||||||
- Increments ref count on virDomainObjPtr
|
- Increments ref count on virDomainObjPtr
|
||||||
- Wait qemuDomainObjPrivate condition 'jobActive != 0' using virDomainObjPtr mutex
|
- Wait qemuDomainObjPrivate condition 'jobActive != 0' using
|
||||||
|
virDomainObjPtr mutex
|
||||||
- Sets jobActive to 1
|
- Sets jobActive to 1
|
||||||
- Unlocks virDomainObjPtr
|
- Unlocks virDomainObjPtr
|
||||||
- Locks driver
|
- Locks driver
|
||||||
@ -140,10 +147,10 @@ To acquire the QEMU monitor lock
|
|||||||
- Releases the virDomainObjPtr lock
|
- Releases the virDomainObjPtr lock
|
||||||
|
|
||||||
qemuDomainObjExitMonitor()
|
qemuDomainObjExitMonitor()
|
||||||
- Acquires the virDomainObjPtr lock
|
|
||||||
- Releases the qemuMonitorObjPtr lock
|
- Releases the qemuMonitorObjPtr lock
|
||||||
|
- Acquires the virDomainObjPtr lock
|
||||||
|
|
||||||
NB: caller must take care to drop the driver lock if neccessary
|
NB: caller must take care to drop the driver lock if necessary
|
||||||
|
|
||||||
|
|
||||||
To acquire the QEMU monitor lock with the driver lock held
|
To acquire the QEMU monitor lock with the driver lock held
|
||||||
@ -154,11 +161,25 @@ To acquire the QEMU monitor lock with the driver lock held
|
|||||||
- Releases the driver lock
|
- Releases the driver lock
|
||||||
|
|
||||||
qemuDomainObjExitMonitorWithDriver()
|
qemuDomainObjExitMonitorWithDriver()
|
||||||
|
- Releases the qemuMonitorObjPtr lock
|
||||||
- Acquires the driver lock
|
- Acquires the driver lock
|
||||||
- Acquires the virDomainObjPtr lock
|
- Acquires the virDomainObjPtr lock
|
||||||
- Releases the qemuMonitorObjPtr lock
|
|
||||||
|
|
||||||
NB: caller must take care to drop the driver lock if neccessary
|
NB: caller must take care to drop the driver lock if necessary
|
||||||
|
|
||||||
|
|
||||||
|
To keep a domain alive while waiting on a remote command, starting
|
||||||
|
with the driver lock held
|
||||||
|
|
||||||
|
qemuDomainObjEnterRemoterWithDriver()
|
||||||
|
- Increments ref count on virDomainObjPtr
|
||||||
|
- Releases the virDomainObjPtr lock
|
||||||
|
- Releases the driver lock
|
||||||
|
|
||||||
|
qemuDomainObjExitRemoteWithDriver()
|
||||||
|
- Acquires the driver lock
|
||||||
|
- Acquires the virDomainObjPtr lock
|
||||||
|
- Decrements ref count on virDomainObjPtr
|
||||||
|
|
||||||
|
|
||||||
Design patterns
|
Design patterns
|
||||||
@ -236,9 +257,11 @@ Design patterns
|
|||||||
|
|
||||||
...do prep work...
|
...do prep work...
|
||||||
|
|
||||||
|
if (virDomainObjIsActive(vm)) {
|
||||||
qemuDomainObjEnterMonitor(obj);
|
qemuDomainObjEnterMonitor(obj);
|
||||||
qemuMonitorXXXX(priv->mon);
|
qemuMonitorXXXX(priv->mon);
|
||||||
qemuDomainObjExitMonitor(obj);
|
qemuDomainObjExitMonitor(obj);
|
||||||
|
}
|
||||||
|
|
||||||
...do final work...
|
...do final work...
|
||||||
|
|
||||||
@ -261,9 +284,11 @@ Design patterns
|
|||||||
|
|
||||||
...do prep work...
|
...do prep work...
|
||||||
|
|
||||||
|
if (virDomainObjIsActive(vm)) {
|
||||||
qemuDomainObjEnterMonitorWithDriver(driver, obj);
|
qemuDomainObjEnterMonitorWithDriver(driver, obj);
|
||||||
qemuMonitorXXXX(priv->mon);
|
qemuMonitorXXXX(priv->mon);
|
||||||
qemuDomainObjExitMonitorWithDriver(driver, obj);
|
qemuDomainObjExitMonitorWithDriver(driver, obj);
|
||||||
|
}
|
||||||
|
|
||||||
...do final work...
|
...do final work...
|
||||||
|
|
||||||
@ -272,6 +297,35 @@ Design patterns
|
|||||||
qemuDriverUnlock(driver);
|
qemuDriverUnlock(driver);
|
||||||
|
|
||||||
|
|
||||||
|
* Coordinating with a remote server for migraion
|
||||||
|
|
||||||
|
virDomainObjPtr obj;
|
||||||
|
qemuDomainObjPrivatePtr priv;
|
||||||
|
|
||||||
|
qemuDriverLock(driver);
|
||||||
|
obj = virDomainFindByUUID(driver->domains, dom->uuid);
|
||||||
|
|
||||||
|
qemuDomainObjBeginJobWithDriver(obj);
|
||||||
|
|
||||||
|
...do prep work...
|
||||||
|
|
||||||
|
if (virDomainObjIsActive(vm)) {
|
||||||
|
qemuDomainObjEnterRemoteWithDriver(driver, obj);
|
||||||
|
...communicate with remote...
|
||||||
|
qemuDomainObjExitRemoteWithDriver(driver, obj);
|
||||||
|
/* domain may have been stopped while we were talking to remote */
|
||||||
|
if (!virDomainObjIsActive(vm)) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("guest unexpectedly quit"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
...do final work...
|
||||||
|
|
||||||
|
qemuDomainObjEndJob(obj);
|
||||||
|
virDomainObjUnlock(obj);
|
||||||
|
qemuDriverUnlock(driver);
|
||||||
|
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
-------
|
-------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user