qemu调用spice库添加memslot

1、qemu中的spice-display.c添加memslot
void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
                            qxl_async_io async)
{
    trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id,memslot->virt_start, memslot->virt_end,async);
    if (async != QXL_SYNC) {
        spice_qxl_add_memslot_async(&ssd->qxl, memslot, (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, QXL_IO_MEMSLOT_ADD_ASYNC));
    } else {
        spice_qxl_add_memslot(&ssd->qxl, memslot);
    }
}
2、spice server中的red-qxl.c声明并实现
SPICE_GNUC_VISIBLE
void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *mem_slot)
{
    RedWorkerMessageAddMemslot payload;
    payload.mem_slot = *mem_slot;
    instance->st->dispatcher->send_message(RED_WORKER_MESSAGE_ADD_MEMSLOT, &payload);
}

SPICE_GNUC_VISIBLE
void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *mem_slot, uint64_t cookie)
{
    RedWorkerMessageAddMemslotAsync payload;
    RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
    payload.base.cookie = cookie;
    payload.mem_slot = *mem_slot;
    instance->st->dispatcher->send_message(message, &payload);
}
3、dispatcher调度消息并调用回调函数
dispatcher->register_handler(RED_WORKER_MESSAGE_ADD_MEMSLOT,
                                 handle_dev_add_memslot,
                                 sizeof(RedWorkerMessageAddMemslot),
                                 true);
dispatcher->register_handler(RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
                                 handle_dev_add_memslot_async,
                                 sizeof(RedWorkerMessageAddMemslotAsync),
                                 false);
4、添加memslot数据
static void handle_dev_add_memslot(void *opaque, void *payload)
{
    auto worker = (RedWorker*) opaque;
    auto msg = (RedWorkerMessageAddMemslot*) payload;
    QXLDevMemSlot mem_slot = msg->mem_slot;
    memslot_info_add_slot(&worker->mem_slots, mem_slot.slot_group_id, mem_slot.slot_id,
                          mem_slot.addr_delta, mem_slot.virt_start, mem_slot.virt_end,
                          mem_slot.generation);
}

static void handle_dev_add_memslot_async(void *opaque, void *payload)
{
    auto msg = (RedWorkerMessageAddMemslotAsync*) payload;
    auto worker = (RedWorker*) opaque;
    dev_add_memslot(worker, msg->mem_slot);
    red_qxl_async_complete(worker->qxl, msg->base.cookie);
}
其中,异步调用的函数dev_add_memslot
static void dev_add_memslot(RedWorker *worker, QXLDevMemSlot mem_slot)
{
    memslot_info_add_slot(&worker->mem_slots, mem_slot.slot_group_id, mem_slot.slot_id,
                          mem_slot.addr_delta, mem_slot.virt_start, mem_slot.virt_end,
                          mem_slot.generation);
}
5、最终加入到RedMemSlotInfo的mem_slots二维数组中
void memslot_info_add_slot(RedMemSlotInfo *info, uint32_t slot_group_id, uint32_t slot_id,
                           uintptr_t addr_delta, uintptr_t virt_start, uintptr_t virt_end,
                           uint32_t generation)
{
    spice_assert(info->num_memslots_groups > slot_group_id);
    spice_assert(info->num_memslots > slot_id);
    info->mem_slots[slot_group_id][slot_id].address_delta = addr_delta;
    info->mem_slots[slot_group_id][slot_id].virt_start_addr = virt_start;
    info->mem_slots[slot_group_id][slot_id].virt_end_addr = virt_end;
    info->mem_slots[slot_group_id][slot_id].generation = generation;
}
6、red_qxl_async_complete异步调用返回
void red_qxl_async_complete(QXLInstance *qxl, uint64_t cookie)
{
    QXLInterface *qxl_interface = qxl_get_interface(qxl);
    qxl_interface->async_complete(qxl, cookie);
}
7、qemu中spice-display.c初始化QXLInterface接口异步完成函数
static const QXLInterface dpy_interface = {
    .base.type               = SPICE_INTERFACE_QXL,
    .base.description        = "qemu simple display",
    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
#if SPICE_HAS_ATTACHED_WORKER
    .attached_worker         = interface_attached_worker,
#else
    .attache_worker          = interface_attach_worker,
#endif
    .set_compression_level   = interface_set_compression_level,
    .get_init_info           = interface_get_init_info,

    /* the callbacks below are called from spice server thread context */
    .get_command             = interface_get_command,
    .req_cmd_notification    = interface_req_cmd_notification,
    .release_resource        = interface_release_resource,
    .get_cursor_command      = interface_get_cursor_command,
    .req_cursor_notification = interface_req_cursor_notification,
    .notify_update           = interface_notify_update,
    .flush_resources         = interface_flush_resources,
    .async_complete          = interface_async_complete,
    .update_area_complete    = interface_update_area_complete,
    .set_client_capabilities = interface_set_client_capabilities,
    .client_monitors_config  = interface_client_monitors_config,
};
8、qemu中spice-display.c实现interface_async_complet,通过代码abort可以推断qemu中基本上都是sync调用,不会async调用。
/* called from spice server thread context only */
static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token)
{
    QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token;
    switch (cookie->type) {
#ifdef HAVE_SPICE_GL
    case QXL_COOKIE_TYPE_GL_DRAW_DONE:
    {
        SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
        qemu_bh_schedule(ssd->gl_unblock_bh);
        break;
    }
    case QXL_COOKIE_TYPE_IO:
        if (cookie->io == QXL_IO_MONITORS_CONFIG_ASYNC) {
            g_free(cookie->u.data);
        }
        break;
#endif
    default:
        /* should never be called, used in qxl native mode only */
        fprintf(stderr, "%s: abort()\n", __func__);
        abort();
    }
    g_free(cookie);
}

你可能感兴趣的:(spice,spice)