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

Michal Privoznik mprivozn at redhat.com
Fri Aug 26 09:34:27 UTC 2011


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 is new thread pool created.
HPC tries to land in usual thread pool firstly. The condition here
is it contains at least one free worker. As soon as it doesn't,
HPCs are placed into the new pool. 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.
---
diff to v2:
- leave the idea of 2 separate pools, and rewrite threadpool to allow priority
  workers. These can work only on priority jobs. Normal workers can work on both
  normal & priority job. Job is inherited from HPC.

- Introduce jobQueueDepth to heal harmless bug with freeWorkers equal zero.

- Leave out callback for proc priority. As this information is in program proc table.
  However, when queueing job, we didn't know to which program is job related.
  Program was looked up in job handling, so after queuing. Move this bit a step forward.

NB: the current division of calls to HPC and normal ones I present here may be not
quite precise enough. So any feedback is more than welcome.

 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  |  544 +++++++++++++++++++++--------------------
 src/rpc/gendispatch.pl        |   20 ++-
 src/rpc/virnetserver.c        |   61 +++--
 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, 507 insertions(+), 327 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 b5268e4..c8bd4a8 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 f691bbb..146ba12 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..787b409 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2201,290 +2201,300 @@ 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.
      *
      * 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_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_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_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_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_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_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_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_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_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_CREATE = 78, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_BUILD = 79, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_DESTROY = 80, /* autogen autogen */
-
-    REMOTE_PROC_STORAGE_POOL_DELETE = 81, /* autogen autogen */
-    REMOTE_PROC_STORAGE_POOL_UNDEFINE = 82, /* autogen autogen */
-    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_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_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_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_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_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_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_NODE_DEVICE_CREATE_XML = 123, /* autogen autogen */
-    REMOTE_PROC_NODE_DEVICE_DESTROY = 124, /* autogen autogen */
-    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_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_CREATE = 133, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_DESTROY = 134, /* autogen autogen */
-    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_DOMAIN_MIGRATE_PREPARE_TUNNEL = 148, /* autogen autogen | writestream at 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_DOMAIN_MEMORY_STATS = 159, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, /* autogen autogen */
-    REMOTE_PROC_CPU_BASELINE = 162, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, /* autogen autogen */
-    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_EVENT_REBOOT = 169, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 170, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 171, /* autogen autogen */
-    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_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_HAS_CURRENT_SNAPSHOT = 190, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT = 191, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_REVERT_TO_SNAPSHOT = 192, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 193, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS = 199, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS = 200, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_OPEN_CONSOLE = 201, /* autogen autogen | readstream at 2 */
-    REMOTE_PROC_DOMAIN_IS_UPDATED = 202, /* autogen autogen */
-    REMOTE_PROC_GET_SYSINFO = 203, /* autogen autogen */
-    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 */
-    REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, /* autogen autogen */
-    REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, /* autogen autogen | writestream at 1 */
-    REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, /* autogen autogen | readstream at 1 */
-    REMOTE_PROC_DOMAIN_INJECT_NMI = 210, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_SCREENSHOT = 211, /* autogen autogen | readstream at 1 */
-    REMOTE_PROC_DOMAIN_GET_STATE = 212, /* skipgen skipgen */
-    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 at 1 */
-    REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3 = 216, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_MIGRATE_FINISH3 = 217, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3 = 218, /* skipgen skipgen */
-    REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS_FLAGS = 219, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_CHANGE_BEGIN = 220, /* autogen autogen */
-
-    REMOTE_PROC_INTERFACE_CHANGE_COMMIT = 221, /* autogen autogen */
-    REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK = 222, /* autogen autogen */
-    REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS = 223, /* skipgen autogen */
-    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_DOMAIN_GET_VCPU_PIN_INFO = 230, /* skipgen skipgen */
-
-    REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS = 231, /* autogen autogen */
-    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_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 */
-    REMOTE_PROC_DOMAIN_BLOCK_PULL = 240, /* autogen autogen */
-
-    REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241 /* skipgen skipgen */
+    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 priority:low */
+    REMOTE_PROC_DOMAIN_ATTACH_DEVICE = 8, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_CREATE = 9, /* autogen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_CREATE_XML = 10, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_DEFINE_XML = 11, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_DESTROY = 12, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_DETACH_DEVICE = 13, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_XML_DESC = 14, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_AUTOSTART = 15, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_INFO = 16, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_MAX_MEMORY = 17, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_MAX_VCPUS = 18, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_OS_TYPE = 19, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_VCPUS = 20, /* skipgen skipgen priority:low */
+
+    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 priority:low */
+    REMOTE_PROC_DOMAIN_REBOOT = 27, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_RESUME = 28, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_AUTOSTART = 29, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_MAX_MEMORY = 30, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_SET_MEMORY = 31, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_VCPUS = 32, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SHUTDOWN = 33, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SUSPEND = 34, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_UNDEFINE = 35, /* autogen autogen priority:low */
+    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 priority:high */
+    REMOTE_PROC_NETWORK_CREATE_XML = 40, /* autogen autogen priority:high */
+
+    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 priority:low */
+    REMOTE_PROC_DOMAIN_RESTORE = 54, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SAVE = 55, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_SCHEDULER_TYPE = 56, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS = 57, /* skipgen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS = 58, /* autogen autogen priority:low */
+    REMOTE_PROC_GET_HOSTNAME = 59, /* autogen autogen priority:low */
+    REMOTE_PROC_SUPPORTS_FEATURE = 60, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_MIGRATE_PREPARE = 61, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_PERFORM = 62, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_FINISH = 63, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_BLOCK_STATS = 64, /* autogen autogen priority:low */
+    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:low */
+    REMOTE_PROC_NUM_OF_DEFINED_STORAGE_POOLS = 73, /* autogen autogen priority:low */
+    REMOTE_PROC_LIST_DEFINED_STORAGE_POOLS = 74, /* autogen autogen priority:low */
+    REMOTE_PROC_FIND_STORAGE_POOL_SOURCES = 75, /* autogen skipgen priority:low */
+    REMOTE_PROC_STORAGE_POOL_CREATE_XML = 76, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_DEFINE_XML = 77, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_CREATE = 78, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_BUILD = 79, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_DESTROY = 80, /* autogen autogen priority:low */
+
+    REMOTE_PROC_STORAGE_POOL_DELETE = 81, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_UNDEFINE = 82, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_REFRESH = 83, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_NAME = 84, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_UUID = 85, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_LOOKUP_BY_VOLUME = 86, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_GET_INFO = 87, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_GET_XML_DESC = 88, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_GET_AUTOSTART = 89, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_SET_AUTOSTART = 90, /* autogen autogen priority:low */
+
+    REMOTE_PROC_STORAGE_POOL_NUM_OF_VOLUMES = 91, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_POOL_LIST_VOLUMES = 92, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_CREATE_XML = 93, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_DELETE = 94, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_NAME = 95, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_KEY = 96, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH = 97, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_GET_INFO = 98, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_GET_XML_DESC = 99, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_GET_PATH = 100, /* autogen autogen priority:low */
+
+    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 priority:low */
+    REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_EVENTS_REGISTER = 105, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER = 106, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE = 107, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_PREPARE2 = 108, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_FINISH2 = 109, /* autogen autogen priority:low */
+    REMOTE_PROC_GET_URI = 110, /* autogen skipgen priority:high */
+
+    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 priority:high */
+    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 priority:high */
+    REMOTE_PROC_NODE_DEVICE_RE_ATTACH = 119, /* autogen skipgen priority:high */
+    REMOTE_PROC_NODE_DEVICE_RESET = 120, /* autogen skipgen priority:high */
+
+    REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL = 121, /* skipgen skipgen priority:low */
+    REMOTE_PROC_NODE_GET_SECURITY_MODEL = 122, /* skipgen skipgen priority:high */
+    REMOTE_PROC_NODE_DEVICE_CREATE_XML = 123, /* autogen autogen priority:high */
+    REMOTE_PROC_NODE_DEVICE_DESTROY = 124, /* autogen autogen priority:high */
+    REMOTE_PROC_STORAGE_VOL_CREATE_XML_FROM = 125, /* autogen autogen priority:low */
+    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 priority:high */
+
+    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 priority:high */
+    REMOTE_PROC_INTERFACE_DESTROY = 134, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_XML_FROM_NATIVE = 135, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_XML_TO_NATIVE = 136, /* autogen autogen priority:low */
+    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 at 1 priority:low */
+    REMOTE_PROC_IS_SECURE = 149, /* autogen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_IS_ACTIVE = 150, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_IS_PERSISTENT = 151, /* autogen autogen priority:low */
+    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:low */
+    REMOTE_PROC_STORAGE_POOL_IS_PERSISTENT = 155, /* autogen autogen priority:low */
+    REMOTE_PROC_INTERFACE_IS_ACTIVE = 156, /* autogen autogen priority:high */
+    REMOTE_PROC_GET_LIB_VERSION = 157, /* autogen autogen priority:low */
+    REMOTE_PROC_CPU_COMPARE = 158, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_MEMORY_STATS = 159, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_ATTACH_DEVICE_FLAGS = 160, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, /* autogen autogen priority:low */
+    REMOTE_PROC_CPU_BASELINE = 162, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_ABORT_JOB = 164, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_WIPE = 165, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 166, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_EVENTS_REGISTER_ANY = 167, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_EVENTS_DEREGISTER_ANY = 168, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_REBOOT = 169, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE = 170, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_EVENT_WATCHDOG = 171, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_IO_ERROR = 172, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_GRAPHICS = 173, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_UPDATE_DEVICE_FLAGS = 174, /* autogen autogen priority:low */
+    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 priority:low */
+    REMOTE_PROC_DOMAIN_HAS_MANAGED_SAVE_IMAGE = 183, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_MANAGED_SAVE_REMOVE = 184, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_CREATE_XML = 185, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_GET_XML_DESC = 186, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_NUM = 187, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_NAMES = 188, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LOOKUP_BY_NAME = 189, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_HAS_CURRENT_SNAPSHOT = 190, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_SNAPSHOT_CURRENT = 191, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_REVERT_TO_SNAPSHOT = 192, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_DELETE = 193, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_BLOCK_INFO = 194, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS = 199, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS = 200, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_OPEN_CONSOLE = 201, /* autogen autogen | readstream at 2 priority:low */
+    REMOTE_PROC_DOMAIN_IS_UPDATED = 202, /* autogen autogen priority:low */
+    REMOTE_PROC_GET_SYSINFO = 203, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_MEMORY_FLAGS = 204, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SET_BLKIO_PARAMETERS = 205, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_BLKIO_PARAMETERS = 206, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_SPEED = 207, /* autogen autogen priority:low */
+    REMOTE_PROC_STORAGE_VOL_UPLOAD = 208, /* autogen autogen | writestream at 1 priority:low */
+    REMOTE_PROC_STORAGE_VOL_DOWNLOAD = 209, /* autogen autogen | readstream at 1 priority:low */
+    REMOTE_PROC_DOMAIN_INJECT_NMI = 210, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_SCREENSHOT = 211, /* autogen autogen | readstream at 1 priority:low */
+    REMOTE_PROC_DOMAIN_GET_STATE = 212, /* skipgen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_MIGRATE_BEGIN3 = 213, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_PREPARE3 = 214, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3 = 215, /* autogen skipgen | writestream at 1 priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3 = 216, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_FINISH3 = 217, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3 = 218, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_SET_SCHEDULER_PARAMETERS_FLAGS = 219, /* autogen autogen priority:low */
+    REMOTE_PROC_INTERFACE_CHANGE_BEGIN = 220, /* autogen autogen priority:high */
+
+    REMOTE_PROC_INTERFACE_CHANGE_COMMIT = 221, /* autogen autogen priority:high */
+    REMOTE_PROC_INTERFACE_CHANGE_ROLLBACK = 222, /* autogen autogen priority:high */
+    REMOTE_PROC_DOMAIN_GET_SCHEDULER_PARAMETERS_FLAGS = 223, /* skipgen autogen priority:low */
+    REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR = 224, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_PIN_VCPU_FLAGS = 225, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SEND_KEY = 226, /* autogen autogen priority:low */
+    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 priority:low */
+
+    REMOTE_PROC_DOMAIN_UNDEFINE_FLAGS = 231, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SAVE_FLAGS = 232, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_RESTORE_FLAGS = 233, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_DESTROY_FLAGS = 234, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SAVE_IMAGE_GET_XML_DESC = 235, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_SAVE_IMAGE_DEFINE_XML = 236, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_BLOCK_JOB_ABORT = 237, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_GET_BLOCK_JOB_INFO = 238, /* skipgen skipgen priority:low */
+    REMOTE_PROC_DOMAIN_BLOCK_JOB_SET_SPEED = 239, /* autogen autogen priority:low */
+    REMOTE_PROC_DOMAIN_BLOCK_PULL = 240, /* autogen autogen priority:low */
+
+    REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB = 241 /* skipgen skipgen priority:low */
 
     /*
      * 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.
      *
      * 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..1ca3bc0 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 = $4;
 
             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..ab964e3 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,32 @@ 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);
+        if (prog)
+            virNetServerProgramFree(prog);
+    }
     virNetServerUnlock(srv);
 
     return ret;
@@ -274,6 +281,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 +298,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




More information about the libvir-list mailing list