From cea4dee2c9d257d65a2a5f07ea6e85d43634aa68 Mon Sep 17 00:00:00 2001 From: Timo Dritschler Date: Wed, 26 Nov 2014 18:03:31 +0100 Subject: Added a Main Loop model to kiro-client Added kiro_client_disconnect function Added missing memory cleanup to kiro server and client upon shutdown --- src/kiro-client.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/kiro-client.h | 17 +++++++++ src/kiro-server.c | 18 +++++---- 3 files changed, 133 insertions(+), 10 deletions(-) diff --git a/src/kiro-client.c b/src/kiro-client.c index 8fa582b..8618c46 100644 --- a/src/kiro-client.c +++ b/src/kiro-client.c @@ -51,9 +51,13 @@ struct _KiroClientPrivate { /* 'Real' private structures */ /* (Not accessible by properties) */ - struct rdma_event_channel *ec; // Main Event Channel - struct rdma_cm_id *conn; // Connection to the Server + struct rdma_event_channel *ec; // Main Event Channel + struct rdma_cm_id *conn; // Connection to the Server + gboolean close_signal; // Flag used to signal event listening to stop for connection tear-down + GMainLoop *main_loop; // Main loop of the server for event polling and handling + GIOChannel *g_io_ec; // GLib IO Channel encapsulation for the connection manager event channel + GThread *main_thread; // Main KIRO client thread }; @@ -94,7 +98,8 @@ kiro_client_init (KiroClient *self) static void kiro_client_finalize (GObject *object) { - //PASS + if (KIRO_IS_CLIENT (object)) + kiro_client_disconnect ((KiroClient *)object); G_OBJECT_CLASS (kiro_client_parent_class)->finalize (object); } @@ -108,6 +113,48 @@ kiro_client_class_init (KiroClientClass *klass) } +static gboolean +process_cm_event (GIOChannel *source, GIOCondition condition, gpointer data) +{ + // Right now, we don't need 'source' and 'condition' + // Tell the compiler to ignore them by (void)-ing them + (void) source; + (void) condition; + + KiroClientPrivate *priv = (KiroClientPrivate *)data; + struct rdma_cm_event *active_event; + + if (0 <= rdma_get_cm_event (priv->ec, &active_event)) { + //Disable cancellation to prevent undefined states during shutdown + struct rdma_cm_event *ev = malloc (sizeof (*active_event)); + + if (!ev) { + g_critical ("Unable to allocate memory for Event handling!"); + rdma_ack_cm_event (active_event); + return FALSE; + } + + memcpy (ev, active_event, sizeof (*active_event)); + rdma_ack_cm_event (active_event); + + if (ev->event == RDMA_CM_EVENT_DISCONNECTED) { + g_debug ("Connection closed by server"); + } + + free (ev); + } + return TRUE; +} + + +gpointer +start_client_main_loop (gpointer data) +{ + g_main_loop_run ((GMainLoop *)data); + return NULL; +} + + int kiro_client_connect (KiroClient *self, const char *address, const char *port) { @@ -196,6 +243,7 @@ kiro_client_connect (KiroClient *self, const char *address, const char *port) } g_message ("Connection to server established"); + priv->ec = priv->conn->channel; //For easy access struct ibv_wc wc; if (rdma_get_recv_comp (priv->conn, &wc) < 0) { @@ -219,6 +267,15 @@ kiro_client_connect (KiroClient *self, const char *address, const char *port) return -1; } + priv->main_loop = g_main_loop_new (NULL, FALSE); + priv->g_io_ec = g_io_channel_unix_new (priv->ec->fd); + g_io_add_watch (priv->g_io_ec, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, process_cm_event, (gpointer)priv); + priv->main_thread = g_thread_new ("KIRO Client main loop", start_client_main_loop, priv->main_loop); + + // We gave control to the main_loop (with add_watch) and don't need our ref + // any longer + g_io_channel_unref (priv->g_io_ec); + g_message ("Connected to %s:%s", address, port); return 0; } @@ -300,3 +357,48 @@ kiro_client_get_memory_size (KiroClient *self) return ctx->rdma_mr->size; } + +void +kiro_client_disconnect (KiroClient *self) +{ + if (!self) + return; + + KiroClientPrivate *priv = KIRO_CLIENT_GET_PRIVATE (self); + + if (!priv->conn) + return; + + //Shut down event listening + priv->close_signal = TRUE; + g_debug ("Event handling stopped"); + + // Stop the main loop and clear its memory + g_main_loop_quit (priv->main_loop); + g_main_loop_unref (priv->main_loop); + priv->main_loop = NULL; + + // Ask the main thread to join (It probably already has, but we do it + // anyways. Just in case!) + g_thread_join (priv->main_thread); + priv->main_thread = NULL; + + // We don't need the connection management IO channel container any more. + // Unref and thus free it. + g_io_channel_unref (priv->g_io_ec); + priv->g_io_ec = NULL; + + priv->close_signal = FALSE; + + //kiro_destroy_connection does not free RDMA memory. Therefore, we need to + //cache the memory pointer and free the memory afterwards manually + struct kiro_connection_context *ctx = (struct kiro_connection_context *) (priv->conn->context); + void *rdma_mem = ctx->rdma_mr->mem; + kiro_destroy_connection (&(priv->conn)); + free (rdma_mem); + + // priv->ec is just an easy-access pointer. Don't free it. Just NULL it + priv->ec = NULL; + g_message ("Client disconnected from server"); +} + diff --git a/src/kiro-client.h b/src/kiro-client.h index 9e9d3ef..9c6036d 100644 --- a/src/kiro-client.h +++ b/src/kiro-client.h @@ -124,6 +124,23 @@ void kiro_client_free (KiroClient *client); */ int kiro_client_connect (KiroClient *client, const char *dest_addr, const char *dest_port); +/** + * kiro_client_disconnect - Diconnect a #KiroClient from the Server + * @client: (transfer none): The #KiroClient to disconnect + * Description: + * Disconnects the given #KiroClient from the KIRO server that it is connected + * to. If the @client is not connected, this function has no effect. + * Note: + * The memory content that has been transfered from the server is + * automatically freed when calling this function. If you want to continue + * using the memory after disconnecting the @client, make sure to memcpy() it + * first, using the informations obtained from kiro_client_get_memory() and + * kiro_client_get_memory_size(). + * See also: + * kiro_server_connect + */ +void kiro_client_disconnect (KiroClient *client); + /** * kiro_client_sync - Read data from the connected server * @client: (transfer none): The #KiroServer to use sync on diff --git a/src/kiro-server.c b/src/kiro-server.c index 29dd960..a236c30 100644 --- a/src/kiro-server.c +++ b/src/kiro-server.c @@ -54,10 +54,10 @@ struct _KiroServerPrivate { struct rdma_cm_id *base; // Base-Listening-Connection GList *clients; // List of connected clients guint next_client_id; // Numeric ID for the next client that will connect - int close_signal; // Integer flag used to signal to the listener-thread that the server is going to shut down void *mem; // Pointer to the server buffer size_t mem_size; // Server Buffer Size in bytes + gboolean close_signal; // Flag used to signal event listening to stop for server shutdown GMainLoop *main_loop; // Main loop of the server for event polling and handling GIOChannel *g_io_ec; // GLib IO Channel encapsulation for the connection manager event channel GThread *main_thread; // Main KIRO server thread @@ -220,7 +220,7 @@ welcome_client (struct rdma_cm_id *client, void *mem, size_t mem_size) } -gboolean +static gboolean process_cm_event (GIOChannel *source, GIOCondition condition, gpointer data) { // Right now, we don't need 'source' and 'condition' @@ -245,7 +245,7 @@ process_cm_event (GIOChannel *source, GIOCondition condition, gpointer data) rdma_ack_cm_event (active_event); if (ev->event == RDMA_CM_EVENT_CONNECT_REQUEST) { - if (0 != priv->close_signal) { + if (TRUE == priv->close_signal) { //Main thread has signalled shutdown! //Don't connect this client any more. //Sorry mate! @@ -420,7 +420,7 @@ kiro_server_stop (KiroServer *self) return; //Shut down event listening - priv->close_signal = 1; + priv->close_signal = TRUE; g_debug ("Event handling stopped"); g_list_foreach (priv->clients, disconnect_client, NULL); @@ -440,12 +440,16 @@ kiro_server_stop (KiroServer *self) // Unref and thus free it. g_io_channel_unref (priv->g_io_ec); priv->g_io_ec = NULL; + priv->close_signal = FALSE; - priv->close_signal = 0; - - + // kiro_destroy_connection would try to call rdma_disconnect on the given + // connection. But the server never 'connects' to anywhere, so this would + // cause a crash. We need to destroy the enpoint manually without disconnect + struct kiro_connection_context *ctx = (struct kiro_connection_context *) (priv->base->context); + kiro_destroy_connection_context (&ctx); rdma_destroy_ep (priv->base); priv->base = NULL; + rdma_destroy_event_channel (priv->ec); priv->ec = NULL; g_message ("Server stopped successfully"); -- cgit v1.2.1