[Spice-devel] [RFC PATCH spice 0.8 15/19] client: handle SPICE_MSG_MAIN_MIGRATE_END
Alon Levy
alevy at redhat.com
Tue Sep 20 09:22:06 PDT 2011
On Mon, Sep 19, 2011 at 12:47:08PM +0300, Yonit Halperin wrote:
> (1) disconnect all channels from the migration src
> (2) after all channels are disconnected, clean global resources
> (3) send SPICE_MSGC_MAIN_MIGRATE_END to migration target
> (4) wait for SPICE_MSG_MAIN_INIT
> (4) switch all channels to migration target
>
> Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
> ---
> client/red_channel.cpp | 61 ++++++++++++++++++++++++++++++++++++++++
> client/red_channel.h | 19 ++++++++++++
> client/red_client.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++-
> client/red_client.h | 11 +++++++
> 4 files changed, 163 insertions(+), 1 deletions(-)
>
> diff --git a/client/red_channel.cpp b/client/red_channel.cpp
> index f4cdf52..2e0de5a 100644
> --- a/client/red_channel.cpp
> +++ b/client/red_channel.cpp
> @@ -27,6 +27,15 @@
> #include "openssl/evp.h"
> #include "openssl/x509.h"
>
> +void MigrationDisconnectSrcEvent::response(AbstractProcessLoop& events_loop)
> +{
> + static_cast<RedChannel*>(events_loop.get_owner())->do_migration_disconnect_src();
> +}
> +
> +void MigrationConnectTargetEvent::response(AbstractProcessLoop& events_loop)
> +{
> + static_cast<RedChannel*>(events_loop.get_owner())->do_migration_connect_target();
> +}
>
> RedChannelBase::RedChannelBase(uint8_t type, uint8_t id, const ChannelCaps& common_caps,
> const ChannelCaps& caps)
> @@ -433,6 +442,58 @@ void RedChannel::disconnect()
> _action_cond.notify_one();
> }
>
> +void RedChannel::disconnect_migration_src()
> +{
> + clear_outgoing_messages();
> +
> + Lock lock(_action_lock);
> + if (_state != CONNECTING_STATE && _state != CONNECTED_STATE) {
> + return;
> + }
> + AutoRef<MigrationDisconnectSrcEvent> migrate_event(new MigrationDisconnectSrcEvent());
> + _loop.push_event(*migrate_event);
IIUC this AutoRef would be constructed and destructed even if the if condition evaluates to true and
we return. Maybe just have a else caluse or simply sorround these two lines with their own scope?
> +}
> +
> +void RedChannel::connect_migration_target()
> +{
> + LOG_INFO("");
> + AutoRef<MigrationConnectTargetEvent> migrate_event(new MigrationConnectTargetEvent());
> + _loop.push_event(*migrate_event);
> +}
> +
> +void RedChannel::do_migration_disconnect_src()
> +{
> + if (_socket_in_loop) {
> + _socket_in_loop = false;
> + _loop.remove_socket(*this);
> + }
> +
> + clear_outgoing_messages();
> + if (_outgoing_message) {
> + _outgoing_message->release();
> + _outgoing_message = NULL;
> + }
> + _incomming_header_pos = 0;
> + if (_incomming_message) {
> + _incomming_message->unref();
> + _incomming_message = NULL;
> + }
> +
> + on_disconnect_mig_src();
> + get_client().migrate_channel(*this);
> + get_client().on_channel_disconnect_mig_src(*this);
> +}
> +
> +void RedChannel::do_migration_connect_target()
> +{
> + LOG_INFO("");
> + _loop.add_socket(*this);
> + _socket_in_loop = true;
> + on_connect_mig_target();
> + set_state(CONNECTED_STATE);
> + on_event();
> +}
> +
> void RedChannel::clear_outgoing_messages()
> {
> Lock lock(_outgoing_lock);
> diff --git a/client/red_channel.h b/client/red_channel.h
> index a326680..c47d143 100644
> --- a/client/red_channel.h
> +++ b/client/red_channel.h
> @@ -106,6 +106,16 @@ public:
> virtual void on_event();
> };
>
> +class MigrationDisconnectSrcEvent: public Event {
> +public:
> + virtual void response(AbstractProcessLoop& events_loop);
> +};
> +
> +class MigrationConnectTargetEvent: public Event {
> +public:
> + virtual void response(AbstractProcessLoop& events_loop);
> +};
> +
> struct SyncInfo {
> Mutex* lock;
> Condition* condition;
> @@ -126,6 +136,9 @@ public:
> virtual void disconnect();
> virtual bool abort();
>
> + virtual void disconnect_migration_src();
> + virtual void connect_migration_target();
> +
> virtual CompoundInMessage *recive();
>
> virtual void post_message(RedChannel::OutMessage* message);
> @@ -140,6 +153,8 @@ protected:
> virtual void on_connect() {}
> virtual void on_disconnect() {}
> virtual void on_migrate() {}
> + virtual void on_disconnect_mig_src() { on_disconnect();}
> + virtual void on_connect_mig_target() { on_connect();}
> void handle_migrate(RedPeer::InMessage* message);
> void handle_set_ack(RedPeer::InMessage* message);
> void handle_ping(RedPeer::InMessage* message);
> @@ -159,6 +174,8 @@ private:
> virtual void on_event();
> void on_message_recived();
> void on_message_complition(uint64_t serial);
> + void do_migration_disconnect_src();
> + void do_migration_connect_target();
>
> static void* worker_main(void *);
>
> @@ -203,6 +220,8 @@ private:
> uint64_t _disconnect_reason;
>
> friend class SendTrigger;
> + friend class MigrationDisconnectSrcEvent;
> + friend class MigrationConnectTargetEvent;
> };
>
>
> diff --git a/client/red_client.cpp b/client/red_client.cpp
> index a7f9cba..51ed7b5 100644
> --- a/client/red_client.cpp
> +++ b/client/red_client.cpp
> @@ -23,6 +23,7 @@
> #include "utils.h"
> #include "debug.h"
> #include "marshallers.h"
> +#include <algorithm>
>
> #ifndef INFINITY
> #define INFINITY HUGE
> @@ -120,6 +121,11 @@ void ClipboardReleaseEvent::response(AbstractProcessLoop& events_loop)
> VD_AGENT_CLIPBOARD_RELEASE, 0, NULL);
> }
>
> +void MigrateEndEvent::response(AbstractProcessLoop& events_loop)
> +{
> + static_cast<RedClient*>(events_loop.get_owner())->send_migrate_end();
> +}
> +
> Migrate::Migrate(RedClient& client)
> : _client (client)
> , _running (false)
> @@ -388,6 +394,7 @@ RedClient::RedClient(Application& application)
> , _agent_caps(NULL)
> , _migrate (*this)
> , _glz_window (_glz_debug)
> + , _during_migration (false)
> {
> Platform::set_clipboard_listener(this);
> MainChannelLoop* message_loop = static_cast<MainChannelLoop*>(get_message_handler());
> @@ -406,6 +413,7 @@ RedClient::RedClient(Application& application)
>
> message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_BEGIN, &RedClient::handle_migrate_begin);
> message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_CANCEL, &RedClient::handle_migrate_cancel);
> + message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_END, &RedClient::handle_migrate_end);
> message_loop->set_handler(SPICE_MSG_MAIN_MIGRATE_SWITCH_HOST,
> &RedClient::handle_migrate_switch_host);
> message_loop->set_handler(SPICE_MSG_MAIN_INIT, &RedClient::handle_init);
> @@ -417,6 +425,8 @@ RedClient::RedClient(Application& application)
> message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DISCONNECTED, &RedClient::handle_agent_disconnected);
> message_loop->set_handler(SPICE_MSG_MAIN_AGENT_DATA, &RedClient::handle_agent_data);
> message_loop->set_handler(SPICE_MSG_MAIN_AGENT_TOKEN, &RedClient::handle_agent_tokens);
> +
> + set_capability(SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
> start();
> }
>
> @@ -484,6 +494,7 @@ void RedClient::on_disconnect()
> void RedClient::delete_channels()
> {
> Lock lock(_channels_lock);
> + _pending_mig_disconnect_channels.clear();
> while (!_channels.empty()) {
> RedChannel *channel = *_channels.begin();
> _channels.pop_front();
> @@ -611,7 +622,7 @@ bool RedClient::abort()
>
> void RedClient::handle_migrate_begin(RedPeer::InMessage* message)
> {
> - DBG(0, "");
> + LOG_INFO("");
> SpiceMsgMainMigrationBegin* migrate = (SpiceMsgMainMigrationBegin*)message->data();
> //add mig channels
> _migrate.start(migrate);
> @@ -619,9 +630,59 @@ void RedClient::handle_migrate_begin(RedPeer::InMessage* message)
>
> void RedClient::handle_migrate_cancel(RedPeer::InMessage* message)
> {
> + LOG_INFO("");
> _migrate.abort();
> }
>
> +void RedClient::handle_migrate_end(RedPeer::InMessage* message)
> +{
> + LOG_INFO("");
> +
> + Lock lock(_channels_lock);
> + ASSERT(_pending_mig_disconnect_channels.empty());
> + Channels::iterator iter = _channels.begin();
> + for (; iter != _channels.end(); ++iter) {
> + (*iter)->disconnect_migration_src();
> + _pending_mig_disconnect_channels.push_back(*iter);
> + }
> + RedChannel::disconnect_migration_src();
> + _pending_mig_disconnect_channels.push_back(this);
> + _during_migration = true;
> +}
> +
> +void RedClient::on_channel_disconnect_mig_src(RedChannel& channel)
> +{
> + Lock lock(_channels_lock);
> + Channels::iterator pending_iter = std::find(_pending_mig_disconnect_channels.begin(),
> + _pending_mig_disconnect_channels.end(),
> + &channel);
> +
> + LOG_INFO("");
> + if (pending_iter == _pending_mig_disconnect_channels.end()) {
> + THROW("unexpected channel");
> + }
> +
> + _pending_mig_disconnect_channels.erase(pending_iter);
> + /* clean shared data when all channels have disconnected */
> + if (_pending_mig_disconnect_channels.empty()) {
> + _pixmap_cache.clear();
> + _glz_window.clear();
> + memset(_sync_info, 0, sizeof(_sync_info));
> +
> + LOG_INFO("calling main to connect and wait for handle_init to tell all the other channels to connect");
> + RedChannel::connect_migration_target();
> +
> + AutoRef<MigrateEndEvent> mig_end_event(new MigrateEndEvent());
> + get_process_loop().push_event(*mig_end_event);
> + }
> +}
> +
> +void RedClient::send_migrate_end()
> +{
> + Message* message = new Message(SPICE_MSGC_MAIN_MIGRATE_END);
> + post_message(message);
> +}
> +
> ChannelFactory* RedClient::find_factory(uint32_t type)
> {
> Factorys::iterator iter = _factorys.begin();
> @@ -968,6 +1029,7 @@ void RedClient::set_mouse_mode(uint32_t supported_modes, uint32_t current_mode)
> void RedClient::handle_init(RedPeer::InMessage* message)
> {
> SpiceMsgMainInit *init = (SpiceMsgMainInit *)message->data();
> + LOG_INFO("");
> _connection_id = init->session_id;
> set_mm_time(init->multi_media_time);
> calc_pixmap_cach_and_glz_window_size(init->display_channels_hint, init->ram_hint);
> @@ -996,6 +1058,15 @@ void RedClient::handle_init(RedPeer::InMessage* message)
> }
> send_main_attach_channels();
> }
> +
> + if (_during_migration) {
> + LOG_INFO("connecting all channels after migration");
> + Channels::iterator iter = _channels.begin();
> + for (; iter != _channels.end(); ++iter) {
> + (*iter)->connect_migration_target();
> + }
> + _during_migration = false;
> + }
> }
>
> void RedClient::handle_channels(RedPeer::InMessage* message)
> diff --git a/client/red_client.h b/client/red_client.h
> index 7fdba44..6b9ffd1 100644
> --- a/client/red_client.h
> +++ b/client/red_client.h
> @@ -207,6 +207,10 @@ public:
> virtual void response(AbstractProcessLoop& events_loop);
> };
>
> +class MigrateEndEvent: public Event {
> +public:
> + virtual void response(AbstractProcessLoop& events_loop);
> +};
>
> class RedClient: public RedChannel,
> public Platform::ClipboardListener {
> @@ -217,6 +221,7 @@ public:
> friend class ClipboardRequestEvent;
> friend class ClipboardNotifyEvent;
> friend class ClipboardReleaseEvent;
> + friend class MigrateEndEvent;
>
> RedClient(Application& application);
> ~RedClient();
> @@ -277,6 +282,8 @@ protected:
>
> private:
> void on_channel_disconnected(RedChannel& channel);
> + void on_channel_disconnect_mig_src(RedChannel& channel);
> + void send_migrate_end();
> void migrate_channel(RedChannel& channel);
> void send_agent_announce_capabilities(bool request);
> void send_agent_monitors_config();
> @@ -287,6 +294,7 @@ private:
>
> void handle_migrate_begin(RedPeer::InMessage* message);
> void handle_migrate_cancel(RedPeer::InMessage* message);
> + void handle_migrate_end(RedPeer::InMessage* message);
> void handle_init(RedPeer::InMessage* message);
> void handle_channels(RedPeer::InMessage* message);
> void handle_mouse_mode(RedPeer::InMessage* message);
> @@ -354,6 +362,7 @@ private:
> Factorys _factorys;
> typedef std::list<RedChannel*> Channels;
> Channels _channels;
> + Channels _pending_mig_disconnect_channels;
> PixmapCache _pixmap_cache;
> uint64_t _pixmap_cache_size;
> Mutex _sync_lock;
> @@ -367,6 +376,8 @@ private:
> Mutex _mm_clock_lock;
> uint64_t _mm_clock_last_update;
> uint32_t _mm_time;
> +
> + bool _during_migration;
> };
>
> #endif
> --
> 1.7.4.4
>
More information about the Spice-devel
mailing list