[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v4] daemon: Create priority workers pool



This patch annotates APIs with low or high priority.
In low set MUST be all APIs which might eventually access monitor
(and thus block indefinitely). Other APIs may be marked as high
priority. However, some must be (e.g. domainDestroy).

For high priority calls (HPC), there are some high priority workers
(HPW) created in the pool. HPW can execute only HPC, although normal
worker can process any call regardless priority. Therefore, only those
APIs which are guaranteed to end in reasonable small amount of time
can be marked as HPC.

The size of this HPC pool is static, because HPC are expected to end
quickly, therefore jobs assigned to this pool will be served quickly.
It can be configured in libvirtd.conf via prio_workers variable.
Default is set to 5.

To mark API with low or high priority, append priority:{low|high} to
it's comment in src/remote/remote_protocol.x. This is similar to
autogen|skipgen. If not marked, the generator assumes low as default.
---
diff to v3:
-make 'priority:low' as default which can be left out
-rearrange some APIs to be HPC or LPC

 daemon/libvirtd.aug           |    1 +
 daemon/libvirtd.c             |    7 +
 daemon/libvirtd.conf          |    6 +
 src/qemu/qemu_driver.c        |    2 +-
 src/qemu/qemu_process.c       |    2 +-
 src/remote/qemu_protocol.x    |   13 ++-
 src/remote/remote_protocol.x  |  294 +++++++++++++++++++++--------------------
 src/rpc/gendispatch.pl        |   20 +++-
 src/rpc/virnetserver.c        |   60 +++++----
 src/rpc/virnetserver.h        |    1 +
 src/rpc/virnetserverprogram.c |   11 ++
 src/rpc/virnetserverprogram.h |    4 +
 src/util/threadpool.c         |  158 +++++++++++++++++++----
 src/util/threadpool.h         |    4 +-
 14 files changed, 382 insertions(+), 201 deletions(-)

diff --git a/daemon/libvirtd.aug b/daemon/libvirtd.aug
index 3f47ebb..ce00db5 100644
--- a/daemon/libvirtd.aug
+++ b/daemon/libvirtd.aug
@@ -57,6 +57,7 @@ module Libvirtd =
                         | int_entry "max_clients"
                         | int_entry "max_requests"
                         | int_entry "max_client_requests"
+                        | int_entry "prio_workers"
 
    let logging_entry = int_entry "log_level"
                      | str_entry "log_filters"
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 423c3d7..7b445a2 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -134,6 +134,8 @@ struct daemonConfig {
     int max_workers;
     int max_clients;
 
+    int prio_workers;
+
     int max_requests;
     int max_client_requests;
 
@@ -886,6 +888,8 @@ daemonConfigNew(bool privileged ATTRIBUTE_UNUSED)
     data->max_workers = 20;
     data->max_clients = 20;
 
+    data->prio_workers = 5;
+
     data->max_requests = 20;
     data->max_client_requests = 5;
 
@@ -1042,6 +1046,8 @@ daemonConfigLoad(struct daemonConfig *data,
     GET_CONF_INT (conf, filename, max_workers);
     GET_CONF_INT (conf, filename, max_clients);
 
+    GET_CONF_INT (conf, filename, prio_workers);
+
     GET_CONF_INT (conf, filename, max_requests);
     GET_CONF_INT (conf, filename, max_client_requests);
 
@@ -1430,6 +1436,7 @@ int main(int argc, char **argv) {
             config->auth_unix_ro == REMOTE_AUTH_POLKIT;
     if (!(srv = virNetServerNew(config->min_workers,
                                 config->max_workers,
+                                config->prio_workers,
                                 config->max_clients,
                                 config->mdns_adv ? config->mdns_name : NULL,
                                 use_polkit_dbus,
diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf
index 95e43dd..da3983e 100644
--- a/daemon/libvirtd.conf
+++ b/daemon/libvirtd.conf
@@ -257,6 +257,12 @@
 #min_workers = 5
 #max_workers = 20
 
+
+# The number of priority workers. If all workers from above
+# pool will stuck, some calls marked as high priority
+# (notably domainDestroy) can be executed in this pool.
+#prio_workers = 5
+
 # Total global limit on concurrent RPC calls. Should be
 # at least as large as max_workers. Beyond this, RPC requests
 # will be read into memory and queued. This directly impact
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f21122d..b26a0cb 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -656,7 +656,7 @@ qemudStartup(int privileged) {
     virHashForEach(qemu_driver->domains.objs, qemuDomainSnapshotLoad,
                    qemu_driver->snapshotDir);
 
-    qemu_driver->workerPool = virThreadPoolNew(0, 1, processWatchdogEvent, qemu_driver);
+    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, processWatchdogEvent, qemu_driver);
     if (!qemu_driver->workerPool)
         goto error;
 
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 58b4d36..878805a 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -576,7 +576,7 @@ qemuProcessHandleWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
              * deleted before handling watchdog event is finished.
              */
             virDomainObjRef(vm);
-            if (virThreadPoolSendJob(driver->workerPool, wdEvent) < 0) {
+            if (virThreadPoolSendJob(driver->workerPool, 0, wdEvent) < 0) {
                 if (virDomainObjUnref(vm) == 0)
                     vm = NULL;
                 VIR_FREE(wdEvent);
diff --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x
index 3279405..39f9adf 100644
--- a/src/remote/qemu_protocol.x
+++ b/src/remote/qemu_protocol.x
@@ -52,9 +52,14 @@ const QEMU_PROGRAM = 0x20008087;
 const QEMU_PROTOCOL_VERSION = 1;
 
 enum qemu_procedure {
-    /* Each function must have a two-word comment.  The first word is
+    /* Each function must have a three-word comment.  The first word is
      * whether gendispatch.pl handles daemon, the second whether
-     * it handles src/remote.  */
-    QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen */
-    QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen */
+     * it handles src/remote.
+     * The last argument describes priority of API. There are two accepted
+     * values: low, high; Each API that might eventually access hypervisor's
+     * monitor (and thus block) MUST fall into low priority. However, there
+     * are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
+     * be marked as high priority. If in doubt, it's safe to choose low. */
+    QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen priority:low */
+    QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen priority:low */
 };
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 8f68808..6ad83f3 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2201,189 +2201,195 @@ const REMOTE_PROGRAM = 0x20008086;
 const REMOTE_PROTOCOL_VERSION = 1;
 
 enum remote_procedure {
-    /* Each function must have a two-word comment.  The first word is
+    /* Each function must have a three-word comment.  The first word is
      * whether gendispatch.pl handles daemon, the second whether
      * it handles src/remote.  Additional flags can be specified after a
      * pipe.
+     * The last argument describes priority of API. There are two accepted
+     * values: low, high; Each API that might eventually access hypervisor's
+     * monitor (and thus block) MUST fall into low priority. However, there
+     * are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
+     * be marked as high priority. If in doubt, it's safe to choose low.
+     * Low is taken as default, and thus can be left out.
      *
      * The (readstream|writestream)@<offset> flag lets daemon and src/remote
      * create a stream.  The direction is defined from the src/remote point
      * of view.  A readstream transfers data from daemon to src/remote.  The
      * <offset> specifies at which offset the stream parameter is inserted
      * in the function parameter list. */
-    REMOTE_PROC_OPEN = 1, /* skipgen skipgen */
-    REMOTE_PROC_CLOSE = 2, /* skipgen skipgen */
-    REMOTE_PROC_GET_TYPE = 3, /* autogen skipgen */
-    REMOTE_PROC_GET_VERSION = 4, /* autogen autogen */
-    REMOTE_PROC_GET_MAX_VCPUS = 5, /* autogen autogen */
-    REMOTE_PROC_NODE_GET_INFO = 6, /* autogen autogen */
+    REMOTE_PROC_OPEN = 1, /* skipgen skipgen priority:high */
+    REMOTE_PROC_CLOSE = 2, /* skipgen skipgen priority:high */
+    REMOTE_PROC_GET_TYPE = 3, /* autogen skipgen priority:high */
+    REMOTE_PROC_GET_VERSION = 4, /* autogen autogen priority:high */
+    REMOTE_PROC_GET_MAX_VCPUS = 5, /* autogen autogen priority:high */
+    REMOTE_PROC_NODE_GET_INFO = 6, /* autogen autogen priority:high */
     REMOTE_PROC_GET_CAPABILITIES = 7, /* autogen autogen */
     REMOTE_PROC_DOMAIN_ATTACH_DEVICE = 8, /* autogen autogen */
     REMOTE_PROC_DOMAIN_CREATE = 9, /* autogen skipgen */
     REMOTE_PROC_DOMAIN_CREATE_XML = 10, /* autogen autogen */
 
-    REMOTE_PROC_DOMAIN_DEFINE_XML = 11, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_DESTROY = 12, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_DEFINE_XML = 11, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_DESTROY = 12, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_DETACH_DEVICE = 13, /* autogen autogen */
     REMOTE_PROC_DOMAIN_GET_XML_DESC = 14, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_AUTOSTART = 15, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_GET_AUTOSTART = 15, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_GET_INFO = 16, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_MAX_MEMORY = 17, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_MAX_VCPUS = 18, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_OS_TYPE = 19, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_VCPUS = 20, /* skipgen skipgen */
-
-    REMOTE_PROC_LIST_DEFINED_DOMAINS = 21, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_LOOKUP_BY_ID = 22, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_LOOKUP_BY_NAME = 23, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID = 24, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_DEFINED_DOMAINS = 25, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_GET_MAX_MEMORY = 17, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_GET_MAX_VCPUS = 18, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_GET_OS_TYPE = 19, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_GET_VCPUS = 20, /* skipgen skipgen priority:high */
+
+    REMOTE_PROC_LIST_DEFINED_DOMAINS = 21, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_LOOKUP_BY_ID = 22, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_LOOKUP_BY_NAME = 23, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID = 24, /* autogen autogen priority:high */
+    REMOTE_PROC_NUM_OF_DEFINED_DOMAINS = 25, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_PIN_VCPU = 26, /* autogen autogen */
     REMOTE_PROC_DOMAIN_REBOOT = 27, /* autogen autogen */
     REMOTE_PROC_DOMAIN_RESUME = 28, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SET_AUTOSTART = 29, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SET_MAX_MEMORY = 30, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_SET_AUTOSTART = 29, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SET_MAX_MEMORY = 30, /* autogen autogen priority:high */
 
     REMOTE_PROC_DOMAIN_SET_MEMORY = 31, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SET_VCPUS = 32, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SHUTDOWN = 33, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SUSPEND = 34, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_UNDEFINE = 35, /* autogen autogen */
-    REMOTE_PROC_LIST_DEFINED_NETWORKS = 36, /* autogen autogen */
-    REMOTE_PROC_LIST_DOMAINS = 37, /* autogen skipgen */
-    REMOTE_PROC_LIST_NETWORKS = 38, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_UNDEFINE = 35, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_DEFINED_NETWORKS = 36, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_DOMAINS = 37, /* autogen skipgen priority:high */
+    REMOTE_PROC_LIST_NETWORKS = 38, /* autogen autogen priority:high */
     REMOTE_PROC_NETWORK_CREATE = 39, /* autogen autogen */
     REMOTE_PROC_NETWORK_CREATE_XML = 40, /* autogen autogen */
 
-    REMOTE_PROC_NETWORK_DEFINE_XML = 41, /* autogen autogen */
-    REMOTE_PROC_NETWORK_DESTROY = 42, /* autogen autogen */
-    REMOTE_PROC_NETWORK_GET_XML_DESC = 43, /* autogen autogen */
-    REMOTE_PROC_NETWORK_GET_AUTOSTART = 44, /* autogen autogen */
-    REMOTE_PROC_NETWORK_GET_BRIDGE_NAME = 45, /* autogen autogen */
-    REMOTE_PROC_NETWORK_LOOKUP_BY_NAME = 46, /* autogen autogen */
-    REMOTE_PROC_NETWORK_LOOKUP_BY_UUID = 47, /* autogen autogen */
-    REMOTE_PROC_NETWORK_SET_AUTOSTART = 48, /* autogen autogen */
-    REMOTE_PROC_NETWORK_UNDEFINE = 49, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_DEFINED_NETWORKS = 50, /* autogen autogen */
-
-    REMOTE_PROC_NUM_OF_DOMAINS = 51, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_NETWORKS = 52, /* autogen autogen */
+    REMOTE_PROC_NETWORK_DEFINE_XML = 41, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_DESTROY = 42, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_GET_XML_DESC = 43, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_GET_AUTOSTART = 44, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_GET_BRIDGE_NAME = 45, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_LOOKUP_BY_NAME = 46, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_LOOKUP_BY_UUID = 47, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_SET_AUTOSTART = 48, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_UNDEFINE = 49, /* autogen autogen priority:high */
+    REMOTE_PROC_NUM_OF_DEFINED_NETWORKS = 50, /* autogen autogen priority:high */
+
+    REMOTE_PROC_NUM_OF_DOMAINS = 51, /* autogen autogen priority:high */
+    REMOTE_PROC_NUM_OF_NETWORKS = 52, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_CORE_DUMP = 53, /* autogen autogen */
     REMOTE_PROC_DOMAIN_RESTORE = 54, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SAVE = 55, /* autogen autogen */
     REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE = 56, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS = 57, /* skipgen autogen */
     REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS = 58, /* autogen autogen */
-    REMOTE_PROC_GET_HOSTNAME = 59, /* autogen autogen */
-    REMOTE_PROC_SUPPORTS_FEATURE = 60, /* autogen autogen */
+    REMOTE_PROC_GET_HOSTNAME = 59, /* autogen autogen priority:high */
+    REMOTE_PROC_SUPPORTS_FEATURE = 60, /* autogen autogen priority:high */
 
     REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62, /* autogen autogen */
     REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63, /* autogen autogen */
     REMOTE_PROC_DOMAIN_BLOCK_STATS = 64, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65, /* autogen autogen */
-    REMOTE_PROC_AUTH_LIST = 66, /* skipgen skipgen */
-    REMOTE_PROC_AUTH_SASL_INIT = 67, /* skipgen skipgen */
-    REMOTE_PROC_AUTH_SASL_START = 68, /* skipgen skipgen */
-    REMOTE_PROC_AUTH_SASL_STEP = 69, /* skipgen skipgen */
-    REMOTE_PROC_AUTH_POLKIT = 70, /* skipgen skipgen */
-
-    REMOTE_PROC_NUM_OF_STORAGE_POOLS = 71, /* autogen autogen */
-    REMOTE_PROC_LIST_STORAGE_POOLS = 72, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 73, /* autogen autogen */
-    REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 74, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_INTERFACE_STATS = 65, /* autogen autogen priority:high */
+    REMOTE_PROC_AUTH_LIST = 66, /* skipgen skipgen priority:high */
+    REMOTE_PROC_AUTH_SASL_INIT = 67, /* skipgen skipgen priority:high */
+    REMOTE_PROC_AUTH_SASL_START = 68, /* skipgen skipgen priority:high */
+    REMOTE_PROC_AUTH_SASL_STEP = 69, /* skipgen skipgen priority:high */
+    REMOTE_PROC_AUTH_POLKIT = 70, /* skipgen skipgen priority:high */
+
+    REMOTE_PROC_NUM_OF_STORAGE_POOLS = 71, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_STORAGE_POOLS = 72, /* autogen autogen priority:high */
+    REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 73, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 74, /* autogen autogen priority:high */
     REMOTE_PROC_FIND_STORAGE_POOL_SOURCES = 75, /* autogen skipgen */
     REMOTE_PROC_STORAGE_POOL_CREATE_XML = 76, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 77, /* autogen autogen */
+    REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 77, /* autogen autogen priority:high */
     REMOTE_PROC_STORAGE_POOL_CREATE = 78, /* autogen autogen */
     REMOTE_PROC_STORAGE_POOL_BUILD = 79, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_DESTROY = 80, /* autogen autogen */
+    REMOTE_PROC_STORAGE_POOL_DESTROY = 80, /* autogen autogen priority:high */
 
     REMOTE_PROC_STORAGE_POOL_DELETE = 81, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_UNDEFINE = 82, /* autogen autogen */
+    REMOTE_PROC_STORAGE_POOL_UNDEFINE = 82, /* autogen autogen priority:high */
     REMOTE_PROC_STORAGE_POOL_REFRESH = 83, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME = 84, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID = 85, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_VOLUME = 86, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_GET_INFO = 87, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_GET_XML_DESC = 88, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART = 89, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART = 90, /* autogen autogen */
-
-    REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES = 91, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES = 92, /* autogen autogen */
+    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME = 84, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID = 85, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_VOLUME = 86, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_GET_INFO = 87, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_GET_XML_DESC = 88, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART = 89, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART = 90, /* autogen autogen priority:high */
+
+    REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES = 91, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES = 92, /* autogen autogen priority:high */
     REMOTE_PROC_STORAGE_VOL_CREATE_XML = 93, /* autogen autogen */
     REMOTE_PROC_STORAGE_VOL_DELETE = 94, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME = 95, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_KEY = 96, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH = 97, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_GET_INFO = 98, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_GET_XML_DESC = 99, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_GET_PATH = 100, /* autogen autogen */
-
-    REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, /* autogen skipgen */
-    REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, /* autogen autogen */
+    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME = 95, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_KEY = 96, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH = 97, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_VOL_GET_INFO = 98, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_VOL_GET_XML_DESC = 99, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_VOL_GET_PATH = 100, /* autogen autogen priority:high */
+
+    REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, /* autogen skipgen priority:high */
+    REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, /* skipgen skipgen */
+    REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, /* skipgen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, /* skipgen skipgen priority:high */
     REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE = 107, /* autogen autogen */
     REMOTE_PROC_DOMAIN_MIGRATE_PREPARE2 = 108, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_MIGRATE_FINISH2 = 109, /* autogen autogen */
-    REMOTE_PROC_GET_URI = 110, /* autogen skipgen */
+    REMOTE_PROC_GET_URI = 110, /* autogen skipgen priority:high */
 
-    REMOTE_PROC_NODE_NUM_OF_DEVICES = 111, /* autogen autogen */
-    REMOTE_PROC_NODE_LIST_DEVICES = 112, /* autogen autogen */
-    REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME = 113, /* autogen autogen */
+    REMOTE_PROC_NODE_NUM_OF_DEVICES = 111, /* autogen autogen priority:high */
+    REMOTE_PROC_NODE_LIST_DEVICES = 112, /* autogen autogen priority:high */
+    REMOTE_PROC_NODE_DEVICE_LOOKUP_BY_NAME = 113, /* autogen autogen priority:high */
     REMOTE_PROC_NODE_DEVICE_GET_XML_DESC = 114, /* autogen autogen */
-    REMOTE_PROC_NODE_DEVICE_GET_PARENT = 115, /* skipgen autogen */
-    REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS = 116, /* autogen autogen */
-    REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 117, /* autogen autogen */
+    REMOTE_PROC_NODE_DEVICE_GET_PARENT = 115, /* skipgen autogen priority:high */
+    REMOTE_PROC_NODE_DEVICE_NUM_OF_CAPS = 116, /* autogen autogen priority:high */
+    REMOTE_PROC_NODE_DEVICE_LIST_CAPS = 117, /* autogen autogen priority:high */
     REMOTE_PROC_NODE_DEVICE_DETTACH = 118, /* autogen skipgen */
     REMOTE_PROC_NODE_DEVICE_RE_ATTACH = 119, /* autogen skipgen */
     REMOTE_PROC_NODE_DEVICE_RESET = 120, /* autogen skipgen */
 
-    REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL = 121, /* skipgen skipgen */
-    REMOTE_PROC_NODE_GET_SECURITY_MODEL = 122, /* skipgen skipgen */
+    REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL = 121, /* skipgen skipgen priority:high */
+    REMOTE_PROC_NODE_GET_SECURITY_MODEL = 122, /* skipgen skipgen priority:high */
     REMOTE_PROC_NODE_DEVICE_CREATE_XML = 123, /* autogen autogen */
-    REMOTE_PROC_NODE_DEVICE_DESTROY = 124, /* autogen autogen */
+    REMOTE_PROC_NODE_DEVICE_DESTROY = 124, /* autogen autogen priority:high */
     REMOTE_PROC_STORAGE_VOL_CREATE_XML_FROM = 125, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_INTERFACES = 126, /* autogen autogen */
-    REMOTE_PROC_LIST_INTERFACES = 127, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_LOOKUP_BY_NAME = 128, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_LOOKUP_BY_MAC_STRING = 129, /* autogen autogen */
+    REMOTE_PROC_NUM_OF_INTERFACES = 126, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_INTERFACES = 127, /* autogen autogen priority:high */
+    REMOTE_PROC_INTERFACE_LOOKUP_BY_NAME = 128, /* autogen autogen priority:high */
+    REMOTE_PROC_INTERFACE_LOOKUP_BY_MAC_STRING = 129, /* autogen autogen priority:high */
     REMOTE_PROC_INTERFACE_GET_XML_DESC = 130, /* autogen autogen */
 
-    REMOTE_PROC_INTERFACE_DEFINE_XML = 131, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_UNDEFINE = 132, /* autogen autogen */
+    REMOTE_PROC_INTERFACE_DEFINE_XML = 131, /* autogen autogen priority:high */
+    REMOTE_PROC_INTERFACE_UNDEFINE = 132, /* autogen autogen priority:high */
     REMOTE_PROC_INTERFACE_CREATE = 133, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_DESTROY = 134, /* autogen autogen */
+    REMOTE_PROC_INTERFACE_DESTROY = 134, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_XML_FROM_NATIVE = 135, /* autogen autogen */
     REMOTE_PROC_DOMAIN_XML_TO_NATIVE = 136, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_DEFINED_INTERFACES = 137, /* autogen autogen */
-    REMOTE_PROC_LIST_DEFINED_INTERFACES = 138, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_SECRETS = 139, /* autogen autogen */
-    REMOTE_PROC_LIST_SECRETS = 140, /* autogen autogen */
-
-    REMOTE_PROC_SECRET_LOOKUP_BY_UUID = 141, /* autogen autogen */
-    REMOTE_PROC_SECRET_DEFINE_XML = 142, /* autogen autogen */
-    REMOTE_PROC_SECRET_GET_XML_DESC = 143, /* autogen autogen */
-    REMOTE_PROC_SECRET_SET_VALUE = 144, /* autogen autogen */
-    REMOTE_PROC_SECRET_GET_VALUE = 145, /* skipgen skipgen */
-    REMOTE_PROC_SECRET_UNDEFINE = 146, /* autogen autogen */
-    REMOTE_PROC_SECRET_LOOKUP_BY_USAGE = 147, /* autogen autogen */
+    REMOTE_PROC_NUM_OF_DEFINED_INTERFACES = 137, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_DEFINED_INTERFACES = 138, /* autogen autogen priority:high */
+    REMOTE_PROC_NUM_OF_SECRETS = 139, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_SECRETS = 140, /* autogen autogen priority:high */
+
+    REMOTE_PROC_SECRET_LOOKUP_BY_UUID = 141, /* autogen autogen priority:high */
+    REMOTE_PROC_SECRET_DEFINE_XML = 142, /* autogen autogen priority:high */
+    REMOTE_PROC_SECRET_GET_XML_DESC = 143, /* autogen autogen priority:high */
+    REMOTE_PROC_SECRET_SET_VALUE = 144, /* autogen autogen priority:high */
+    REMOTE_PROC_SECRET_GET_VALUE = 145, /* skipgen skipgen priority:high */
+    REMOTE_PROC_SECRET_UNDEFINE = 146, /* autogen autogen priority:high */
+    REMOTE_PROC_SECRET_LOOKUP_BY_USAGE = 147, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL = 148, /* autogen autogen | writestream 1 */
-    REMOTE_PROC_IS_SECURE = 149, /* autogen skipgen */
-    REMOTE_PROC_DOMAIN_IS_ACTIVE = 150, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_IS_PERSISTENT = 151, /* autogen autogen */
-    REMOTE_PROC_NETWORK_IS_ACTIVE = 152, /* autogen autogen */
-    REMOTE_PROC_NETWORK_IS_PERSISTENT = 153, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_IS_ACTIVE = 154, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_IS_PERSISTENT = 155, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_IS_ACTIVE = 156, /* autogen autogen */
-    REMOTE_PROC_GET_LIB_VERSION = 157, /* autogen autogen */
-    REMOTE_PROC_CPU_COMPARE = 158, /* autogen autogen */
+    REMOTE_PROC_IS_SECURE = 149, /* autogen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_IS_ACTIVE = 150, /* autogen autogen priority:high */
+
+    REMOTE_PROC_DOMAIN_IS_PERSISTENT = 151, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_IS_ACTIVE = 152, /* autogen autogen priority:high */
+    REMOTE_PROC_NETWORK_IS_PERSISTENT = 153, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_IS_ACTIVE = 154, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_POOL_IS_PERSISTENT = 155, /* autogen autogen priority:high */
+    REMOTE_PROC_INTERFACE_IS_ACTIVE = 156, /* autogen autogen priority:high */
+    REMOTE_PROC_GET_LIB_VERSION = 157, /* autogen autogen priority:high */
+    REMOTE_PROC_CPU_COMPARE = 158, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_MEMORY_STATS = 159, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, /* autogen autogen */
 
@@ -2393,8 +2399,8 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_ABORT_JOB = 164, /* autogen autogen */
     REMOTE_PROC_STORAGE_VOL_WIPE = 165, /* autogen autogen */
     REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 166, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_EVENTS_REGISTER_ANY = 167, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 168, /* skipgen skipgen */
+    REMOTE_PROC_DOMAIN_EVENTS_REGISTER_ANY = 167, /* skipgen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 168, /* skipgen skipgen priority:high */
     REMOTE_PROC_DOMAIN_EVENT_REBOOT = 169, /* autogen autogen */
     REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 170, /* autogen autogen */
 
@@ -2402,22 +2408,22 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 172, /* autogen autogen */
     REMOTE_PROC_DOMAIN_EVENT_GRAPHICS = 173, /* autogen autogen */
     REMOTE_PROC_DOMAIN_UPDATE_DEVICE_FLAGS = 174, /* autogen autogen */
-    REMOTE_PROC_NWFILTER_LOOKUP_BY_NAME = 175, /* autogen autogen */
-    REMOTE_PROC_NWFILTER_LOOKUP_BY_UUID = 176, /* autogen autogen */
-    REMOTE_PROC_NWFILTER_GET_XML_DESC = 177, /* autogen autogen */
-    REMOTE_PROC_NUM_OF_NWFILTERS = 178, /* autogen autogen */
-    REMOTE_PROC_LIST_NWFILTERS = 179, /* autogen autogen */
-    REMOTE_PROC_NWFILTER_DEFINE_XML = 180, /* autogen autogen */
-
-    REMOTE_PROC_NWFILTER_UNDEFINE = 181, /* autogen autogen */
+    REMOTE_PROC_NWFILTER_LOOKUP_BY_NAME = 175, /* autogen autogen priority:high */
+    REMOTE_PROC_NWFILTER_LOOKUP_BY_UUID = 176, /* autogen autogen priority:high */
+    REMOTE_PROC_NWFILTER_GET_XML_DESC = 177, /* autogen autogen priority:high */
+    REMOTE_PROC_NUM_OF_NWFILTERS = 178, /* autogen autogen priority:high */
+    REMOTE_PROC_LIST_NWFILTERS = 179, /* autogen autogen priority:high */
+    REMOTE_PROC_NWFILTER_DEFINE_XML = 180, /* autogen autogen priority:high */
+
+    REMOTE_PROC_NWFILTER_UNDEFINE = 181, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_MANAGED_SAVE = 182, /* autogen autogen */
     REMOTE_PROC_DOMAIN_HAS_MANAGED_SAVE_IMAGE = 183, /* autogen autogen */
     REMOTE_PROC_DOMAIN_MANAGED_SAVE_REMOVE = 184, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML = 185, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_GET_XML_DESC = 186, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_NUM = 187, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES = 188, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME = 189, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_GET_XML_DESC = 186, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_NUM = 187, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES = 188, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME = 189, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT = 190, /* autogen autogen */
 
     REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT = 191, /* autogen autogen */
@@ -2432,8 +2438,8 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS = 200, /* autogen autogen */
 
     REMOTE_PROC_DOMAIN_OPEN_CONSOLE = 201, /* autogen autogen | readstream 2 */
-    REMOTE_PROC_DOMAIN_IS_UPDATED = 202, /* autogen autogen */
-    REMOTE_PROC_GET_SYSINFO = 203, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_IS_UPDATED = 202, /* autogen autogen priority:high */
+    REMOTE_PROC_GET_SYSINFO = 203, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_SET_MEMORY_FLAGS = 204, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SET_BLKIO_PARAMETERS = 205, /* autogen autogen */
     REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, /* skipgen skipgen */
@@ -2443,7 +2449,7 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_INJECT_NMI = 210, /* autogen autogen */
 
     REMOTE_PROC_DOMAIN_SCREENSHOT = 211, /* autogen autogen | readstream 1 */
-    REMOTE_PROC_DOMAIN_GET_STATE = 212, /* skipgen skipgen */
+    REMOTE_PROC_DOMAIN_GET_STATE = 212, /* skipgen skipgen priority:high */
     REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3 = 213, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_MIGRATE_PREPARE3 = 214, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3 = 215, /* autogen skipgen | writestream 1 */
@@ -2459,17 +2465,17 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_PIN_VCPU_FLAGS = 225, /* autogen autogen */
     REMOTE_PROC_DOMAIN_SEND_KEY = 226, /* autogen autogen */
-    REMOTE_PROC_NODE_GET_CPU_STATS = 227, /* skipgen skipgen */
-    REMOTE_PROC_NODE_GET_MEMORY_STATS = 228, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_GET_CONTROL_INFO = 229, /* autogen autogen */
+    REMOTE_PROC_NODE_GET_CPU_STATS = 227, /* skipgen skipgen priority:high */
+    REMOTE_PROC_NODE_GET_MEMORY_STATS = 228, /* skipgen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_GET_CONTROL_INFO = 229, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_GET_VCPU_PIN_INFO = 230, /* skipgen skipgen */
 
-    REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS = 231, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS = 231, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_SAVE_FLAGS = 232, /* autogen autogen */
     REMOTE_PROC_DOMAIN_RESTORE_FLAGS = 233, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_DESTROY_FLAGS = 234, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SAVE_IMAGE_GET_XML_DESC = 235, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SAVE_IMAGE_DEFINE_XML = 236, /* autogen autogen */
+    REMOTE_PROC_DOMAIN_DESTROY_FLAGS = 234, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SAVE_IMAGE_GET_XML_DESC = 235, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_SAVE_IMAGE_DEFINE_XML = 236, /* autogen autogen priority:high */
     REMOTE_PROC_DOMAIN_BLOCK_JOB_ABORT = 237, /* autogen autogen */
     REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO = 238, /* skipgen skipgen */
     REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 239, /* autogen autogen */
@@ -2481,10 +2487,16 @@ enum remote_procedure {
      * Notice how the entries are grouped in sets of 10 ?
      * Nice isn't it. Please keep it this way when adding more.
      *
-     * Each function must have a two-word comment.  The first word is
+     * Each function must have a three-word comment.  The first word is
      * whether gendispatch.pl handles daemon, the second whether
      * it handles src/remote.  Additional flags can be specified after a
      * pipe.
+     * The last argument describes priority of API. There are two accepted
+     * values: low, high; Each API that might eventually access hypervisor's
+     * monitor (and thus block) MUST fall into low priority. However, there
+     * are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
+     * be marked as high priority. If in doubt, it's safe to choose low.
+     * Low is taken as default, and thus can be left out.
      *
      * The (readstream|writestream)@<offset> flag lets daemon and src/remote
      * create a stream.  The direction is defined from the src/remote point
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index 0d344e8..38cbb65 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -146,12 +146,13 @@ while (<PROTOCOL>) {
         }
 
         if ($opt_b or $opt_k) {
-            if (!($flags =~ m/^\s*\/\*\s*(\S+)\s+(\S+)\s*(.*)\*\/\s*$/)) {
+            if (!($flags =~ m/^\s*\/\*\s*(\S+)\s+(\S+)\s*(\|.*)?\s+(priority:(\S+))?\s*\*\/\s*$/)) {
                 die "invalid generator flags for ${procprefix}_PROC_${name}"
             }
 
             my $genmode = $opt_b ? $1 : $2;
             my $genflags = $3;
+            my $priority = defined $5 ? $5 : "low";
 
             if ($genmode eq "autogen") {
                 push(@autogen, $ProcName);
@@ -171,6 +172,16 @@ while (<PROTOCOL>) {
             } else {
                 $calls{$name}->{streamflag} = "none";
             }
+
+            # for now, we distinguish only two levels of prioroty:
+            # low (0) and high (1)
+            if ($priority eq "high") {
+                $calls{$name}->{priority} = 1;
+            } elsif ($priority eq "low") {
+                $calls{$name}->{priority} = 0;
+            } else {
+                die "invalid priority ${priority} for ${procprefix}_PROC_${name}"
+            }
         }
 
         $calls[$id] = $calls{$name};
@@ -259,6 +270,7 @@ if ($opt_d) {
         print "$_:\n";
         print "        name $calls{$_}->{name} ($calls{$_}->{ProcName})\n";
         print "        $calls{$_}->{args} -> $calls{$_}->{ret}\n";
+        print "        priority -> $calls{$_}->{priority}\n";
     }
 }
 
@@ -927,7 +939,7 @@ elsif ($opt_b) {
 
     print "virNetServerProgramProc ${structprefix}Procs[] = {\n";
     for ($id = 0 ; $id <= $#calls ; $id++) {
-	my ($comment, $name, $argtype, $arglen, $argfilter, $retlen, $retfilter);
+	my ($comment, $name, $argtype, $arglen, $argfilter, $retlen, $retfilter, $priority);
 
 	if (defined $calls[$id] && !$calls[$id]->{msg}) {
 	    $comment = "/* Method $calls[$id]->{ProcName} => $id */";
@@ -950,7 +962,9 @@ elsif ($opt_b) {
 	    $retfilter = "xdr_void";
 	}
 
-	print "{ $comment\n   ${name},\n   $arglen,\n   (xdrproc_t)$argfilter,\n   $retlen,\n   (xdrproc_t)$retfilter,\n   true \n},\n";
+    $priority = defined $calls[$id]->{priority} ? $calls[$id]->{priority} : 0;
+
+	print "{ $comment\n   ${name},\n   $arglen,\n   (xdrproc_t)$argfilter,\n   $retlen,\n   (xdrproc_t)$retfilter,\n   true,\n   $priority\n},\n";
     }
     print "};\n";
     print "size_t ${structprefix}NProcs = ARRAY_CARDINALITY(${structprefix}Procs);\n";
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index 1a49dbb..bc9fa89 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -64,6 +64,7 @@ typedef virNetServerJob *virNetServerJobPtr;
 struct _virNetServerJob {
     virNetServerClientPtr client;
     virNetMessagePtr msg;
+    virNetServerProgramPtr prog;
 };
 
 struct _virNetServer {
@@ -128,38 +129,18 @@ static void virNetServerHandleJob(void *jobOpaque, void *opaque)
 {
     virNetServerPtr srv = opaque;
     virNetServerJobPtr job = jobOpaque;
-    virNetServerProgramPtr prog = NULL;
-    size_t i;
 
-    virNetServerLock(srv);
     VIR_DEBUG("server=%p client=%p message=%p",
               srv, job->client, job->msg);
 
-    for (i = 0 ; i < srv->nprograms ; i++) {
-        if (virNetServerProgramMatches(srv->programs[i], job->msg)) {
-            prog = srv->programs[i];
-            break;
-        }
-    }
-
-    if (!prog) {
-        VIR_DEBUG("Cannot find program %d version %d",
-                  job->msg->header.prog,
-                  job->msg->header.vers);
-        goto error;
-    }
-
-    virNetServerProgramRef(prog);
-    virNetServerUnlock(srv);
-
-    if (virNetServerProgramDispatch(prog,
+    if (virNetServerProgramDispatch(job->prog,
                                     srv,
                                     job->client,
                                     job->msg) < 0)
         goto error;
 
     virNetServerLock(srv);
-    virNetServerProgramFree(prog);
+    virNetServerProgramFree(job->prog);
     virNetServerUnlock(srv);
     virNetServerClientFree(job->client);
 
@@ -168,21 +149,23 @@ static void virNetServerHandleJob(void *jobOpaque, void *opaque)
 
 error:
     virNetServerUnlock(srv);
-    virNetServerProgramFree(prog);
+    virNetServerProgramFree(job->prog);
     virNetMessageFree(job->msg);
     virNetServerClientClose(job->client);
     virNetServerClientFree(job->client);
     VIR_FREE(job);
 }
 
-
 static int virNetServerDispatchNewMessage(virNetServerClientPtr client,
                                           virNetMessagePtr msg,
                                           void *opaque)
 {
     virNetServerPtr srv = opaque;
     virNetServerJobPtr job;
-    int ret;
+    virNetServerProgramPtr prog = NULL;
+    unsigned int priority = 0;
+    size_t i;
+    int ret = -1;
 
     VIR_DEBUG("server=%p client=%p message=%p",
               srv, client, msg);
@@ -196,8 +179,31 @@ static int virNetServerDispatchNewMessage(virNetServerClientPtr client,
     job->msg = msg;
 
     virNetServerLock(srv);
-    if ((ret = virThreadPoolSendJob(srv->workers, job)) < 0)
+    for (i = 0 ; i < srv->nprograms ; i++) {
+        if (virNetServerProgramMatches(srv->programs[i], job->msg)) {
+            prog = srv->programs[i];
+            break;
+        }
+    }
+
+    if (!prog) {
+        VIR_DEBUG("Cannot find program %d version %d",
+                  job->msg->header.prog,
+                  job->msg->header.vers);
+        goto cleanup;
+    }
+
+    virNetServerProgramRef(prog);
+    job->prog = prog;
+    priority = virNetServerProgramGetPriority(prog, msg->header.proc);
+
+    ret = virThreadPoolSendJob(srv->workers, priority, job);
+
+cleanup:
+    if (ret < 0) {
         VIR_FREE(job);
+        virNetServerProgramFree(prog);
+    }
     virNetServerUnlock(srv);
 
     return ret;
@@ -274,6 +280,7 @@ static void virNetServerFatalSignal(int sig, siginfo_t *siginfo ATTRIBUTE_UNUSED
 
 virNetServerPtr virNetServerNew(size_t min_workers,
                                 size_t max_workers,
+                                size_t priority_workers,
                                 size_t max_clients,
                                 const char *mdnsGroupName,
                                 bool connectDBus ATTRIBUTE_UNUSED,
@@ -290,6 +297,7 @@ virNetServerPtr virNetServerNew(size_t min_workers,
     srv->refs = 1;
 
     if (!(srv->workers = virThreadPoolNew(min_workers, max_workers,
+                                          priority_workers,
                                           virNetServerHandleJob,
                                           srv)))
         goto error;
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h
index 324cfb7..cc9d039 100644
--- a/src/rpc/virnetserver.h
+++ b/src/rpc/virnetserver.h
@@ -39,6 +39,7 @@ typedef int (*virNetServerClientInitHook)(virNetServerPtr srv,
 
 virNetServerPtr virNetServerNew(size_t min_workers,
                                 size_t max_workers,
+                                size_t priority_workers,
                                 size_t max_clients,
                                 const char *mdnsGroupName,
                                 bool connectDBus,
diff --git a/src/rpc/virnetserverprogram.c b/src/rpc/virnetserverprogram.c
index ca80ae0..33e036d 100644
--- a/src/rpc/virnetserverprogram.c
+++ b/src/rpc/virnetserverprogram.c
@@ -108,6 +108,17 @@ static virNetServerProgramProcPtr virNetServerProgramGetProc(virNetServerProgram
     return &prog->procs[procedure];
 }
 
+unsigned int
+virNetServerProgramGetPriority(virNetServerProgramPtr prog,
+                               int procedure)
+{
+    virNetServerProgramProcPtr proc = virNetServerProgramGetProc(prog, procedure);
+
+    if (!proc)
+        return 0;
+
+    return proc->priority;
+}
 
 static int
 virNetServerProgramSendError(virNetServerProgramPtr prog,
diff --git a/src/rpc/virnetserverprogram.h b/src/rpc/virnetserverprogram.h
index ca31b7e..4f931ff 100644
--- a/src/rpc/virnetserverprogram.h
+++ b/src/rpc/virnetserverprogram.h
@@ -53,6 +53,7 @@ struct _virNetServerProgramProc {
     size_t ret_len;
     xdrproc_t ret_filter;
     bool needAuth;
+    unsigned int priority;
 };
 
 virNetServerProgramPtr virNetServerProgramNew(unsigned program,
@@ -63,6 +64,9 @@ virNetServerProgramPtr virNetServerProgramNew(unsigned program,
 int virNetServerProgramGetID(virNetServerProgramPtr prog);
 int virNetServerProgramGetVersion(virNetServerProgramPtr prog);
 
+unsigned int virNetServerProgramGetPriority(virNetServerProgramPtr prog,
+                                            int procedure);
+
 void virNetServerProgramRef(virNetServerProgramPtr prog);
 
 int virNetServerProgramMatches(virNetServerProgramPtr prog,
diff --git a/src/util/threadpool.c b/src/util/threadpool.c
index 8217591..70a75c0 100644
--- a/src/util/threadpool.c
+++ b/src/util/threadpool.c
@@ -37,7 +37,9 @@ typedef struct _virThreadPoolJob virThreadPoolJob;
 typedef virThreadPoolJob *virThreadPoolJobPtr;
 
 struct _virThreadPoolJob {
+    virThreadPoolJobPtr prev;
     virThreadPoolJobPtr next;
+    unsigned int priority;
 
     void *data;
 };
@@ -47,7 +49,8 @@ typedef virThreadPoolJobList *virThreadPoolJobListPtr;
 
 struct _virThreadPoolJobList {
     virThreadPoolJobPtr head;
-    virThreadPoolJobPtr *tail;
+    virThreadPoolJobPtr tail;
+    virThreadPoolJobPtr firstPrio;
 };
 
 
@@ -57,6 +60,7 @@ struct _virThreadPool {
     virThreadPoolJobFunc jobFunc;
     void *jobOpaque;
     virThreadPoolJobList jobList;
+    size_t jobQueueDepth;
 
     virMutex mutex;
     virCond cond;
@@ -66,33 +70,75 @@ struct _virThreadPool {
     size_t freeWorkers;
     size_t nWorkers;
     virThreadPtr workers;
+
+    size_t nPrioWorkers;
+    virThreadPtr prioWorkers;
+    virCond prioCond;
+};
+
+struct virThreadPoolWorkerData {
+    virThreadPoolPtr pool;
+    virCondPtr cond;
+    bool priority;
 };
 
 static void virThreadPoolWorker(void *opaque)
 {
-    virThreadPoolPtr pool = opaque;
+    struct virThreadPoolWorkerData *data = opaque;
+    virThreadPoolPtr pool = data->pool;
+    virCondPtr cond = data->cond;
+    bool priority = data->priority;
+    virThreadPoolJobPtr job = NULL;
+
+    VIR_FREE(data);
 
     virMutexLock(&pool->mutex);
 
     while (1) {
         while (!pool->quit &&
-               !pool->jobList.head) {
-            pool->freeWorkers++;
-            if (virCondWait(&pool->cond, &pool->mutex) < 0) {
-                pool->freeWorkers--;
+               ((!priority && !pool->jobList.head) ||
+                (priority && !pool->jobList.firstPrio))) {
+            if (!priority)
+                pool->freeWorkers++;
+            if (virCondWait(cond, &pool->mutex) < 0) {
+                if (!priority)
+                    pool->freeWorkers--;
                 goto out;
             }
-            pool->freeWorkers--;
+            if (!priority)
+                pool->freeWorkers--;
         }
 
         if (pool->quit)
             break;
 
-        virThreadPoolJobPtr job = pool->jobList.head;
-        pool->jobList.head = pool->jobList.head->next;
-        job->next = NULL;
-        if (pool->jobList.tail == &job->next)
-            pool->jobList.tail = &pool->jobList.head;
+        if (priority) {
+            job = pool->jobList.firstPrio;
+        } else {
+            job = pool->jobList.head;
+        }
+
+        if (job == pool->jobList.firstPrio) {
+            virThreadPoolJobPtr tmp = job->next;
+            while (tmp) {
+                if (tmp->priority) {
+                    break;
+                }
+                tmp = tmp->next;
+            }
+            pool->jobList.firstPrio = tmp;
+        }
+
+        if (job->prev)
+            job->prev->next = job->next;
+        else
+            pool->jobList.head = job->next;
+        if (job->next)
+            job->next->prev = job->prev;
+        else
+            pool->jobList.tail = job->prev;
+
+        pool->jobQueueDepth--;
 
         virMutexUnlock(&pool->mutex);
         (pool->jobFunc)(job->data, pool->jobOpaque);
@@ -101,19 +147,24 @@ static void virThreadPoolWorker(void *opaque)
     }
 
 out:
-    pool->nWorkers--;
-    if (pool->nWorkers == 0)
+    if (priority)
+        pool->nPrioWorkers--;
+    else
+        pool->nWorkers--;
+    if (pool->nWorkers == 0 && pool->nPrioWorkers==0)
         virCondSignal(&pool->quit_cond);
     virMutexUnlock(&pool->mutex);
 }
 
 virThreadPoolPtr virThreadPoolNew(size_t minWorkers,
                                   size_t maxWorkers,
+                                  size_t prioWorkers,
                                   virThreadPoolJobFunc func,
                                   void *opaque)
 {
     virThreadPoolPtr pool;
     size_t i;
+    struct virThreadPoolWorkerData *data = NULL;
 
     if (minWorkers > maxWorkers)
         minWorkers = maxWorkers;
@@ -123,8 +174,7 @@ virThreadPoolPtr virThreadPoolNew(size_t minWorkers,
         return NULL;
     }
 
-    pool->jobList.head = NULL;
-    pool->jobList.tail = &pool->jobList.head;
+    pool->jobList.tail = pool->jobList.head = NULL;
 
     pool->jobFunc = func;
     pool->jobOpaque = opaque;
@@ -141,18 +191,51 @@ virThreadPoolPtr virThreadPoolNew(size_t minWorkers,
 
     pool->maxWorkers = maxWorkers;
     for (i = 0; i < minWorkers; i++) {
+        if (VIR_ALLOC(data) < 0) {
+            virReportOOMError();
+            goto error;
+        }
+        data->pool = pool;
+        data->cond = &pool->cond;
+
         if (virThreadCreate(&pool->workers[i],
                             true,
                             virThreadPoolWorker,
-                            pool) < 0) {
+                            data) < 0) {
             goto error;
         }
         pool->nWorkers++;
     }
 
+    if (prioWorkers) {
+        if (virCondInit(&pool->prioCond) < 0)
+            goto error;
+        if (VIR_ALLOC_N(pool->prioWorkers, prioWorkers) < 0)
+            goto error;
+
+        for (i = 0; i < prioWorkers; i++) {
+            if (VIR_ALLOC(data) < 0) {
+                virReportOOMError();
+                goto error;
+            }
+            data->pool = pool;
+            data->cond = &pool->prioCond;
+            data->priority = true;
+
+            if (virThreadCreate(&pool->prioWorkers[i],
+                                true,
+                                virThreadPoolWorker,
+                                data) < 0) {
+                goto error;
+            }
+            pool->nPrioWorkers++;
+        }
+    }
+
     return pool;
 
 error:
+    VIR_FREE(data);
     virThreadPoolFree(pool);
     return NULL;
 
@@ -161,17 +244,22 @@ error:
 void virThreadPoolFree(virThreadPoolPtr pool)
 {
     virThreadPoolJobPtr job;
+    bool priority = false;
 
     if (!pool)
         return;
 
     virMutexLock(&pool->mutex);
     pool->quit = true;
-    if (pool->nWorkers > 0) {
+    if (pool->nWorkers > 0)
         virCondBroadcast(&pool->cond);
-        ignore_value(virCondWait(&pool->quit_cond, &pool->mutex));
+    if (pool->nPrioWorkers > 0) {
+        priority = true;
+        virCondBroadcast(&pool->prioCond);
     }
 
+    ignore_value(virCondWait(&pool->quit_cond, &pool->mutex));
+
     while ((job = pool->jobList.head)) {
         pool->jobList.head = pool->jobList.head->next;
         VIR_FREE(job);
@@ -182,10 +270,19 @@ void virThreadPoolFree(virThreadPoolPtr pool)
     virMutexDestroy(&pool->mutex);
     ignore_value(virCondDestroy(&pool->quit_cond));
     ignore_value(virCondDestroy(&pool->cond));
+    if (priority) {
+        VIR_FREE(pool->prioWorkers);
+        ignore_value(virCondDestroy(&pool->prioCond));
+    }
     VIR_FREE(pool);
 }
 
+/*
+ * @priority - job priority
+ * Return: 0 on success, -1 otherwise
+ */
 int virThreadPoolSendJob(virThreadPoolPtr pool,
+                         unsigned int priority,
                          void *jobData)
 {
     virThreadPoolJobPtr job;
@@ -194,7 +291,7 @@ int virThreadPoolSendJob(virThreadPoolPtr pool,
     if (pool->quit)
         goto error;
 
-    if (pool->freeWorkers == 0 &&
+    if (pool->freeWorkers - pool->jobQueueDepth <= 0 &&
         pool->nWorkers < pool->maxWorkers) {
         if (VIR_EXPAND_N(pool->workers, pool->nWorkers, 1) < 0) {
             virReportOOMError();
@@ -216,13 +313,26 @@ int virThreadPoolSendJob(virThreadPoolPtr pool,
     }
 
     job->data = jobData;
-    job->next = NULL;
-    *pool->jobList.tail = job;
-    pool->jobList.tail = &(*pool->jobList.tail)->next;
+    job->priority = priority;
+
+    job->prev = pool->jobList.tail;
+    if (pool->jobList.tail)
+        pool->jobList.tail->next = job;
+    pool->jobList.tail = job;
+
+    if (!pool->jobList.head)
+        pool->jobList.head = job;
+
+    if (priority && !pool->jobList.firstPrio)
+        pool->jobList.firstPrio = job;
+
+    pool->jobQueueDepth++;
 
     virCondSignal(&pool->cond);
-    virMutexUnlock(&pool->mutex);
+    if (priority)
+        virCondSignal(&pool->prioCond);
 
+    virMutexUnlock(&pool->mutex);
     return 0;
 
 error:
diff --git a/src/util/threadpool.h b/src/util/threadpool.h
index 8b8c676..c4612ad 100644
--- a/src/util/threadpool.h
+++ b/src/util/threadpool.h
@@ -35,12 +35,14 @@ typedef void (*virThreadPoolJobFunc)(void *jobdata, void *opaque);
 
 virThreadPoolPtr virThreadPoolNew(size_t minWorkers,
                                   size_t maxWorkers,
+                                  size_t prioWorkers,
                                   virThreadPoolJobFunc func,
-                                  void *opaque) ATTRIBUTE_NONNULL(3);
+                                  void *opaque) ATTRIBUTE_NONNULL(4);
 
 void virThreadPoolFree(virThreadPoolPtr pool);
 
 int virThreadPoolSendJob(virThreadPoolPtr pool,
+                         unsigned int priority,
                          void *jobdata) ATTRIBUTE_NONNULL(1)
                                         ATTRIBUTE_RETURN_CHECK;
 
-- 
1.7.3.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]