[Spice-commits] 3 commits - server/red-record-qxl.c server/red-record-qxl.h server/red-worker.c

Frediano Ziglio fziglio at kemper.freedesktop.org
Thu May 26 15:30:18 UTC 2016


 server/red-record-qxl.c |  100 ++++++++++++++++++++++++++++++++++++++++++++----
 server/red-record-qxl.h |   19 +++++++--
 server/red-worker.c     |   26 ++++--------
 3 files changed, 116 insertions(+), 29 deletions(-)

New commits:
commit 8f7419a711cb0cb6c2c2f481ad88319479313cce
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Thu May 26 10:14:52 2016 +0100

    replay: rename red_record_dev_input_primary_surface_create
    
    Rename red_record_dev_input_primary_surface_create to
    red_record_primary_surface_create.
    Name is more concise and was not clear what "dev_input" was supposed
    to specify.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-record-qxl.c b/server/red-record-qxl.c
index c6cd963..39d6639 100644
--- a/server/red-record-qxl.c
+++ b/server/red-record-qxl.c
@@ -790,8 +790,9 @@ void red_record_cursor_cmd(FILE *fd, RedMemSlotInfo *slots, int group_id,
     }
 }
 
-void red_record_dev_input_primary_surface_create(RedRecord *record,
-    QXLDevSurfaceCreate* surface, uint8_t *line_0)
+void red_record_primary_surface_create(RedRecord *record,
+                                       QXLDevSurfaceCreate* surface,
+                                       uint8_t *line_0)
 {
     FILE *fd = record->fd;
 
diff --git a/server/red-record-qxl.h b/server/red-record-qxl.h
index e2a551c..ae22de2 100644
--- a/server/red-record-qxl.h
+++ b/server/red-record-qxl.h
@@ -34,9 +34,9 @@ RedRecord* red_record_new(const char *filename);
 
 void red_record_free(RedRecord *record);
 
-void red_record_dev_input_primary_surface_create(RedRecord *record,
-                                                 QXLDevSurfaceCreate *surface,
-                                                 uint8_t *line_0);
+void red_record_primary_surface_create(RedRecord *record,
+                                       QXLDevSurfaceCreate *surface,
+                                       uint8_t *line_0);
 
 void red_record_event(RedRecord *record, int what, uint32_t type, unsigned long ts);
 
diff --git a/server/red-worker.c b/server/red-worker.c
index facccb2..2684e19 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -664,8 +664,8 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
         return;
     }
     if (worker->record) {
-        red_record_dev_input_primary_surface_create(worker->record,
-                                                    &surface, line_0);
+        red_record_primary_surface_create(worker->record,
+                                          &surface, line_0);
     }
 
     if (surface.stride < 0) {
commit 82caf1402574fa05d18bf7fe93c78dc07a69305b
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Fri Aug 21 09:33:16 2015 +0100

    replay: allows to specify a filter for record output
    
    This allows compression using external programs or any type
    of filters.
    
    To use it set SPICE_WORKER_RECORD_FILTER environment to the
    filter command you want to use. The command is executed with
    g_spawn_async_with_pipes (which uses execve) so is not a shell
    command although the command is parsed using g_shell_parse_argv
    which split arguments as shell does.
    
    One easy way to use it is to just use a compressor like gzip with
    
      export SPICE_WORKER_RECORD_FILENAME=/tmp/qemu_record.gz
      export SPICE_WORKER_RECORD_FILTER=gzip
      qemu ...
    
    The filter will receive the recording on standard input and is
    supposed to write in output filename (which is the standard output).
    You can use additional arguments in SPICE_WORKER_RECORD_FILTER to
    specify for instance compression level.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-record-qxl.c b/server/red-record-qxl.c
index 5337699..c6cd963 100644
--- a/server/red-record-qxl.c
+++ b/server/red-record-qxl.c
@@ -21,6 +21,8 @@
 
 #include <stdbool.h>
 #include <inttypes.h>
+#include <fcntl.h>
+#include <glib.h>
 #include "red-worker.h"
 #include "red-common.h"
 #include "memslot.h"
@@ -834,10 +836,26 @@ void red_record_qxl_command(RedRecord *record, RedMemSlotInfo *slots,
     }
 }
 
+/**
+ * Redirects child output to the file specified
+ */
+static void child_output_setup(gpointer user_data)
+{
+    int fd = GPOINTER_TO_INT(user_data);
+
+    while (dup2(fd, STDOUT_FILENO) < 0 && errno == EINTR)
+        continue;
+    close(fd);
+
+    // make sure file is not closed calling exec()
+    fcntl(STDOUT_FILENO, F_SETFD, 0);
+}
+
 RedRecord *red_record_new(const char *filename)
 {
     static const char header[] = "SPICE_REPLAY 1\n";
 
+    const char *filter;
     FILE *f;
     RedRecord *record;
 
@@ -846,6 +864,33 @@ RedRecord *red_record_new(const char *filename)
         spice_error("failed to open recording file %s\n", filename);
     }
 
+    filter = getenv("SPICE_WORKER_RECORD_FILTER");
+    if (filter) {
+        gint argc;
+        gchar **argv = NULL;
+        GError *error = NULL;
+        GPid child_pid;
+        gboolean ret;
+        gint fd_in;
+
+        ret = g_shell_parse_argv(filter, &argc, &argv, &error);
+
+        if (ret)
+            ret = g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+                               child_output_setup, GINT_TO_POINTER(fileno(f)), &child_pid,
+                               &fd_in, NULL, NULL, &error);
+
+        g_strfreev(argv);
+        if (!ret) {
+            g_error_free(error);
+            fclose(f);
+            spice_error("failed to setup filter for replay");
+        }
+        while (dup2(fd_in, fileno(f)) < 0 && errno == EINTR)
+            continue;
+        close(fd_in);
+    }
+
     if (fwrite(header, sizeof(header)-1, 1, f) != 1) {
         spice_error("failed to write replay header");
     }
commit 751a0aeb51ad3915299a2fae3b57568bec01eb69
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Mon Aug 24 21:52:12 2015 +0100

    replay: better record encapsulation
    
    Remove global/static from red_record_qxl.c.
    Defined a structure and use it to hold record state.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-record-qxl.c b/server/red-record-qxl.c
index aa2f3e5..5337699 100644
--- a/server/red-record-qxl.c
+++ b/server/red-record-qxl.c
@@ -26,6 +26,12 @@
 #include "memslot.h"
 #include "red-parse-qxl.h"
 #include "zlib-encoder.h"
+#include "red-record-qxl.h"
+
+struct RedRecord {
+    FILE *fd;
+    unsigned int counter;
+};
 
 #if 0
 static void hexdump_qxl(RedMemSlotInfo *slots, int group_id,
@@ -782,9 +788,11 @@ void red_record_cursor_cmd(FILE *fd, RedMemSlotInfo *slots, int group_id,
     }
 }
 
-void red_record_dev_input_primary_surface_create(FILE *fd,
+void red_record_dev_input_primary_surface_create(RedRecord *record,
     QXLDevSurfaceCreate* surface, uint8_t *line_0)
 {
+    FILE *fd = record->fd;
+
     fprintf(fd, "%d %d %d %d\n", surface->width, surface->height,
         surface->stride, surface->format);
     fprintf(fd, "%d %d %d %d\n", surface->position, surface->mouse_mode,
@@ -793,22 +801,22 @@ void red_record_dev_input_primary_surface_create(FILE *fd,
         line_0);
 }
 
-void red_record_event(FILE *fd, int what, uint32_t type, unsigned long ts)
+void red_record_event(RedRecord *record, int what, uint32_t type, unsigned long ts)
 {
-    static int counter = 0;
-
     // TODO: record the size of the packet in the header. This would make
     // navigating it much faster (well, I can add an index while I'm at it..)
     // and make it trivial to get a histogram from a file.
     // But to implement that I would need some temporary buffer for each event.
     // (that can be up to VGA_FRAMEBUFFER large)
-    fprintf(fd, "event %d %d %u %lu\n", counter++, what, type, ts);
+    fprintf(record->fd, "event %u %d %u %lu\n", record->counter++, what, type, ts);
 }
 
-void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
+void red_record_qxl_command(RedRecord *record, RedMemSlotInfo *slots,
                             QXLCommandExt ext_cmd, unsigned long ts)
 {
-    red_record_event(fd, 0, ext_cmd.cmd.type, ts);
+    FILE *fd = record->fd;
+
+    red_record_event(record, 0, ext_cmd.cmd.type, ts);
 
     switch (ext_cmd.cmd.type) {
     case QXL_CMD_DRAW:
@@ -825,3 +833,33 @@ void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
         break;
     }
 }
+
+RedRecord *red_record_new(const char *filename)
+{
+    static const char header[] = "SPICE_REPLAY 1\n";
+
+    FILE *f;
+    RedRecord *record;
+
+    f = fopen(filename, "w+");
+    if (!f) {
+        spice_error("failed to open recording file %s\n", filename);
+    }
+
+    if (fwrite(header, sizeof(header)-1, 1, f) != 1) {
+        spice_error("failed to write replay header");
+    }
+
+    record = g_new(RedRecord, 1);
+    record->fd = f;
+    record->counter = 0;
+    return record;
+}
+
+void red_record_free(RedRecord *record)
+{
+    if (record) {
+        fclose(record->fd);
+        g_free(record);
+    }
+}
diff --git a/server/red-record-qxl.h b/server/red-record-qxl.h
index d5eaaa0..e2a551c 100644
--- a/server/red-record-qxl.h
+++ b/server/red-record-qxl.h
@@ -24,12 +24,23 @@
 #include "red-common.h"
 #include "memslot.h"
 
-void red_record_dev_input_primary_surface_create(
-                           FILE *fd, QXLDevSurfaceCreate *surface, uint8_t *line_0);
+typedef struct RedRecord RedRecord;
 
-void red_record_event(FILE *fd, int what, uint32_t type, unsigned long ts);
+/**
+ * Create a new structure to handle recording.
+ * This function never returns NULL.
+ */
+RedRecord* red_record_new(const char *filename);
 
-void red_record_qxl_command(FILE *fd, RedMemSlotInfo *slots,
+void red_record_free(RedRecord *record);
+
+void red_record_dev_input_primary_surface_create(RedRecord *record,
+                                                 QXLDevSurfaceCreate *surface,
+                                                 uint8_t *line_0);
+
+void red_record_event(RedRecord *record, int what, uint32_t type, unsigned long ts);
+
+void red_record_qxl_command(RedRecord *record, RedMemSlotInfo *slots,
                             QXLCommandExt ext_cmd, unsigned long ts);
 
 #endif
diff --git a/server/red-worker.c b/server/red-worker.c
index 3603025..facccb2 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -88,7 +88,7 @@ struct RedWorker {
 
     int driver_cap_monitors_config;
 
-    FILE *record_fd;
+    RedRecord *record;
 };
 
 static RedsState* red_worker_get_server(RedWorker *worker);
@@ -215,8 +215,8 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
             return n;
         }
 
-        if (worker->record_fd)
-            red_record_qxl_command(worker->record_fd, &worker->mem_slots, ext_cmd,
+        if (worker->record)
+            red_record_qxl_command(worker->record, &worker->mem_slots, ext_cmd,
                                    stat_now(CLOCK_MONOTONIC));
 
         stat_inc_counter(reds, worker->command_counter, 1);
@@ -663,9 +663,9 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
     if (error) {
         return;
     }
-    if (worker->record_fd) {
-        red_record_dev_input_primary_surface_create(worker->record_fd,
-                    &surface, line_0);
+    if (worker->record) {
+        red_record_dev_input_primary_surface_create(worker->record,
+                                                    &surface, line_0);
     }
 
     if (surface.stride < 0) {
@@ -1176,7 +1176,7 @@ static void worker_dispatcher_record(void *opaque, uint32_t message_type, void *
 {
     RedWorker *worker = opaque;
 
-    red_record_event(worker->record_fd, 1, message_type, stat_now(CLOCK_MONOTONIC));
+    red_record_event(worker->record, 1, message_type, stat_now(CLOCK_MONOTONIC));
 }
 
 static void register_callbacks(Dispatcher *dispatcher)
@@ -1456,22 +1456,14 @@ RedWorker* red_worker_new(QXLInstance *qxl,
 
     record_filename = getenv("SPICE_WORKER_RECORD_FILENAME");
     if (record_filename) {
-        static const char header[] = "SPICE_REPLAY 1\n";
-
-        worker->record_fd = fopen(record_filename, "w+");
-        if (worker->record_fd == NULL) {
-            spice_error("failed to open recording file %s\n", record_filename);
-        }
-        if (fwrite(header, sizeof(header)-1, 1, worker->record_fd) != 1) {
-            spice_error("failed to write replay header");
-        }
+        worker->record = red_record_new(record_filename);
     }
     dispatcher = red_qxl_get_dispatcher(qxl);
     dispatcher_set_opaque(dispatcher, worker);
 
     worker->qxl = qxl;
     register_callbacks(dispatcher);
-    if (worker->record_fd) {
+    if (worker->record) {
         dispatcher_register_universal_handler(dispatcher, worker_dispatcher_record);
     }
 


More information about the Spice-commits mailing list