[Spice-devel] [PATCH spice-server 1/7] char_device.c: add ref count for write-to-device buffers

Yonit Halperin yhalperi at redhat.com
Wed Nov 21 11:42:00 PST 2012


The ref count is used in order to keep buffers that were in the write
queue and now are part of migration data, in case the char_device state
is destroyed before we complete sending the migration data.
---
 server/char_device.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
 server/char_device.h |  1 +
 2 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/server/char_device.c b/server/char_device.c
index 141ec88..1c48719 100644
--- a/server/char_device.c
+++ b/server/char_device.c
@@ -86,6 +86,14 @@ typedef struct SpiceCharDeviceMsgToClientItem {
     SpiceCharDeviceMsgToClient *msg;
 } SpiceCharDeviceMsgToClientItem;
 
+static void spice_char_device_write_buffer_free(SpiceCharDeviceWriteBuffer *buf)
+{
+    if (--buf->refs == 0) {
+        free(buf->buf);
+        free(buf);
+    }
+}
+
 static void write_buffers_queue_free(Ring *write_queue)
 {
     while (!ring_is_empty(write_queue)) {
@@ -94,18 +102,21 @@ static void write_buffers_queue_free(Ring *write_queue)
 
         ring_remove(item);
         buf = SPICE_CONTAINEROF(item, SpiceCharDeviceWriteBuffer, link);
-        free(buf->buf);
-        free(buf);
+        spice_char_device_write_buffer_free(buf);
     }
 }
 
 static void spice_char_device_write_buffer_pool_add(SpiceCharDeviceState *dev,
                                                     SpiceCharDeviceWriteBuffer *buf)
 {
-    buf->buf_used = 0;
-    buf->origin = WRITE_BUFFER_ORIGIN_NONE;
-    buf->client = NULL;
-    ring_add(&dev->write_bufs_pool, &buf->link);
+    if (buf->refs == 1) {
+        buf->buf_used = 0;
+        buf->origin = WRITE_BUFFER_ORIGIN_NONE;
+        buf->client = NULL;
+        ring_add(&dev->write_bufs_pool, &buf->link);
+    } else {
+        --buf->refs;
+    }
 }
 
 static void spice_char_device_client_send_queue_free(SpiceCharDeviceState *dev,
@@ -530,6 +541,7 @@ static SpiceCharDeviceWriteBuffer *__spice_char_device_write_buffer_get(SpiceCha
     }
 
     ret->token_price = migrated_data_tokens ? migrated_data_tokens : 1;
+    ret->refs = 1;
     return ret;
 error:
     ring_add(&dev->write_bufs_pool, &ret->link);
@@ -542,6 +554,14 @@ SpiceCharDeviceWriteBuffer *spice_char_device_write_buffer_get(SpiceCharDeviceSt
 {
    return  __spice_char_device_write_buffer_get(dev, client, size, 0);
 }
+
+static void spice_char_device_write_buffer_ref(SpiceCharDeviceWriteBuffer *write_buf)
+{
+    spice_assert(write_buf);
+
+    write_buf->refs++;
+}
+
 void spice_char_device_write_buffer_add(SpiceCharDeviceState *dev,
                                         SpiceCharDeviceWriteBuffer *write_buf)
 {
@@ -677,7 +697,7 @@ void spice_char_device_state_destroy(SpiceCharDeviceState *char_dev)
         spice_char_device_client_free(char_dev, dev_client);
     }
     char_dev->running = FALSE;
- 
+
     spice_char_device_state_unref(char_dev);
 }
 
@@ -826,6 +846,13 @@ void spice_char_device_state_migrate_data_marshall_empty(SpiceMarshaller *m)
     mig_data->connected = FALSE;
 }
 
+static void migrate_data_marshaller_write_buffer_free(uint8_t *data, void *opaque)
+{
+    SpiceCharDeviceWriteBuffer *write_buf = (SpiceCharDeviceWriteBuffer *)opaque;
+
+    spice_char_device_write_buffer_free(write_buf);
+}
+
 void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
                                                    SpiceMarshaller *m)
 {
@@ -857,8 +884,10 @@ void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
     if (dev->cur_write_buf) {
         uint32_t buf_remaining = dev->cur_write_buf->buf + dev->cur_write_buf->buf_used -
                                  dev->cur_write_buf_pos;
-
-        spice_marshaller_add_ref(m2, dev->cur_write_buf_pos, buf_remaining);
+        spice_char_device_write_buffer_ref(dev->cur_write_buf);
+        spice_marshaller_add_ref_full(m2, dev->cur_write_buf_pos, buf_remaining,
+                                      migrate_data_marshaller_write_buffer_free,
+                                      dev->cur_write_buf);
         *write_to_dev_size_ptr += buf_remaining;
         if (dev->cur_write_buf->origin == WRITE_BUFFER_ORIGIN_CLIENT) {
             spice_assert(dev->cur_write_buf->client == client_state->client);
@@ -870,7 +899,9 @@ void spice_char_device_state_migrate_data_marshall(SpiceCharDeviceState *dev,
         SpiceCharDeviceWriteBuffer *write_buf;
 
         write_buf = SPICE_CONTAINEROF(item, SpiceCharDeviceWriteBuffer, link);
-        spice_marshaller_add_ref(m2, write_buf->buf, write_buf->buf_used);
+        spice_char_device_write_buffer_ref(write_buf);
+        spice_marshaller_add_ref_full(m2, write_buf->buf, write_buf->buf_used,
+                                      migrate_data_marshaller_write_buffer_free, write_buf);
         *write_to_dev_size_ptr += write_buf->buf_used;
         if (write_buf->origin == WRITE_BUFFER_ORIGIN_CLIENT) {
             spice_assert(write_buf->client == client_state->client);
diff --git a/server/char_device.h b/server/char_device.h
index d6d75e3..8bfe4ec 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -73,6 +73,7 @@ typedef struct SpiceCharDeviceWriteBuffer {
     uint32_t buf_size;
     uint32_t buf_used;
     uint32_t token_price;
+    uint32_t refs;
 } SpiceCharDeviceWriteBuffer;
 
 typedef void SpiceCharDeviceMsgToClient;
-- 
1.7.11.7



More information about the Spice-devel mailing list