[Spice-devel] [PATCH v3 06/10] server: move three functions to red_channel

Alon Levy alevy at redhat.com
Tue Aug 13 00:47:25 PDT 2013


Three blocking functions, one was split to leave the display channel
specific referencing of the DrawablePipeItem being sent inside
red_worker, but the rest (most) of the timeout logic was moved to
red_channel, including the associated constants.

Moved functions:
red_channel_client_wait_pipe_item_sent
red_wait_outgoing_item
red_wait_all_sent

Introduces red_time.h & red_time.c for a small helper function dealing
with time.h
---
 server/red_channel.c | 106 ++++++++++++++++++++++++++++++++++++++++++++
 server/red_channel.h |  10 +++++
 server/red_time.c    |   1 +
 server/red_time.h    |  15 +++++++
 server/red_worker.c  | 121 +--------------------------------------------------
 5 files changed, 134 insertions(+), 119 deletions(-)
 create mode 100644 server/red_time.c
 create mode 100644 server/red_time.h

diff --git a/server/red_channel.c b/server/red_channel.c
index d565634..d0b979e 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -41,6 +41,7 @@
 #include "red_channel.h"
 #include "reds.h"
 #include "main_dispatcher.h"
+#include "red_time.h"
 
 typedef struct EmptyMsgPipeItem {
     PipeItem base;
@@ -50,6 +51,12 @@ typedef struct EmptyMsgPipeItem {
 #define PING_TEST_TIMEOUT_MS 15000
 #define PING_TEST_IDLE_NET_TIMEOUT_MS 100
 
+#define DETACH_TIMEOUT 15000000000ULL //nano
+#define DETACH_SLEEP_DURATION 10000 //micro
+
+#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano
+#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
+
 enum QosPingState {
     PING_STATE_NONE,
     PING_STATE_TIMER,
@@ -2195,3 +2202,102 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel)
     }
     return sum;
 }
+
+void red_wait_outgoing_item(RedChannelClient *rcc)
+{
+    uint64_t end_time;
+    int blocked;
+
+    if (!red_channel_client_blocked(rcc)) {
+        return;
+    }
+    end_time = red_now() + DETACH_TIMEOUT;
+    spice_info("blocked");
+
+    do {
+        usleep(DETACH_SLEEP_DURATION);
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+    } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
+
+    if (blocked) {
+        spice_warning("timeout");
+        // TODO - shutting down the socket but we still need to trigger
+        // disconnection. Right now we wait for main channel to error for that.
+        red_channel_client_shutdown(rcc);
+    } else {
+        spice_assert(red_channel_client_no_item_being_sent(rcc));
+    }
+}
+
+/* TODO: more evil sync stuff. anything with the word wait in it's name. */
+void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
+                                            PipeItem *item)
+{
+    uint64_t end_time;
+    int item_in_pipe;
+
+    spice_info(NULL);
+
+    end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
+
+    rcc->channel->channel_cbs.hold_item(rcc, item);
+
+    if (red_channel_client_blocked(rcc)) {
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+    }
+    red_channel_client_push(rcc);
+
+    while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
+        usleep(CHANNEL_PUSH_SLEEP_DURATION);
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+        red_channel_client_push(rcc);
+    }
+
+    if (item_in_pipe) {
+        spice_warning("timeout");
+        red_channel_client_disconnect(rcc);
+    } else {
+        red_wait_outgoing_item(rcc);
+    }
+    red_channel_client_release_item(rcc, item, TRUE);
+}
+
+static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
+{
+    if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) {
+        red_channel_client_shutdown(rcc);
+    } else {
+        spice_assert(red_channel_client_no_item_being_sent(rcc));
+    }
+}
+
+void red_wait_all_sent(RedChannel *channel)
+{
+    uint64_t end_time;
+    uint32_t max_pipe_size;
+    int blocked = FALSE;
+
+    end_time = red_now() + DETACH_TIMEOUT;
+
+    red_channel_push(channel);
+    while (((max_pipe_size = red_channel_max_pipe_size(channel)) ||
+           (blocked = red_channel_any_blocked(channel))) &&
+           red_now() < end_time) {
+        spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked);
+        usleep(DETACH_SLEEP_DURATION);
+        red_channel_receive(channel);
+        red_channel_send(channel);
+        red_channel_push(channel);
+    }
+
+    if (max_pipe_size || blocked) {
+        spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)",
+                       max_pipe_size, blocked);
+        red_channel_apply_clients(channel, rcc_shutdown_if_pending_send);
+    } else {
+        spice_assert(red_channel_no_item_being_sent(channel));
+    }
+}
diff --git a/server/red_channel.h b/server/red_channel.h
index 0dd73ea..b2a3a6a 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -596,4 +596,14 @@ int red_client_during_migrate_at_target(RedClient *client);
 
 void red_client_migrate(RedClient *client);
 
+/* blocking function */
+void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
+                                            PipeItem *item);
+
+/* blocking function */
+void red_wait_outgoing_item(RedChannelClient *rcc);
+
+/* blocking function */
+void red_wait_all_sent(RedChannel *channel);
+
 #endif
diff --git a/server/red_time.c b/server/red_time.c
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/server/red_time.c
@@ -0,0 +1 @@
+
diff --git a/server/red_time.h b/server/red_time.h
new file mode 100644
index 0000000..ffa97f2
--- /dev/null
+++ b/server/red_time.h
@@ -0,0 +1,15 @@
+#ifndef H_RED_TIME
+#define H_RED_TIME
+
+#include <time.h>
+
+static inline uint64_t red_now(void)
+{
+    struct timespec time;
+
+    clock_gettime(CLOCK_MONOTONIC, &time);
+
+    return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
+}
+
+#endif
diff --git a/server/red_worker.c b/server/red_worker.c
index 3b9c5b0..0e86cff 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -83,6 +83,7 @@
 #include "spice_timer_queue.h"
 #include "main_dispatcher.h"
 #include "spice_server_utils.h"
+#include "red_time.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -103,12 +104,6 @@
 #define CMD_RING_POLL_TIMEOUT 10 //milli
 #define CMD_RING_POLL_RETRIES 200
 
-#define DETACH_TIMEOUT 15000000000ULL //nano
-#define DETACH_SLEEP_DURATION 10000 //micro
-
-#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano
-#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
-
 #define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
 #define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
 #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
@@ -1104,10 +1099,8 @@ static void cursor_channel_client_release_item_before_push(CursorChannelClient *
                                                            PipeItem *item);
 static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc,
                                                           PipeItem *item);
-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
 
 static void red_push_monitors_config(DisplayChannelClient *dcc);
-static inline uint64_t red_now(void);
 
 /*
  * Macros to make iterating over stuff easier
@@ -2095,12 +2088,10 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int
     }
 
     if (item) {
-        red_wait_pipe_item_sent(&dcc->common.base, item);
+        red_channel_client_wait_pipe_item_sent(&dcc->common.base, item);
     }
 }
 
-static void red_wait_outgoing_item(RedChannelClient *rcc);
-
 static void red_clear_surface_drawables_from_pipes(RedWorker *worker, int surface_id,
     int force, int wait_for_outgoing_item)
 {
@@ -5086,15 +5077,6 @@ static void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint
     red_release_cursor(worker, cursor_item);
 }
 
-static inline uint64_t red_now(void)
-{
-    struct timespec time;
-
-    clock_gettime(CLOCK_MONOTONIC, &time);
-
-    return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
-}
-
 static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
 {
     QXLCommandExt ext_cmd;
@@ -10986,105 +10968,6 @@ typedef struct __attribute__ ((__packed__)) CursorData {
     SpiceCursor _cursor;
 } CursorData;
 
-static void red_wait_outgoing_item(RedChannelClient *rcc)
-{
-    uint64_t end_time;
-    int blocked;
-
-    if (!red_channel_client_blocked(rcc)) {
-        return;
-    }
-    end_time = red_now() + DETACH_TIMEOUT;
-    spice_info("blocked");
-
-    do {
-        usleep(DETACH_SLEEP_DURATION);
-        red_channel_client_receive(rcc);
-        red_channel_client_send(rcc);
-    } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
-
-    if (blocked) {
-        spice_warning("timeout");
-        // TODO - shutting down the socket but we still need to trigger
-        // disconnection. Right now we wait for main channel to error for that.
-        red_channel_client_shutdown(rcc);
-    } else {
-        spice_assert(red_channel_client_no_item_being_sent(rcc));
-    }
-}
-
-static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
-{
-    if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) {
-        red_channel_client_shutdown(rcc);
-    } else {
-        spice_assert(red_channel_client_no_item_being_sent(rcc));
-    }
-}
-
-static void red_wait_all_sent(RedChannel *channel)
-{
-    uint64_t end_time;
-    uint32_t max_pipe_size;
-    int blocked = FALSE;
-
-    end_time = red_now() + DETACH_TIMEOUT;
-
-    red_channel_push(channel);
-    while (((max_pipe_size = red_channel_max_pipe_size(channel)) ||
-           (blocked = red_channel_any_blocked(channel))) &&
-           red_now() < end_time) {
-        spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked);
-        usleep(DETACH_SLEEP_DURATION);
-        red_channel_receive(channel);
-        red_channel_send(channel);
-        red_channel_push(channel);
-    }
-
-    if (max_pipe_size || blocked) {
-        spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)",
-                       max_pipe_size, blocked);
-        red_channel_apply_clients(channel, rcc_shutdown_if_pending_send);
-    } else {
-        spice_assert(red_channel_no_item_being_sent(channel));
-    }
-}
-
-/* TODO: more evil sync stuff. anything with the word wait in it's name. */
-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item)
-{
-    DrawablePipeItem *dpi;
-    uint64_t end_time;
-    int item_in_pipe;
-
-    spice_info(NULL);
-    dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
-    ref_drawable_pipe_item(dpi);
-
-    end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
-
-    if (red_channel_client_blocked(rcc)) {
-        red_channel_client_receive(rcc);
-        red_channel_client_send(rcc);
-    }
-    red_channel_client_push(rcc);
-
-    while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
-        usleep(CHANNEL_PUSH_SLEEP_DURATION);
-        red_channel_client_receive(rcc);
-        red_channel_client_send(rcc);
-        red_channel_client_push(rcc);
-    }
-
-    if (item_in_pipe) {
-        spice_warning("timeout");
-        red_channel_client_disconnect(rcc);
-    } else {
-        red_wait_outgoing_item(rcc);
-    }
-    put_drawable_pipe_item(dpi);
-}
-
 static void surface_dirty_region_to_rects(RedSurface *surface,
                                           QXLRect *qxl_dirty_rects,
                                           uint32_t num_dirty_rects,
-- 
1.8.3.1



More information about the Spice-devel mailing list