This document describes how thread safety is ensured throughout
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
- Must be safe against dispatch asynchronous events from monitor
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
- *WILL* occurr.
+ *WILL* occur.
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().
- 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
reference count prevents it being freed by another thread.
* qemuMonitorPrivatePtr: Job condition
- Since virDomainObjPtr lock must not be held during sleeps, the job condition
- provides additional protection for code making updates.
+ Since virDomainObjPtr lock must not be held during sleeps, the job
+ condition provides additional protection for code making updates.
- Immediately after acquiring the virDomainObjPtr lock, any method which intends
- to update state, must acquire the job condition. The virDomainObjPtr lock
- is released while blocking on this condition variable. Once the job condition
- is acquired a method can safely release the virDomainObjPtr lock whenever it
- hits a piece of code which may sleep/wait, and re-acquire it after the sleep/
- wait.
+ Immediately after acquiring the virDomainObjPtr lock, any method
+ which intends to update state must acquire the job condition. The
+ virDomainObjPtr lock is released while blocking on this condition
+ variable. Once the job condition is acquired, a method can safely
+ release the virDomainObjPtr lock whenever it hits a piece of code
+ 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
qemuDomainObjBeginJob() (if driver is unlocked)
- 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
qemuDomainObjBeginJobWithDriver() (if driver needs to be locked)
- Unlocks driver
- 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
- Unlocks virDomainObjPtr
- Locks driver
- Releases the virDomainObjPtr lock
qemuDomainObjExitMonitor()
- - Acquires the virDomainObjPtr 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
- Releases the driver lock
qemuDomainObjExitMonitorWithDriver()
+ - Releases the qemuMonitorObjPtr lock
- Acquires the driver 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
...do prep work...
- qemuDomainObjEnterMonitor(obj);
- qemuMonitorXXXX(priv->mon);
- qemuDomainObjExitMonitor(obj);
+ if (virDomainObjIsActive(vm)) {
+ qemuDomainObjEnterMonitor(obj);
+ qemuMonitorXXXX(priv->mon);
+ qemuDomainObjExitMonitor(obj);
+ }
...do final work...
...do prep work...
- qemuDomainObjEnterMonitorWithDriver(driver, obj);
- qemuMonitorXXXX(priv->mon);
- qemuDomainObjExitMonitorWithDriver(driver, obj);
+ if (virDomainObjIsActive(vm)) {
+ qemuDomainObjEnterMonitorWithDriver(driver, obj);
+ qemuMonitorXXXX(priv->mon);
+ qemuDomainObjExitMonitorWithDriver(driver, obj);
+ }
...do final work...
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
-------