|
|
20333d |
From 2549affd7164634609ffe2796616a2195a3118a4 Mon Sep 17 00:00:00 2001
|
|
|
20333d |
From: Alon Levy <alevy@redhat.com>
|
|
|
20333d |
Date: Mon, 12 Aug 2013 15:01:42 +0300
|
|
|
20333d |
Subject: [PATCH] server: move three functions to red_channel
|
|
|
20333d |
|
|
|
20333d |
Three blocking functions, one was split to leave the display channel
|
|
|
20333d |
specific referencing of the DrawablePipeItem being sent inside
|
|
|
20333d |
red_worker, but the rest (most) of the timeout logic was moved to
|
|
|
20333d |
red_channel, including the associated constants.
|
|
|
20333d |
|
|
|
20333d |
Moved functions:
|
|
|
20333d |
red_channel_client_wait_pipe_item_sent
|
|
|
20333d |
red_wait_outgoing_item
|
|
|
20333d |
red_wait_all_sent
|
|
|
20333d |
|
|
|
20333d |
Introduces red_time.h & red_time.c for a small helper function dealing
|
|
|
20333d |
with time.h
|
|
|
20333d |
|
|
|
20333d |
https://bugzilla.redhat.com/show_bug.cgi?id=1016795
|
|
|
20333d |
Conflicts:
|
|
|
20333d |
server/red_worker.c
|
|
|
20333d |
---
|
|
|
20333d |
server/red_channel.c | 106 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
20333d |
server/red_channel.h | 10 +++++
|
|
|
20333d |
server/red_time.c | 1 +
|
|
|
20333d |
server/red_time.h | 15 +++++++
|
|
|
20333d |
server/red_worker.c | 121 +--------------------------------------------------
|
|
|
20333d |
5 files changed, 134 insertions(+), 119 deletions(-)
|
|
|
20333d |
create mode 100644 server/red_time.c
|
|
|
20333d |
create mode 100644 server/red_time.h
|
|
|
20333d |
|
|
|
20333d |
diff --git a/server/red_channel.c b/server/red_channel.c
|
|
|
20333d |
index 1a57db5..555d376 100644
|
|
|
20333d |
--- a/server/red_channel.c
|
|
|
20333d |
+++ b/server/red_channel.c
|
|
|
20333d |
@@ -38,6 +38,7 @@
|
|
|
20333d |
#include "red_channel.h"
|
|
|
20333d |
#include "reds.h"
|
|
|
20333d |
#include "main_dispatcher.h"
|
|
|
20333d |
+#include "red_time.h"
|
|
|
20333d |
|
|
|
20333d |
typedef struct EmptyMsgPipeItem {
|
|
|
20333d |
PipeItem base;
|
|
|
20333d |
@@ -47,6 +48,12 @@ typedef struct EmptyMsgPipeItem {
|
|
|
20333d |
#define PING_TEST_TIMEOUT_MS 15000
|
|
|
20333d |
#define PING_TEST_IDLE_NET_TIMEOUT_MS 100
|
|
|
20333d |
|
|
|
20333d |
+#define DETACH_TIMEOUT 15000000000ULL //nano
|
|
|
20333d |
+#define DETACH_SLEEP_DURATION 10000 //micro
|
|
|
20333d |
+
|
|
|
20333d |
+#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano
|
|
|
20333d |
+#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
|
|
|
20333d |
+
|
|
|
20333d |
enum QosPingState {
|
|
|
20333d |
PING_STATE_NONE,
|
|
|
20333d |
PING_STATE_TIMER,
|
|
|
20333d |
@@ -2183,3 +2190,102 @@ uint32_t red_channel_sum_pipes_size(RedChannel *channel)
|
|
|
20333d |
}
|
|
|
20333d |
return sum;
|
|
|
20333d |
}
|
|
|
20333d |
+
|
|
|
20333d |
+void red_wait_outgoing_item(RedChannelClient *rcc)
|
|
|
20333d |
+{
|
|
|
20333d |
+ uint64_t end_time;
|
|
|
20333d |
+ int blocked;
|
|
|
20333d |
+
|
|
|
20333d |
+ if (!red_channel_client_blocked(rcc)) {
|
|
|
20333d |
+ return;
|
|
|
20333d |
+ }
|
|
|
20333d |
+ end_time = red_now() + DETACH_TIMEOUT;
|
|
|
20333d |
+ spice_info("blocked");
|
|
|
20333d |
+
|
|
|
20333d |
+ do {
|
|
|
20333d |
+ usleep(DETACH_SLEEP_DURATION);
|
|
|
20333d |
+ red_channel_client_receive(rcc);
|
|
|
20333d |
+ red_channel_client_send(rcc);
|
|
|
20333d |
+ } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
|
|
|
20333d |
+
|
|
|
20333d |
+ if (blocked) {
|
|
|
20333d |
+ spice_warning("timeout");
|
|
|
20333d |
+ // TODO - shutting down the socket but we still need to trigger
|
|
|
20333d |
+ // disconnection. Right now we wait for main channel to error for that.
|
|
|
20333d |
+ red_channel_client_shutdown(rcc);
|
|
|
20333d |
+ } else {
|
|
|
20333d |
+ spice_assert(red_channel_client_no_item_being_sent(rcc));
|
|
|
20333d |
+ }
|
|
|
20333d |
+}
|
|
|
20333d |
+
|
|
|
20333d |
+/* TODO: more evil sync stuff. anything with the word wait in it's name. */
|
|
|
20333d |
+void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
|
|
|
20333d |
+ PipeItem *item)
|
|
|
20333d |
+{
|
|
|
20333d |
+ uint64_t end_time;
|
|
|
20333d |
+ int item_in_pipe;
|
|
|
20333d |
+
|
|
|
20333d |
+ spice_info(NULL);
|
|
|
20333d |
+
|
|
|
20333d |
+ end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
|
|
|
20333d |
+
|
|
|
20333d |
+ rcc->channel->channel_cbs.hold_item(rcc, item);
|
|
|
20333d |
+
|
|
|
20333d |
+ if (red_channel_client_blocked(rcc)) {
|
|
|
20333d |
+ red_channel_client_receive(rcc);
|
|
|
20333d |
+ red_channel_client_send(rcc);
|
|
|
20333d |
+ }
|
|
|
20333d |
+ red_channel_client_push(rcc);
|
|
|
20333d |
+
|
|
|
20333d |
+ while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
|
|
|
20333d |
+ usleep(CHANNEL_PUSH_SLEEP_DURATION);
|
|
|
20333d |
+ red_channel_client_receive(rcc);
|
|
|
20333d |
+ red_channel_client_send(rcc);
|
|
|
20333d |
+ red_channel_client_push(rcc);
|
|
|
20333d |
+ }
|
|
|
20333d |
+
|
|
|
20333d |
+ if (item_in_pipe) {
|
|
|
20333d |
+ spice_warning("timeout");
|
|
|
20333d |
+ red_channel_client_disconnect(rcc);
|
|
|
20333d |
+ } else {
|
|
|
20333d |
+ red_wait_outgoing_item(rcc);
|
|
|
20333d |
+ }
|
|
|
20333d |
+ red_channel_client_release_item(rcc, item, TRUE);
|
|
|
20333d |
+}
|
|
|
20333d |
+
|
|
|
20333d |
+static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
|
|
|
20333d |
+{
|
|
|
20333d |
+ if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) {
|
|
|
20333d |
+ red_channel_client_shutdown(rcc);
|
|
|
20333d |
+ } else {
|
|
|
20333d |
+ spice_assert(red_channel_client_no_item_being_sent(rcc));
|
|
|
20333d |
+ }
|
|
|
20333d |
+}
|
|
|
20333d |
+
|
|
|
20333d |
+void red_wait_all_sent(RedChannel *channel)
|
|
|
20333d |
+{
|
|
|
20333d |
+ uint64_t end_time;
|
|
|
20333d |
+ uint32_t max_pipe_size;
|
|
|
20333d |
+ int blocked = FALSE;
|
|
|
20333d |
+
|
|
|
20333d |
+ end_time = red_now() + DETACH_TIMEOUT;
|
|
|
20333d |
+
|
|
|
20333d |
+ red_channel_push(channel);
|
|
|
20333d |
+ while (((max_pipe_size = red_channel_max_pipe_size(channel)) ||
|
|
|
20333d |
+ (blocked = red_channel_any_blocked(channel))) &&
|
|
|
20333d |
+ red_now() < end_time) {
|
|
|
20333d |
+ spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked);
|
|
|
20333d |
+ usleep(DETACH_SLEEP_DURATION);
|
|
|
20333d |
+ red_channel_receive(channel);
|
|
|
20333d |
+ red_channel_send(channel);
|
|
|
20333d |
+ red_channel_push(channel);
|
|
|
20333d |
+ }
|
|
|
20333d |
+
|
|
|
20333d |
+ if (max_pipe_size || blocked) {
|
|
|
20333d |
+ spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)",
|
|
|
20333d |
+ max_pipe_size, blocked);
|
|
|
20333d |
+ red_channel_apply_clients(channel, rcc_shutdown_if_pending_send);
|
|
|
20333d |
+ } else {
|
|
|
20333d |
+ spice_assert(red_channel_no_item_being_sent(channel));
|
|
|
20333d |
+ }
|
|
|
20333d |
+}
|
|
|
20333d |
diff --git a/server/red_channel.h b/server/red_channel.h
|
|
|
20333d |
index 0dd73ea..b2a3a6a 100644
|
|
|
20333d |
--- a/server/red_channel.h
|
|
|
20333d |
+++ b/server/red_channel.h
|
|
|
20333d |
@@ -596,4 +596,14 @@ int red_client_during_migrate_at_target(RedClient *client);
|
|
|
20333d |
|
|
|
20333d |
void red_client_migrate(RedClient *client);
|
|
|
20333d |
|
|
|
20333d |
+/* blocking function */
|
|
|
20333d |
+void red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
|
|
|
20333d |
+ PipeItem *item);
|
|
|
20333d |
+
|
|
|
20333d |
+/* blocking function */
|
|
|
20333d |
+void red_wait_outgoing_item(RedChannelClient *rcc);
|
|
|
20333d |
+
|
|
|
20333d |
+/* blocking function */
|
|
|
20333d |
+void red_wait_all_sent(RedChannel *channel);
|
|
|
20333d |
+
|
|
|
20333d |
#endif
|
|
|
20333d |
diff --git a/server/red_time.c b/server/red_time.c
|
|
|
20333d |
new file mode 100644
|
|
|
20333d |
index 0000000..8b13789
|
|
|
20333d |
--- /dev/null
|
|
|
20333d |
+++ b/server/red_time.c
|
|
|
20333d |
@@ -0,0 +1 @@
|
|
|
20333d |
+
|
|
|
20333d |
diff --git a/server/red_time.h b/server/red_time.h
|
|
|
20333d |
new file mode 100644
|
|
|
20333d |
index 0000000..ffa97f2
|
|
|
20333d |
--- /dev/null
|
|
|
20333d |
+++ b/server/red_time.h
|
|
|
20333d |
@@ -0,0 +1,15 @@
|
|
|
20333d |
+#ifndef H_RED_TIME
|
|
|
20333d |
+#define H_RED_TIME
|
|
|
20333d |
+
|
|
|
20333d |
+#include <time.h>
|
|
|
20333d |
+
|
|
|
20333d |
+static inline uint64_t red_now(void)
|
|
|
20333d |
+{
|
|
|
20333d |
+ struct timespec time;
|
|
|
20333d |
+
|
|
|
20333d |
+ clock_gettime(CLOCK_MONOTONIC, &time);
|
|
|
20333d |
+
|
|
|
20333d |
+ return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
|
|
|
20333d |
+}
|
|
|
20333d |
+
|
|
|
20333d |
+#endif
|
|
|
20333d |
diff --git a/server/red_worker.c b/server/red_worker.c
|
|
|
20333d |
index a4f0663..b3a957e 100644
|
|
|
20333d |
--- a/server/red_worker.c
|
|
|
20333d |
+++ b/server/red_worker.c
|
|
|
20333d |
@@ -82,6 +82,7 @@
|
|
|
20333d |
#include "migration_protocol.h"
|
|
|
20333d |
#include "spice_timer_queue.h"
|
|
|
20333d |
#include "main_dispatcher.h"
|
|
|
20333d |
+#include "red_time.h"
|
|
|
20333d |
|
|
|
20333d |
//#define COMPRESS_STAT
|
|
|
20333d |
//#define DUMP_BITMAP
|
|
|
20333d |
@@ -97,12 +98,6 @@
|
|
|
20333d |
#define CMD_RING_POLL_TIMEOUT 10 //milli
|
|
|
20333d |
#define CMD_RING_POLL_RETRIES 200
|
|
|
20333d |
|
|
|
20333d |
-#define DETACH_TIMEOUT 15000000000ULL //nano
|
|
|
20333d |
-#define DETACH_SLEEP_DURATION 10000 //micro
|
|
|
20333d |
-
|
|
|
20333d |
-#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano
|
|
|
20333d |
-#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro
|
|
|
20333d |
-
|
|
|
20333d |
#define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
|
|
|
20333d |
#define DISPLAY_CLIENT_MIGRATE_DATA_TIMEOUT 10000000000ULL //nano, 10 sec
|
|
|
20333d |
#define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro
|
|
|
20333d |
@@ -1098,14 +1093,12 @@ static void cursor_channel_client_release_item_before_push(CursorChannelClient *
|
|
|
20333d |
PipeItem *item);
|
|
|
20333d |
static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc,
|
|
|
20333d |
PipeItem *item);
|
|
|
20333d |
-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
|
|
|
20333d |
|
|
|
20333d |
#ifdef DUMP_BITMAP
|
|
|
20333d |
static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
|
|
|
20333d |
#endif
|
|
|
20333d |
|
|
|
20333d |
static void red_push_monitors_config(DisplayChannelClient *dcc);
|
|
|
20333d |
-static inline uint64_t red_now(void);
|
|
|
20333d |
|
|
|
20333d |
/*
|
|
|
20333d |
* Macros to make iterating over stuff easier
|
|
|
20333d |
@@ -2098,12 +2091,10 @@ static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int
|
|
|
20333d |
}
|
|
|
20333d |
|
|
|
20333d |
if (item) {
|
|
|
20333d |
- red_wait_pipe_item_sent(&dcc->common.base, item);
|
|
|
20333d |
+ red_channel_client_wait_pipe_item_sent(&dcc->common.base, item);
|
|
|
20333d |
}
|
|
|
20333d |
}
|
|
|
20333d |
|
|
|
20333d |
-static void red_wait_outgoing_item(RedChannelClient *rcc);
|
|
|
20333d |
-
|
|
|
20333d |
static void red_clear_surface_drawables_from_pipes(RedWorker *worker, int surface_id,
|
|
|
20333d |
int force, int wait_for_outgoing_item)
|
|
|
20333d |
{
|
|
|
20333d |
@@ -5088,15 +5079,6 @@ static void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint
|
|
|
20333d |
red_release_cursor(worker, cursor_item);
|
|
|
20333d |
}
|
|
|
20333d |
|
|
|
20333d |
-static inline uint64_t red_now(void)
|
|
|
20333d |
-{
|
|
|
20333d |
- struct timespec time;
|
|
|
20333d |
-
|
|
|
20333d |
- clock_gettime(CLOCK_MONOTONIC, &time);
|
|
|
20333d |
-
|
|
|
20333d |
- return ((uint64_t) time.tv_sec) * 1000000000 + time.tv_nsec;
|
|
|
20333d |
-}
|
|
|
20333d |
-
|
|
|
20333d |
static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
|
|
|
20333d |
{
|
|
|
20333d |
QXLCommandExt ext_cmd;
|
|
|
20333d |
@@ -10988,105 +10970,6 @@ typedef struct __attribute__ ((__packed__)) CursorData {
|
|
|
20333d |
SpiceCursor _cursor;
|
|
|
20333d |
} CursorData;
|
|
|
20333d |
|
|
|
20333d |
-static void red_wait_outgoing_item(RedChannelClient *rcc)
|
|
|
20333d |
-{
|
|
|
20333d |
- uint64_t end_time;
|
|
|
20333d |
- int blocked;
|
|
|
20333d |
-
|
|
|
20333d |
- if (!red_channel_client_blocked(rcc)) {
|
|
|
20333d |
- return;
|
|
|
20333d |
- }
|
|
|
20333d |
- end_time = red_now() + DETACH_TIMEOUT;
|
|
|
20333d |
- spice_info("blocked");
|
|
|
20333d |
-
|
|
|
20333d |
- do {
|
|
|
20333d |
- usleep(DETACH_SLEEP_DURATION);
|
|
|
20333d |
- red_channel_client_receive(rcc);
|
|
|
20333d |
- red_channel_client_send(rcc);
|
|
|
20333d |
- } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
|
|
|
20333d |
-
|
|
|
20333d |
- if (blocked) {
|
|
|
20333d |
- spice_warning("timeout");
|
|
|
20333d |
- // TODO - shutting down the socket but we still need to trigger
|
|
|
20333d |
- // disconnection. Right now we wait for main channel to error for that.
|
|
|
20333d |
- red_channel_client_shutdown(rcc);
|
|
|
20333d |
- } else {
|
|
|
20333d |
- spice_assert(red_channel_client_no_item_being_sent(rcc));
|
|
|
20333d |
- }
|
|
|
20333d |
-}
|
|
|
20333d |
-
|
|
|
20333d |
-static void rcc_shutdown_if_pending_send(RedChannelClient *rcc)
|
|
|
20333d |
-{
|
|
|
20333d |
- if (red_channel_client_blocked(rcc) || rcc->pipe_size > 0) {
|
|
|
20333d |
- red_channel_client_shutdown(rcc);
|
|
|
20333d |
- } else {
|
|
|
20333d |
- spice_assert(red_channel_client_no_item_being_sent(rcc));
|
|
|
20333d |
- }
|
|
|
20333d |
-}
|
|
|
20333d |
-
|
|
|
20333d |
-static void red_wait_all_sent(RedChannel *channel)
|
|
|
20333d |
-{
|
|
|
20333d |
- uint64_t end_time;
|
|
|
20333d |
- uint32_t max_pipe_size;
|
|
|
20333d |
- int blocked = FALSE;
|
|
|
20333d |
-
|
|
|
20333d |
- end_time = red_now() + DETACH_TIMEOUT;
|
|
|
20333d |
-
|
|
|
20333d |
- red_channel_push(channel);
|
|
|
20333d |
- while (((max_pipe_size = red_channel_max_pipe_size(channel)) ||
|
|
|
20333d |
- (blocked = red_channel_any_blocked(channel))) &&
|
|
|
20333d |
- red_now() < end_time) {
|
|
|
20333d |
- spice_debug("pipe-size %u blocked %d", max_pipe_size, blocked);
|
|
|
20333d |
- usleep(DETACH_SLEEP_DURATION);
|
|
|
20333d |
- red_channel_receive(channel);
|
|
|
20333d |
- red_channel_send(channel);
|
|
|
20333d |
- red_channel_push(channel);
|
|
|
20333d |
- }
|
|
|
20333d |
-
|
|
|
20333d |
- if (max_pipe_size || blocked) {
|
|
|
20333d |
- spice_printerr("timeout: pending out messages exist (pipe-size %u, blocked %d)",
|
|
|
20333d |
- max_pipe_size, blocked);
|
|
|
20333d |
- red_channel_apply_clients(channel, rcc_shutdown_if_pending_send);
|
|
|
20333d |
- } else {
|
|
|
20333d |
- spice_assert(red_channel_no_item_being_sent(channel));
|
|
|
20333d |
- }
|
|
|
20333d |
-}
|
|
|
20333d |
-
|
|
|
20333d |
-/* TODO: more evil sync stuff. anything with the word wait in it's name. */
|
|
|
20333d |
-static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item)
|
|
|
20333d |
-{
|
|
|
20333d |
- DrawablePipeItem *dpi;
|
|
|
20333d |
- uint64_t end_time;
|
|
|
20333d |
- int item_in_pipe;
|
|
|
20333d |
-
|
|
|
20333d |
- spice_info(NULL);
|
|
|
20333d |
- dpi = SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item);
|
|
|
20333d |
- ref_drawable_pipe_item(dpi);
|
|
|
20333d |
-
|
|
|
20333d |
- end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
|
|
|
20333d |
-
|
|
|
20333d |
- if (red_channel_client_blocked(rcc)) {
|
|
|
20333d |
- red_channel_client_receive(rcc);
|
|
|
20333d |
- red_channel_client_send(rcc);
|
|
|
20333d |
- }
|
|
|
20333d |
- red_channel_client_push(rcc);
|
|
|
20333d |
-
|
|
|
20333d |
- while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
|
|
|
20333d |
- usleep(CHANNEL_PUSH_SLEEP_DURATION);
|
|
|
20333d |
- red_channel_client_receive(rcc);
|
|
|
20333d |
- red_channel_client_send(rcc);
|
|
|
20333d |
- red_channel_client_push(rcc);
|
|
|
20333d |
- }
|
|
|
20333d |
-
|
|
|
20333d |
- if (item_in_pipe) {
|
|
|
20333d |
- spice_warning("timeout");
|
|
|
20333d |
- red_channel_client_disconnect(rcc);
|
|
|
20333d |
- } else {
|
|
|
20333d |
- red_wait_outgoing_item(rcc);
|
|
|
20333d |
- }
|
|
|
20333d |
- put_drawable_pipe_item(dpi);
|
|
|
20333d |
-}
|
|
|
20333d |
-
|
|
|
20333d |
static void surface_dirty_region_to_rects(RedSurface *surface,
|
|
|
20333d |
QXLRect *qxl_dirty_rects,
|
|
|
20333d |
uint32_t num_dirty_rects,
|