[Spice-devel] [PATCH 28/35] vdi port: redesign.

Gerd Hoffmann kraxel at redhat.com
Wed May 12 04:32:22 PDT 2010


Pretty straight forward.

One thing we should think about is if and how we are going to deal
with multiple ports here?

With vdi port using virtio-serial as communication channel to the guest
it is easy to have multiple ports, i.e. we might want to use a second
instance for clipboard data.  That implies that we need support for
multiple channels all the way through the stack ...
---
 server/reds.c         |   91 +++++++++++++++++++++++++++----------------------
 server/vd_interface.h |   33 +++++++++---------
 2 files changed, 67 insertions(+), 57 deletions(-)

diff --git a/server/reds.c b/server/reds.c
index 2d03029..dac5df0 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -59,7 +59,7 @@ static MigrationInterface *mig = NULL;
 static SpiceKbdInstance *keyboard = NULL;
 static SpiceMouseInstance *mouse = NULL;
 static SpiceTabletInstance *tablet = NULL;
-static VDIPortInterface *vdagent = NULL;
+static SpiceVDIPortInstance *vdagent = NULL;
 
 #define MIGRATION_NOTIFY_SPICE_KEY "spice_mig_ext"
 
@@ -176,8 +176,7 @@ typedef struct __attribute__ ((__packed__)) VDIChunkHeader {
 } VDIChunkHeader;
 
 typedef struct VDIPortState {
-    VDIPortPlug plug;
-    VDObjectRef plug_ref;
+    int connected;
     uint32_t plug_generation;
 
     uint32_t num_tokens;
@@ -743,10 +742,12 @@ static void reds_disconnect()
     reds->disconnecting = TRUE;
     reds_reset_outgoing();
 
-    if (reds->agent_state.plug_ref != INVALID_VD_OBJECT_REF) {
-        ASSERT(vdagent);
-        vdagent->unplug(vdagent, reds->agent_state.plug_ref);
-        reds->agent_state.plug_ref = INVALID_VD_OBJECT_REF;
+    if (reds->agent_state.connected) {
+        SpiceVDIPortInterface *sif;
+        sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
+        reds->agent_state.connected = 0;
+        if (sif->state)
+            sif->state(vdagent, reds->agent_state.connected);
         reds_reset_vdp();
     }
 
@@ -1122,18 +1123,21 @@ static void reds_send_agent_disconnected()
 
 static void reds_agent_remove()
 {
-    VDIPortInterface *interface = vdagent;
+    SpiceVDIPortInstance *sin = vdagent;
+    SpiceVDIPortInterface *sif;
 
     vdagent = NULL;
     reds_update_mouse_mode();
 
-    if (!reds->peer || !interface) {
+    if (!reds->peer || !sin) {
         return;
     }
 
-    ASSERT(reds->agent_state.plug_ref != INVALID_VD_OBJECT_REF);
-    interface->unplug(interface, reds->agent_state.plug_ref);
-    reds->agent_state.plug_ref = INVALID_VD_OBJECT_REF;
+    ASSERT(reds->agent_state.connected)
+    sif = SPICE_CONTAINEROF(sin->base.sif, SpiceVDIPortInterface, base);
+    reds->agent_state.connected = 0;
+    if (sif->state)
+        sif->state(sin, reds->agent_state.connected);
 
     if (reds->mig_target) {
         return;
@@ -1164,21 +1168,23 @@ static void reds_send_tokens()
 static int write_to_vdi_port()
 {
     VDIPortState *state = &reds->agent_state;
+    SpiceVDIPortInterface *sif;
     RingItem *ring_item;
     VDIPortBuf *buf;
     int total = 0;
     int n;
 
-    if (reds->agent_state.plug_ref == INVALID_VD_OBJECT_REF || reds->mig_target) {
+    if (!reds->agent_state.connected || reds->mig_target) {
         return 0;
     }
 
+    sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
     for (;;) {
         if (!(ring_item = ring_get_tail(&state->write_queue))) {
             break;
         }
         buf = (VDIPortBuf *)ring_item;
-        n = vdagent->write(vdagent, state->plug_ref, buf->now, buf->write_len);
+        n = sif->write(vdagent, buf->now, buf->write_len);
         if (n == 0) {
             break;
         }
@@ -1217,18 +1223,20 @@ static void dispatch_vdi_port_data(int port, VDIReadBuf *buf)
 static int read_from_vdi_port()
 {
     VDIPortState *state = &reds->agent_state;
+    SpiceVDIPortInterface *sif;
     VDIReadBuf *dispatch_buf;
     int total = 0;
     int n;
 
-    if (reds->mig_target) {
+    if (!reds->agent_state.connected || reds->mig_target) {
         return 0;
     }
 
-    while (reds->agent_state.plug_ref != INVALID_VD_OBJECT_REF) {
+    sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
+    for (;;) {
         switch (state->read_state) {
         case VDI_PORT_READ_STATE_READ_HADER:
-            n = vdagent->read(vdagent, state->plug_ref, state->recive_pos, state->recive_len);
+            n = sif->read(vdagent, state->recive_pos, state->recive_len);
             if (!n) {
                 return total;
             }
@@ -1262,7 +1270,7 @@ static int read_from_vdi_port()
             state->read_state = VDI_PORT_READ_STATE_READ_DATA;
         }
         case VDI_PORT_READ_STATE_READ_DATA:
-            n = vdagent->read(vdagent, state->plug_ref, state->recive_pos, state->recive_len);
+            n = sif->read(vdagent, state->recive_pos, state->recive_len);
             if (!n) {
                 return total;
             }
@@ -1287,7 +1295,7 @@ static int read_from_vdi_port()
     return total;
 }
 
-static void reds_agent_wakeup(VDIPortPlug *plug)
+__visible__ void spice_server_vdi_port_wakeup(SpiceVDIPortInstance *sin)
 {
     while (write_to_vdi_port() || read_from_vdi_port());
 }
@@ -1385,7 +1393,7 @@ static void main_channel_send_migrate_data_item(RedsOutItem *in_item, struct iov
     item->data.serial = reds->serial;
     item->data.ping_id = reds->ping_id;
 
-    item->data.agent_connected = !!state->plug_ref;
+    item->data.agent_connected = !!state->connected;
     item->data.client_agent_started = state->client_agent_started;
     item->data.num_client_tokens = state->num_client_tokens;
     item->data.send_tokens = state->send_tokens;
@@ -1634,13 +1642,13 @@ static void main_channel_recive_migrate_data(MainMigrateData *data, uint8_t *end
 
 
     if (!data->agent_connected) {
-        if (state->plug_ref) {
+        if (state->connected) {
             reds_send_agent_connected();
         }
         return;
     }
 
-    if (state->plug_ref == INVALID_VD_OBJECT_REF) {
+    if (!state->connected) {
         reds_send_agent_disconnected();
         return;
     }
@@ -2054,10 +2062,11 @@ static void reds_handle_main_link(RedLinkInfo *link)
     reds_show_new_channel(link);
     __reds_release_link(link);
     if (vdagent) {
-        reds->agent_state.plug_ref = vdagent->plug(vdagent, &reds->agent_state.plug);
-        if (reds->agent_state.plug_ref == INVALID_VD_OBJECT_REF) {
-            PANIC("vdagent plug failed");
-        }
+        SpiceVDIPortInterface *sif;
+        sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
+        reds->agent_state.connected = 1;
+        if (sif->state)
+            sif->state(vdagent, reds->agent_state.connected);
         reds->agent_state.plug_generation++;
     }
     reds->peer->watch = core->watch_add(reds->peer->socket,
@@ -4017,16 +4026,20 @@ static void mm_timer_proc(void *opaque)
     core->timer_start(reds->mm_timer, MM_TIMER_GRANULARITY_MS);
 }
 
-static void attach_to_red_agent(VDIPortInterface *interface)
+static void attach_to_red_agent(SpiceVDIPortInstance *sin)
 {
     VDIPortState *state = &reds->agent_state;
+    SpiceVDIPortInterface *sif;
 
-    vdagent = interface;
+    vdagent = sin;
     reds_update_mouse_mode();
     if (!reds->peer) {
         return;
     }
-    state->plug_ref = vdagent->plug(vdagent, &state->plug);
+    sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceVDIPortInterface, base);
+    state->connected = 1;
+    if (sif->state)
+        sif->state(vdagent, state->connected);
     reds->agent_state.plug_generation++;
 
     if (reds->mig_target) {
@@ -4144,18 +4157,18 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
         }
         snd_attach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
 
-    } else if (strcmp(interface->type, VD_INTERFACE_VDI_PORT) == 0) {
-        red_printf("VD_INTERFACE_VDI_PORT");
+    } else if (strcmp(interface->type, SPICE_INTERFACE_VDI_PORT) == 0) {
+        red_printf("SPICE_INTERFACE_VDI_PORT");
         if (vdagent) {
             red_printf("vdi port already attached");
             return -1;
         }
-        if (interface->major_version != VD_INTERFACE_VDI_PORT_MAJOR ||
-            interface->minor_version < VD_INTERFACE_VDI_PORT_MINOR) {
+        if (interface->major_version != SPICE_INTERFACE_VDI_PORT_MAJOR ||
+            interface->minor_version < SPICE_INTERFACE_VDI_PORT_MINOR) {
             red_printf("unsuported vdi port interface");
             return -1;
         }
-        attach_to_red_agent((VDIPortInterface *)interface);
+        attach_to_red_agent(SPICE_CONTAINEROF(sin, SpiceVDIPortInstance, base));
 
     } else if (strcmp(interface->type, VD_INTERFACE_NET_WIRE) == 0) {
 #ifdef HAVE_SLIRP
@@ -4198,9 +4211,9 @@ __visible__ int spice_server_remove_interface(SpiceBaseInstance *sin)
         red_printf("remove SPICE_INTERFACE_RECORD");
         snd_detach_record(SPICE_CONTAINEROF(sin, SpiceRecordInstance, base));
 
-    } else if (strcmp(interface->type, VD_INTERFACE_VDI_PORT) == 0) {
-        red_printf("remove VD_INTERFACE_VDI_PORT");
-        if (interface == (SpiceBaseInterface *)vdagent) {
+    } else if (strcmp(interface->type, SPICE_INTERFACE_VDI_PORT) == 0) {
+        red_printf("remove SPICE_INTERFACE_VDI_PORT");
+        if (sin == &vdagent->base) {
             reds_agent_remove();
         }
 
@@ -4293,10 +4306,6 @@ static void init_vd_agent_resources()
         ring_item_init(&buf->out_item.link);
         ring_add(&reds->agent_state.read_bufs, &buf->out_item.link);
     }
-
-    state->plug.major_version = VD_INTERFACE_VDI_PORT_MAJOR;
-    state->plug.minor_version = VD_INTERFACE_VDI_PORT_MINOR;
-    state->plug.wakeup = reds_agent_wakeup;
 }
 
 const char *version_string = VERSION;
diff --git a/server/vd_interface.h b/server/vd_interface.h
index 78f0f62..0f26822 100644
--- a/server/vd_interface.h
+++ b/server/vd_interface.h
@@ -367,27 +367,28 @@ void spice_server_record_stop(SpiceRecordInstance *sin);
 uint32_t spice_server_record_get_samples(SpiceRecordInstance *sin,
                                          uint32_t *samples, uint32_t bufsize);
 
-#define VD_INTERFACE_VDI_PORT "vdi_port"
-#define VD_INTERFACE_VDI_PORT_MAJOR 1
-#define VD_INTERFACE_VDI_PORT_MINOR 1
-typedef struct VDIPortInterface VDIPortInterface;
+#define SPICE_INTERFACE_VDI_PORT "vdi_port"
+#define SPICE_INTERFACE_VDI_PORT_MAJOR 1
+#define SPICE_INTERFACE_VDI_PORT_MINOR 1
+typedef struct SpiceVDIPortInterface SpiceVDIPortInterface;
+typedef struct SpiceVDIPortInstance SpiceVDIPortInstance;
+typedef struct SpiceVDIPortState SpiceVDIPortState;
+
+struct SpiceVDIPortInterface {
+    SpiceBaseInterface base;
 
-typedef struct VDIPortPlug VDIPortPlug;
-struct VDIPortPlug {
-    uint32_t minor_version;
-    uint32_t major_version;
-    void (*wakeup)(VDIPortPlug *plug);
+    void (*state)(SpiceVDIPortInstance *sin, int connected);
+    int (*write)(SpiceVDIPortInstance *sin, const uint8_t *buf, int len);
+    int (*read)(SpiceVDIPortInstance *sin, uint8_t *buf, int len);
 };
 
-struct VDIPortInterface {
-    SpiceBaseInterface base;
-
-    VDObjectRef (*plug)(VDIPortInterface *port, VDIPortPlug* plug);
-    void (*unplug)(VDIPortInterface *port, VDObjectRef plug);
-    int (*write)(VDIPortInterface *port, VDObjectRef plug, const uint8_t *buf, int len);
-    int (*read)(VDIPortInterface *port, VDObjectRef plug, uint8_t *buf, int len);
+struct SpiceVDIPortInstance {
+    SpiceBaseInstance base;
+    SpiceVDIPortState *st;
 };
 
+void spice_server_vdi_port_wakeup(SpiceVDIPortInstance *sin);
+
 #define VD_INTERFACE_NET_WIRE "net_wire"
 #define VD_INTERFACE_NET_WIRE_MAJOR 1
 #define VD_INTERFACE_NET_WIRE_MINOR 1
-- 
1.6.6.1



More information about the Spice-devel mailing list