From 448ed75bd6c8db7ca48cab8aa1256a262e87fcc0 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Mon, 11 Apr 2011 12:44:00 +0300 Subject: server: Add RedClient That means RedClient tracks a ring of channels. Right now there will be only a single client because of the disconnection mechanism - whenever a new client comes we disconnect all existing clients. But this patch adds already a ring of clients to reds.c (stored in RedServer). There is a known problem handling many connections and disconnections at the same time, trigerrable easily by the following script: export NEW_DISPLAY=:3.0 Xephyr $NEW_DISPLAY -noreset & for ((i = 0 ; i < 5; ++i)); do for ((j = 0 ; j < 10; ++j)); do DISPLAY=$NEW_DISPLAY c_win7x86_qxl_tests & done sleep 2; done I fixed a few of the problems resulting from this in the same patch. This required already introducing a few other changes: * make sure all removal of channels happens in the main thread, for that two additional dispatcher calls are added to remove a specific channel client (RED_WORKER_MESSAGE_CURSOR_DISCONNECT_CLIENT and RED_WORKER_MESSAGE_DISPLAY_DISCONNECT_CLIENT). * change some asserts in input channel. * make main channel disconnect not recursive * introduce disconnect call back to red_channel_create_parser The remaining abort is from a double free in the main channel, still can't find it (doesn't happen when running under valgrind - probably due to the slowness resulting from that), but is easy to see when running under gdb. --- server/red_channel.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'server/red_channel.h') diff --git a/server/red_channel.h b/server/red_channel.h index 2bd3054c..874fdf09 100644 --- a/server/red_channel.h +++ b/server/red_channel.h @@ -140,7 +140,9 @@ typedef uint64_t (*channel_handle_migrate_data_get_serial_proc)(RedChannelClient struct RedChannelClient { RingItem channel_link; + RingItem client_link; RedChannel *channel; + RedClient *client; RedsStream *stream; struct { uint32_t generation; @@ -172,6 +174,7 @@ struct RedChannel { int handle_acks; RedChannelClient *rcc; + uint32_t clients_num; OutgoingHandlerInterface outgoing_cb; IncomingHandlerInterface incoming_cb; @@ -219,6 +222,7 @@ RedChannel *red_channel_create_parser(int size, SpiceCoreInterface *core, int migrate, int handle_acks, channel_configure_socket_proc config_socket, + channel_disconnect_proc disconnect, spice_parse_channel_func_t parser, channel_handle_parsed_proc handle_parsed, channel_alloc_msg_recv_buf_proc alloc_recv_buf, @@ -231,13 +235,19 @@ RedChannel *red_channel_create_parser(int size, channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark, channel_handle_migrate_data_proc handle_migrate_data, channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial); -RedChannelClient *red_channel_client_create(int size, RedChannel *channel, +RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedClient *client, RedsStream *stream); int red_channel_is_connected(RedChannel *channel); void red_channel_client_destroy(RedChannelClient *rcc); void red_channel_destroy(RedChannel *channel); +/* shutdown is the only safe thing to do out of the client/channel + * thread. It will not touch the rings, just shutdown the socket. + * It should be followed by some way to gurantee a disconnection. */ +void red_channel_client_shutdown(RedChannelClient *rcc); +void red_channel_shutdown(RedChannel *channel); + /* should be called when a new channel is ready to send messages */ void red_channel_init_outgoing_messages_window(RedChannel *channel); @@ -350,4 +360,17 @@ typedef void (*channel_client_visitor_data)(RedChannelClient *rcc, void *data); void red_channel_apply_clients(RedChannel *channel, channel_client_visitor v); void red_channel_apply_clients_data(RedChannel *channel, channel_client_visitor_data v, void *data); +struct RedClient { + RingItem link; + Ring channels; + int channels_num; + int disconnecting; + MainChannelClient *mcc; +}; + +RedClient *red_client_new(); +void red_client_destroy(RedClient *client); +void red_client_set_main(RedClient *client, MainChannelClient *mcc); +MainChannelClient *red_client_get_main(RedClient *client); + #endif -- cgit