[Spice-devel] [PATCH] fix for not clearing the cursor ring when the primary surface is destroyed

Yonit Halperin yhalperi at redhat.com
Wed Jun 23 06:32:12 PDT 2010


fixes a crash in qxl_soft_reset
---
 server/red_worker.c |   85 ++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 71 insertions(+), 14 deletions(-)

diff --git a/server/red_worker.c b/server/red_worker.c
index b9ada15..9bd551c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1043,6 +1043,7 @@ static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawabl
 static void reset_rate(StreamAgent *stream_agent);
 static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
 static inline int _stride_is_extra(SpiceBitmap *bitmap);
+static void red_disconnect_cursor(RedChannel *channel);
 
 #ifdef DUMP_BITMAP
 static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
@@ -4978,13 +4979,15 @@ static inline uint64_t red_now()
     return time.tv_sec * 1000000000 + time.tv_nsec;
 }
 
-static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size)
+static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
 {
     QXLCommandExt ext_cmd;
     int n = 0;
 
+    *ring_is_empty = FALSE;
     while (!worker->cursor_channel || worker->cursor_channel->base.pipe_size <= max_pipe_size) {
         if (!worker->qxl->st->qif->get_cursor_command(worker->qxl, &ext_cmd)) {
+            *ring_is_empty = TRUE;
             if (worker->repoll_cursor_ring < CMD_RING_POLL_RETRIES) {
                 worker->repoll_cursor_ring++;
                 worker->epoll_timeout = MIN(worker->epoll_timeout, CMD_RING_POLL_TIMEOUT);
@@ -5014,14 +5017,16 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size)
     return n;
 }
 
-static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size)
+static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
 {
     QXLCommandExt ext_cmd;
     int n = 0;
     uint64_t start = red_now();
-
+    
+    *ring_is_empty = FALSE;
     while (!worker->display_channel || worker->display_channel->base.pipe_size <= max_pipe_size) {
         if (!worker->qxl->st->qif->get_command(worker->qxl, &ext_cmd)) {
+            *ring_is_empty = TRUE;;
             if (worker->repoll_cmd_ring < CMD_RING_POLL_RETRIES) {
                 worker->repoll_cmd_ring++;
                 worker->epoll_timeout = MIN(worker->epoll_timeout, CMD_RING_POLL_TIMEOUT);
@@ -9981,17 +9986,18 @@ static inline void flush_display_commands(RedWorker *worker)
 {
     for (;;) {
         uint64_t end_time;
+        int ring_is_empty;
 
-        red_process_commands(worker, MAX_PIPE_SIZE);
-        if (!worker->qxl->st->qif->has_command(worker->qxl)) {
+        red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty);
+        if (ring_is_empty) {
             break;
         }
 
-        while (red_process_commands(worker, MAX_PIPE_SIZE)) {
+        while (red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
             display_channel_push(worker);
         }
 
-        if (!worker->qxl->st->qif->has_command(worker->qxl)) {
+        if (ring_is_empty) {
             break;
         }
         end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10;
@@ -10008,7 +10014,7 @@ static inline void flush_display_commands(RedWorker *worker)
             red_send_data(channel, NULL);
             if (red_now() >= end_time) {
                 red_printf("update timeout");
-                red_disconnect_display((RedChannel *)worker->display_channel);
+                red_disconnect_display(channel);
             } else {
                 sleep_count++;
                 usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
@@ -10018,6 +10024,54 @@ static inline void flush_display_commands(RedWorker *worker)
     }
 }
 
+static inline void flush_cursor_commands(RedWorker *worker)
+{
+    for (;;) {
+        uint64_t end_time;
+        int ring_is_empty = FALSE;
+
+        red_process_cursor(worker, MAX_PIPE_SIZE, &ring_is_empty);
+        if (ring_is_empty) {
+            break;
+        }
+
+        while (red_process_cursor(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
+            cursor_channel_push(worker);
+        }
+
+        if (ring_is_empty) {
+            break;
+        }
+        end_time = red_now() + DISPLAY_CLIENT_TIMEOUT * 10;
+        int sleep_count = 0;
+        for (;;) {
+            cursor_channel_push(worker);
+            if (!worker->cursor_channel ||
+                                        worker->cursor_channel->base.pipe_size <= MAX_PIPE_SIZE) {
+                break;
+            }
+            RedChannel *channel = (RedChannel *)worker->cursor_channel;
+            red_ref_channel(channel);
+            red_receive(channel);
+            red_send_data(channel, NULL);
+            if (red_now() >= end_time) {
+                red_printf("flush cursor timeout");
+                red_disconnect_cursor(channel);
+            } else {
+                sleep_count++;
+                usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
+            }
+            red_unref_channel(channel);
+        }
+    }
+}
+
+static inline void flush_all_qxl_commands(RedWorker *worker)
+{
+    flush_display_commands(worker);
+    flush_cursor_commands(worker);
+}
+
 static inline void red_flush_surface_pipe(RedWorker *worker)
 {
     if (worker->display_channel) {
@@ -10929,8 +10983,9 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
 
     ASSERT(surface_id == 0);
+    
+    flush_all_qxl_commands(worker);
 
-    flush_display_commands(worker);
     if (worker->surfaces[0].context.canvas) {
         destroy_surface_wait(worker, 0);
     }
@@ -10944,7 +10999,7 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     int i;
     RedWorkerMessage message;
 
-    flush_display_commands(worker);
+    flush_all_qxl_commands(worker);
     //to handle better
     if (worker->surfaces[0].context.canvas) {
         destroy_surface_wait(worker, 0);
@@ -11050,7 +11105,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
         ASSERT(!worker->cursor_channel->base.send_data.item);
     }
 
-    flush_display_commands(worker);
+    flush_all_qxl_commands(worker);
     destroy_surface_wait(worker, 0);
     red_destroy_surface(worker, 0);
     ASSERT(ring_is_empty(&worker->streams));
@@ -11069,6 +11124,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
 {
     RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
     RedWorkerMessage message;
+    int ring_is_empty;
 
     read_message(worker->channel, &message);
 
@@ -11082,7 +11138,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         break;
     case RED_WORKER_MESSAGE_OOM:
         ASSERT(worker->running);
-        while (red_process_commands(worker, MAX_PIPE_SIZE)) {
+        while (red_process_commands(worker, MAX_PIPE_SIZE, &ring_is_empty)) {
             display_channel_push(worker);
         }
         if (worker->qxl->st->qif->flush_resources(worker->qxl) == 0) {
@@ -11439,8 +11495,9 @@ void *red_worker_main(void *arg)
         }
 
         if (worker.running) {
-            red_process_cursor(&worker, MAX_PIPE_SIZE);
-            red_process_commands(&worker, MAX_PIPE_SIZE);
+            int ring_is_empty;
+            red_process_cursor(&worker, MAX_PIPE_SIZE, &ring_is_empty);
+            red_process_commands(&worker, MAX_PIPE_SIZE, &ring_is_empty);
         }
         red_push(&worker);
     }
-- 
1.6.6.1



More information about the Spice-devel mailing list