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

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



On Mon, Sep 05, 2011 at 02:36:13PM +0200, Michal Privoznik wrote:
> 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;
>  

  Okay, the suggesting from Dan are in, ACK,

  please push :)

Daniel

-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel veillard com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/


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