mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-27 08:05:24 +00:00
64 lines
2.5 KiB
Plaintext
64 lines
2.5 KiB
Plaintext
|
|
||
|
Threading: the RULES.
|
||
|
====================
|
||
|
|
||
|
If you don't understand this, don't touch the code. Ask for
|
||
|
further advice / explanation on the mailing list first.
|
||
|
|
||
|
- the top level lock is on 'struct qemud_server'. This must be
|
||
|
held before acquiring any other lock
|
||
|
|
||
|
- Each 'struct qemud_client' object has a lock. The server lock
|
||
|
must be held before acquiring it. Once the client lock is acquired
|
||
|
the server lock can (optionally) be dropped.
|
||
|
|
||
|
- The event loop has its own self-contained lock. You can ignore
|
||
|
this as a caller of virEvent APIs.
|
||
|
|
||
|
|
||
|
The server lock is only needed / used once the daemon has entered
|
||
|
its main loop, which is the qemudRunLoop() . The initial thread
|
||
|
acquires the lock upon entering this method.
|
||
|
|
||
|
It immediatelty spawns 'n' worker threads, whose main loop is
|
||
|
the qemudWorker() method. The workers will immediately try to
|
||
|
acquire the server lock, and thus block since its held by the
|
||
|
initial thread.
|
||
|
|
||
|
When the initial thread enters the poll() call, it drops the
|
||
|
server lock. The worker locks now each wakeup, acquire the
|
||
|
server lock and go into a condition wait on the 'job' condition
|
||
|
variable. The workers are now all 'primed' for incoming RPC
|
||
|
calls.
|
||
|
|
||
|
|
||
|
|
||
|
A file descriptor event now occurrs, causing the initial thread
|
||
|
to exit poll(). It invokes the registered callback associated
|
||
|
with the file descriptors on which the event occurrs. The callbacks
|
||
|
are required to immediately acquire the server lock.
|
||
|
|
||
|
If the callback is dealing with a client event, it will then
|
||
|
acquire the client lock, and drop the server lock.
|
||
|
|
||
|
The callback will now handle the I/O event, reading or writing
|
||
|
a RPC message. Once a complete RPC message has been read the
|
||
|
client is marked as being in state QEMUD_MODE_WAIT_DISPATCH,
|
||
|
and the 'job' condition variable is signaled. The callback
|
||
|
now drops the client lock and goes back into the poll() loop
|
||
|
waiting for more I/O events.
|
||
|
|
||
|
Meanwhile one of the worker threads wakes up from its condition
|
||
|
variable sleep, holding the server lock. It now searches for a
|
||
|
client in state QEMUD_MODE_WAIT_DISPATCH. If it doesn't find
|
||
|
one, it goes back to sleep. If it does find one, then it calls
|
||
|
into the remoteDispatchClientRequest() method de-serialize the
|
||
|
incoming message into an XDR object and invoke the helper method
|
||
|
for the associated RPC call.
|
||
|
|
||
|
While the helper method is executing, no locks are held on either
|
||
|
the client or server, but the ref count on the 'struct qemud_client'
|
||
|
object is incremented to ensure its not deleted. The helper can
|
||
|
now safely invoke the neccessary libvirt API call.
|
||
|
|