From 69f57959d50cf08d063484551f15f6990582953d Mon Sep 17 00:00:00 2001 From: Timo Dritschler Date: Tue, 27 May 2014 15:30:08 +0200 Subject: Changed build system to CMake --- src/CMakeLists.txt | 2 + src/kiro-client.c | 256 +++++++++++++++++++++++++++++++++++++ src/kiro-client.h | 90 +++++++++++++ src/kiro-rdma.h | 230 ++++++++++++++++++++++++++++++++++ src/kiro-server.c | 361 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/kiro-server.h | 106 ++++++++++++++++ src/kiro-trb.c | 270 +++++++++++++++++++++++++++++++++++++++ src/kiro-trb.h | 332 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1647 insertions(+) create mode 100644 src/CMakeLists.txt create mode 100644 src/kiro-client.c create mode 100644 src/kiro-client.h create mode 100644 src/kiro-rdma.h create mode 100644 src/kiro-server.c create mode 100644 src/kiro-server.h create mode 100644 src/kiro-trb.c create mode 100644 src/kiro-trb.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..a657e1c --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(kiro kiro-trb.c kiro-client.c kiro-server.c) +target_link_libraries(kiro SDL m rdmacm ibverbs pthread) diff --git a/src/kiro-client.c b/src/kiro-client.c new file mode 100644 index 0000000..807d7d5 --- /dev/null +++ b/src/kiro-client.c @@ -0,0 +1,256 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +/** + * SECTION: kiro-client + * @Short_description: KIRO RDMA Client / Consumer + * @Title: KiroClient + * + * KiroClient implements the client / active / consumer side of the the RDMA + * Communication Channel. It uses a KIRO-CLIENT to manage data read from the Server. + */ + +#include +#include +#include +#include +#include +#include +#include "kiro-client.h" +#include "kiro-rdma.h" +#include "kiro-trb.h" + +#include + + +/* + * Definition of 'private' structures and members and macro to access them + */ + +#define KIRO_CLIENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), KIRO_TYPE_CLIENT, KiroClientPrivate)) + +struct _KiroClientPrivate { + + /* Properties */ + // PLACEHOLDER // + + /* 'Real' private structures */ + /* (Not accessible by properties) */ + struct rdma_event_channel *ec; // Main Event Channel + struct rdma_cm_id *conn; // Connection to the Server + +}; + + +G_DEFINE_TYPE_WITH_PRIVATE (KiroClient, kiro_client, G_TYPE_OBJECT); + + +static void kiro_client_init (KiroClient *self) +{ + KiroClientPrivate *priv = KIRO_CLIENT_GET_PRIVATE(self); + memset(priv, 0, sizeof(&priv)); +} + +static void +kiro_client_finalize (GObject *object) +{ + //KiroClient *self = KIRO_CLIENT(object); + //KiroClientPrivate * priv = KIRO_CLIENT_GET_PRIVATE(self); + //PASS +} + +static void +kiro_client_class_init (KiroClientClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = kiro_client_finalize; +} + + + +int kiro_client_connect (KiroClient *self, char *address, char* port) +{ + KiroClientPrivate *priv = KIRO_CLIENT_GET_PRIVATE(self); + + if(priv->conn) + { + printf("Already connected to server.\n"); + return -1; + } + + struct rdma_addrinfo hints, *res_addrinfo; + memset(&hints, 0, sizeof(hints)); + hints.ai_port_space = RDMA_PS_IB; + if(rdma_getaddrinfo(address, port, &hints, &res_addrinfo)) + { + printf("Failed to contruct address information for %s:%s\n",address, port); + return -1; + } + printf("Address information created.\n"); + + struct ibv_qp_init_attr qp_attr; + memset(&qp_attr, 0, sizeof(qp_attr)); + qp_attr.cap.max_send_wr = 10; + qp_attr.cap.max_recv_wr = 10; + qp_attr.cap.max_send_sge = 1; + qp_attr.cap.max_recv_sge = 1; + qp_attr.qp_context = priv->conn; + qp_attr.sq_sig_all = 1; + + if(rdma_create_ep(&(priv->conn), res_addrinfo, NULL, &qp_attr)) + { + printf("Endpoint creation failed with error: %i\n", errno); + return -1; + } + printf("Route to server resolved.\n"); + + struct kiro_connection_context *ctx = (struct kiro_connection_context *)calloc(1,sizeof(struct kiro_connection_context)); + if(!ctx) + { + printf("Failed to create connection context.\n"); + rdma_destroy_ep(priv->conn); + return -1; + } + + ctx->cf_mr_send = (struct kiro_rdma_mem *)calloc(1, sizeof(struct kiro_rdma_mem)); + ctx->cf_mr_recv = (struct kiro_rdma_mem *)calloc(1, sizeof(struct kiro_rdma_mem)); + if(!ctx->cf_mr_recv || !ctx->cf_mr_send) + { + printf("Failed to allocate Control Flow Memory Container.\n"); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + + ctx->cf_mr_recv = kiro_create_rdma_memory(priv->conn->pd, sizeof(struct kiro_ctrl_msg), IBV_ACCESS_LOCAL_WRITE); + ctx->cf_mr_send = kiro_create_rdma_memory(priv->conn->pd, sizeof(struct kiro_ctrl_msg), IBV_ACCESS_LOCAL_WRITE); + if(!ctx->cf_mr_recv || !ctx->cf_mr_send) + { + printf("Failed to register control message memory.\n"); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + ctx->cf_mr_recv->size = ctx->cf_mr_send->size = sizeof(struct kiro_ctrl_msg); + priv->conn->context = ctx; + + if(rdma_post_recv(priv->conn, priv->conn, ctx->cf_mr_recv->mem, ctx->cf_mr_recv->size, ctx->cf_mr_recv->mr)) + { + printf("Posting preemtive receive for connection failed with error: %i\n", errno); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + + if(rdma_connect(priv->conn, NULL)) + { + printf("Failed to establish connection to the server.\n"); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + printf("Connected to server.\n"); + + + struct ibv_wc wc; + if(rdma_get_recv_comp(priv->conn, &wc) < 0) + { + printf("Failure waiting for POST from server.\n"); + rdma_disconnect(priv->conn); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + printf("Got Message from Server.\n"); + ctx->peer_mr = (((struct kiro_ctrl_msg *)(ctx->cf_mr_recv->mem))->peer_mri); + printf("Expected Memory Size is: %u\n",ctx->peer_mr.length); + + ctx->rdma_mr = kiro_create_rdma_memory(priv->conn->pd, ctx->peer_mr.length, IBV_ACCESS_LOCAL_WRITE); + if(!ctx->rdma_mr) + { + printf("Failed to allocate memory for receive buffer.\n"); + rdma_disconnect(priv->conn); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + printf("Connection setup completed successfully!\n"); + + return 0; +} + + + +int kiro_client_sync (KiroClient *self) +{ + KiroClientPrivate *priv = KIRO_CLIENT_GET_PRIVATE(self); + struct kiro_connection_context *ctx = (struct kiro_connection_context *)priv->conn->context; + + if(rdma_post_read(priv->conn, priv->conn, ctx->rdma_mr->mem, ctx->peer_mr.length, ctx->rdma_mr->mr, 0, ctx->peer_mr.addr, ctx->peer_mr.rkey)) + { + printf("Failed to read from server.\n"); + rdma_disconnect(priv->conn); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + + struct ibv_wc wc; + if(rdma_get_send_comp(priv->conn, &wc) < 0) + { + printf("Failure reading from server.\n"); + rdma_disconnect(priv->conn); + kiro_destroy_connection_context(&ctx); + rdma_destroy_ep(priv->conn); + return -1; + } + return 0; +} + + +void* kiro_client_get_memory (KiroClient *self) +{ + KiroClientPrivate *priv = KIRO_CLIENT_GET_PRIVATE(self); + if(!priv->conn) + return NULL; + + struct kiro_connection_context *ctx = (struct kiro_connection_context *)priv->conn->context; + if(!ctx->rdma_mr) + return NULL; + + return ctx->rdma_mr->mem; +} + + +size_t kiro_client_get_memory_size (KiroClient *self) +{ + KiroClientPrivate *priv = KIRO_CLIENT_GET_PRIVATE(self); + if(!priv->conn) + return 0; + + struct kiro_connection_context *ctx = (struct kiro_connection_context *)priv->conn->context; + if(!ctx->rdma_mr) + return 0; + + return ctx->rdma_mr->size; +} + + + + + diff --git a/src/kiro-client.h b/src/kiro-client.h new file mode 100644 index 0000000..e3e60de --- /dev/null +++ b/src/kiro-client.h @@ -0,0 +1,90 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +/** + * SECTION: kiro-client + * @Short_description: KIRO RDMA Client / Consumer + * @Title: KiroClient + * + * KiroClient implements the client / active / consumer side of the the RDMA + * Communication Channel. It uses a KIRO-CLIENT to manage data read from the Server. + */ + +#ifndef __KIRO_CLIENT_H +#define __KIRO_CLIENT_H + +#include +#include + +G_BEGIN_DECLS + +#define KIRO_TYPE_CLIENT (kiro_client_get_type()) +#define KIRO_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KIRO_TYPE_CLIENT, KiroClient)) +#define KIRO_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KIRO_TYPE_CLIENT)) +#define KIRO_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), KIRO_TYPE_CLIENT, KiroClientClass)) +#define KIRO_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), KIRO_TYPE_CLIENT)) +#define KIRO_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), KIRO_TYPE_CLIENT, KiroClientClass)) + + +typedef struct _KiroClient KiroClient; +typedef struct _KiroClientClass KiroClientClass; +typedef struct _KiroClientPrivate KiroClientPrivate; + + +struct _KiroClient { + + GObject parent; + + /*< private >*/ + KiroClientPrivate *priv; +}; + + +/** + * IbvConnectorInterface: + * + * Base interface for IbvConnectors. + */ + +struct _KiroClientClass { + + GObjectClass parent_class; + +}; + + + +/* GObject and GType functions */ +GType kiro_client_get_type (void); + +GObject kiro_client_new (void); + +/* client functions */ + + +int kiro_client_connect (KiroClient* client, char* dest_addr, char* dest_port); + +int kiro_client_sync (KiroClient* client); + +void* kiro_client_get_memory (KiroClient* client); + +size_t kior_client_get_memory_size (KiroClient* client); + +G_END_DECLS + +#endif //__KIRO_CLIENT_H \ No newline at end of file diff --git a/src/kiro-rdma.h b/src/kiro-rdma.h new file mode 100644 index 0000000..fa16fd1 --- /dev/null +++ b/src/kiro-rdma.h @@ -0,0 +1,230 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +#include +#include +#include +#ifndef __KIRO_RDMA_H__ +#define __KIRO_RDMA_H__ + + +#include + + +struct kiro_connection_context { + + // Information and necessary structurs + uint32_t identifier; // Unique Identifier for this connection (Application Specific) + struct kiro_rdma_mem *cf_mr_recv; // Control-Flow Memory Region Receive + struct kiro_rdma_mem *cf_mr_send; // Control-Flow Memory Region Send + struct kiro_rdma_mem *rdma_mr; // Memory Region for RDMA Operations + + struct ibv_mr peer_mr; // RDMA Memory Region Information of the peer + + enum { + KIRO_IDLE, + KIRO_MRI_REQUESTED, // Memory Region Information Requested + KIRO_RDMA_ESTABLISHED, // MRI Exchange complete. RDMA is ready + KIRO_RDMA_ACTIVE // RDMA Operation is being performed + } rdma_state; + +}; + + +struct kiro_connection { + + uint32_t identifier; + struct rdma_cm_id *id; + struct kiro_connection *next; + +}; + + +struct kiro_ctrl_msg { + + enum { + KIRO_REQ_RDMA, // Requesting RDMA Access to/from the peer + KIRO_ACK_RDMA, // acknowledge RDMA Request and provide Memory Region Information + KIRO_REJ_RDMA // RDMA Request rejected :( (peer_mri will be invalid) + } msg_type; + + struct ibv_mr peer_mri; + +}; + + +struct kiro_rdma_mem { + + void *mem; // Pointer to the beginning of the memory block + struct ibv_mr *mr; // Memory Region associated with the memory + size_t size; // Size in Bytes of the memory block + +}; + + +static int kiro_attach_qp (struct rdma_cm_id *id) +{ + if(!id) + return -1; + + id->pd = ibv_alloc_pd(id->verbs); + id->send_cq_channel = ibv_create_comp_channel(id->verbs); + id->recv_cq_channel = id->send_cq_channel; //we use one shared completion channel + id->send_cq = ibv_create_cq(id->verbs, 1, id, id->send_cq_channel, 0); + id->recv_cq = id->send_cq; //we use one shared completion queue + + struct ibv_qp_init_attr qp_attr; + memset(&qp_attr, 0, sizeof(struct ibv_qp_init_attr)); + qp_attr.qp_context = (uintptr_t)id; + qp_attr.send_cq = id->send_cq; + qp_attr.recv_cq = id->recv_cq; + qp_attr.qp_type = IBV_QPT_RC; + qp_attr.cap.max_send_wr = 1; + qp_attr.cap.max_recv_wr = 1; + qp_attr.cap.max_send_sge = 1; + qp_attr.cap.max_recv_sge = 1; + + return rdma_create_qp(id, id->pd, &qp_attr); +} + + +static int kiro_register_rdma_memory (struct ibv_pd *pd, struct ibv_mr **mr, void *mem, size_t mem_size, int access) +{ + + if(mem_size == 0) + { + printf("Cant allocate memory of size '0'.\n"); + return -1; + } + + void *mem_handle = mem; + + if(!mem_handle) + mem_handle = malloc(mem_size); + + if(!mem_handle) + { + printf("Failed to allocate memory [Register Memory]."); + return -1; + } + + *mr = ibv_reg_mr(pd, mem_handle, mem_size, access); + if(!(*mr)) + { + // Memory Registration failed + printf("Failed to register memory region!\n"); + free(mem_handle); + return -1; + } + + return 0; +} + + +static struct kiro_rdma_mem* kiro_create_rdma_memory (struct ibv_pd *pd, size_t mem_size, int access) +{ + if(mem_size == 0) + { + printf("Cant allocate memory of size '0'.\n"); + return NULL; + } + + struct kiro_rdma_mem *krm = (struct kiro_rdma_mem *)calloc(1, sizeof(struct kiro_rdma_mem)); + if(!krm) + { + printf("Failed to create new KIRO RDMA Memory.\n"); + return NULL; + } + + if(kiro_register_rdma_memory(pd, &(krm->mr), krm->mem, mem_size, access)) + { + free(krm); + return NULL; + } + + if(!krm->mem) + krm->mem = krm->mr->addr; + + + return krm; + +} + + +static void kiro_destroy_rdma_memory (struct kiro_rdma_mem *krm) +{ + if(!krm) + return; + + if(krm->mr) + ibv_dereg_mr(krm->mr); + + if(krm->mem) + free(krm->mem); + + free(krm); + krm = NULL; +} + + +static void kiro_destroy_connection_context (struct kiro_connection_context **ctx) +{ + if(!ctx) + return; + + if(!(*ctx)) + return; + + if((*ctx)->cf_mr_recv) + kiro_destroy_rdma_memory((*ctx)->cf_mr_recv); + if((*ctx)->cf_mr_send) + kiro_destroy_rdma_memory((*ctx)->cf_mr_send); + + //The RDMA-Memory Region normally contains allocated memory from the USER that has + //just been 'registered' for RDMA. DON'T free it! Just deregister it. The user is + //responsible for freeing this memory. + if((*ctx)->rdma_mr) + { + if((*ctx)->rdma_mr->mr) + ibv_dereg_mr((*ctx)->rdma_mr->mr); + + free((*ctx)->rdma_mr); + (*ctx)->rdma_mr = NULL; + } + + free(*ctx); + *ctx = NULL; +} + + +static void kiro_destroy_connection (struct rdma_cm_id **conn) +{ + if(!(*conn)) + return; + + rdma_disconnect(*conn); + struct kiro_connection_context *ctx = (struct kiro_connection_context *)((*conn)->context); + if(ctx) + kiro_destroy_connection_context(&ctx); + + rdma_destroy_ep(*conn); + *conn = NULL; +} + + +#endif //__KIRO_RDMA_H__ \ No newline at end of file diff --git a/src/kiro-server.c b/src/kiro-server.c new file mode 100644 index 0000000..52304c8 --- /dev/null +++ b/src/kiro-server.c @@ -0,0 +1,361 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +/** + * SECTION: kiro-server + * @Short_description: KIRO RDMA Server / Consumer + * @Title: KiroServer + * + * KiroServer implements the server / passive / provider side of the the RDMA + * Communication Channel. It uses a KIRO-TRB to manage its data. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "kiro-server.h" +#include "kiro-rdma.h" +#include "kiro-trb.h" + + +/* + * Definition of 'private' structures and members and macro to access them + */ + +#define KIRO_SERVER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), KIRO_TYPE_SERVER, KiroServerPrivate)) + +struct _KiroServerPrivate { + + /* Properties */ + // PLACEHOLDER // + + /* 'Real' private structures */ + /* (Not accessible by properties) */ + struct rdma_event_channel *ec; // Main Event Channel + struct rdma_cm_id *base; // Base-Listening-Connection + struct kiro_connection *client; // Connection to the client + pthread_t event_listener; // Pointer to the completion-listener thread of this connection + pthread_mutex_t mtx; // Mutex to signal the listener-thread termination + void *mem; // Pointer to the server buffer + size_t mem_size; // Server Buffer Size in bytes + +}; + + +G_DEFINE_TYPE_WITH_PRIVATE (KiroServer, kiro_server, G_TYPE_OBJECT); + + +static void kiro_server_init (KiroServer *self) +{ + KiroServerPrivate *priv = KIRO_SERVER_GET_PRIVATE(self); + memset(priv, 0, sizeof(&priv)); +} + + +static void +kiro_server_finalize (GObject *object) +{ + //PASS +} + + +static void +kiro_server_class_init (KiroServerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = kiro_server_finalize; +} + + +static int connect_client (struct rdma_cm_id *client) +{ + if(!client) + return -1; + + if( -1 == kiro_attach_qp(client)) + { + printf("Could not create a QP for the new connection.\n"); + rdma_destroy_id(client); + return -1; + } + + struct kiro_connection_context *ctx = (struct kiro_connection_context *)calloc(1,sizeof(struct kiro_connection_context)); + if(!ctx) + { + printf("Failed to create connection context.\n"); + rdma_destroy_id(client); + return -1; + } + + ctx->cf_mr_send = (struct kiro_rdma_mem *)calloc(1, sizeof(struct kiro_rdma_mem)); + ctx->cf_mr_recv = (struct kiro_rdma_mem *)calloc(1, sizeof(struct kiro_rdma_mem)); + if(!ctx->cf_mr_recv || !ctx->cf_mr_send) + { + printf("Failed to allocate Control Flow Memory Container.\n"); + goto error; + } + + ctx->cf_mr_recv = kiro_create_rdma_memory(client->pd, sizeof(struct kiro_ctrl_msg), IBV_ACCESS_LOCAL_WRITE); + ctx->cf_mr_send = kiro_create_rdma_memory(client->pd, sizeof(struct kiro_ctrl_msg), IBV_ACCESS_LOCAL_WRITE); + if(!ctx->cf_mr_recv || !ctx->cf_mr_send) + { + printf("Failed to register control message memory.\n"); + goto error; + } + ctx->cf_mr_recv->size = ctx->cf_mr_send->size = sizeof(struct kiro_ctrl_msg); + client->context = ctx; + + if(rdma_post_recv(client, client, ctx->cf_mr_recv->mem, ctx->cf_mr_recv->size, ctx->cf_mr_recv->mr)) + { + printf("Posting preemtive receive for connection failed.\n"); + goto error; + } + + if(rdma_accept(client, NULL)) + { + printf("Failed to establish connection to the client with error: %i.\n", errno); + goto error; + } + printf("Client Connected.\n"); + return 0; + + +error: + rdma_reject(client, NULL, 0); + kiro_destroy_connection_context(&ctx); + rdma_destroy_id(client); + return -1; +} + + +static int welcome_client (struct rdma_cm_id *client, void *mem, size_t mem_size) +{ + struct kiro_connection_context *ctx = (struct kiro_connection_context *)(client->context); + ctx->rdma_mr = (struct kiro_rdma_mem *)calloc(1, sizeof(struct kiro_rdma_mem)); + if(!ctx->rdma_mr) + { + printf("Failed to allocate RDMA Memory Container.\n"); + return -1; + } + + ctx->rdma_mr->mem = mem; + ctx->rdma_mr->size = mem_size; + ctx->rdma_mr->mr = rdma_reg_read(client, ctx->rdma_mr->mem, ctx->rdma_mr->size); + if(!ctx->rdma_mr->mr) + { + printf("Failed to register RDMA Memory Region.\n"); + kiro_destroy_rdma_memory(ctx->rdma_mr); + return -1; + } + + struct kiro_ctrl_msg *msg = (struct kiro_ctrl_msg *)(ctx->cf_mr_send->mem); + msg->msg_type = KIRO_ACK_RDMA; + msg->peer_mri = *(ctx->rdma_mr->mr); + + if(rdma_post_send(client, client, ctx->cf_mr_send->mem, ctx->cf_mr_send->size, ctx->cf_mr_send->mr, IBV_SEND_SIGNALED)) + { + printf("Failure while trying to post SEND.\n"); + kiro_destroy_rdma_memory(ctx->rdma_mr); + return -1; + } + + struct ibv_wc wc; + + if(rdma_get_send_comp(client, &wc) < 0) + { + printf("Failed to post RDMA MRI to client.\n"); + kiro_destroy_rdma_memory(ctx->rdma_mr); + return -1; + } + printf("RDMA MRI sent to client.\n"); + + return 0; +} + + +void * event_loop (void *self) +{ + KiroServerPrivate *priv = KIRO_SERVER_GET_PRIVATE((KiroServer *)self); + struct rdma_cm_event *active_event; + + int stop = 0; + + while(0 == stop) { + if(0 <= rdma_get_cm_event(priv->ec, &active_event)) + { + + struct rdma_cm_event *ev = malloc(sizeof(*active_event)); + if(!ev) + { + printf("Unable to allocate memory for Event handling!\n"); + rdma_ack_cm_event(active_event); + continue; + } + memcpy(ev, active_event, sizeof(*active_event)); + rdma_ack_cm_event(active_event); + + if (ev->event == RDMA_CM_EVENT_CONNECT_REQUEST) + { + + /* + priv->client = (struct kiro_connection *)calloc(1, sizeof(struct kiro_connection)); + if(!(priv->client)) + { + printf("Failed to create container for client connection.\n"); + free(ev); + continue; + } + priv->client->identifier = 0; //First Client + priv->client->id = ev->id; + */ + + if(0 == connect_client(ev->id)) + { + // Connection set-up successfully! (Server) + // Post a welcoming "Recieve" for handshaking + welcome_client(ev->id, priv->mem, priv->mem_size); + } + } + else if(ev->event == RDMA_CM_EVENT_DISCONNECTED) + { + printf("Got disconnect request.\n"); + //pthread_mutex_unlock(&(priv->mtx)); + kiro_destroy_connection(&(ev->id)); + printf("Connection closed successfully\n"); + } + free(ev); + } + + // Mutex will be freed as a signal to stop request + if(0 == pthread_mutex_trylock(&(priv->mtx))) + stop = 1; + } + + printf("Closing Event Listener Thread\n"); + return NULL; +} + + + + +int kiro_server_start (KiroServer *self, char *address, char *port, void* mem, size_t mem_size) +{ + KiroServerPrivate *priv = KIRO_SERVER_GET_PRIVATE(self); + + if(priv->base) + { + printf("Server already started.\n"); + return -1; + } + + if(!mem || mem_size == 0) + { + printf("Invalid memory given to provide.\n"); + return -1; + } + + struct rdma_addrinfo hints, *res_addrinfo; + memset(&hints, 0, sizeof(hints)); + hints.ai_port_space = RDMA_PS_IB; + hints.ai_flags = RAI_PASSIVE; + if(rdma_getaddrinfo(address, port, &hints, &res_addrinfo)) + { + printf("Failed to create address information."); + return -1; + } + + struct ibv_qp_init_attr qp_attr; + memset(&qp_attr, 0, sizeof(qp_attr)); + qp_attr.cap.max_send_wr = 10; + qp_attr.cap.max_recv_wr = 10; + qp_attr.cap.max_send_sge = 1; + qp_attr.cap.max_recv_sge = 1; + qp_attr.qp_context = priv->base; + qp_attr.sq_sig_all = 1; + + if(rdma_create_ep(&(priv->base), res_addrinfo, NULL, &qp_attr)) + { + printf("Endpoint creation failed.\n"); + return -1; + } + printf("Endpoint created.\n"); + + char *addr_local = NULL; + struct sockaddr* src_addr = rdma_get_local_addr(priv->base); + if(!src_addr) + { + addr_local = "NONE"; + } + else + { + addr_local = inet_ntoa(((struct sockaddr_in *)src_addr)->sin_addr); + /* + if(src_addr->sa_family == AF_INET) + addr_local = &(((struct sockaddr_in*)src_addr)->sin_addr); + else + addr_local = &(((struct sockaddr_in6*)src_addr)->sin6_addr); + */ + } + + printf("Bound to address %s:%s\n",addr_local, port); + + if(rdma_listen(priv->base, 0)) + { + printf("Failed to put server into listening state.\n"); + rdma_destroy_ep(priv->base); + return -1; + } + + priv->mem = mem; + priv->mem_size = mem_size; + + priv->ec = rdma_create_event_channel(); + int oldflags = fcntl (priv->ec->fd, F_GETFL, 0); + /* Only change the FD Mode if we were able to get its flags */ + if (oldflags >= 0) { + oldflags |= O_NONBLOCK; + /* Store modified flag word in the descriptor. */ + fcntl (priv->ec->fd, F_SETFL, oldflags); + } + if(rdma_migrate_id(priv->base, priv->ec)) + { + printf("Was unable to migrate connection to new Event Channel.\n"); + rdma_destroy_ep(priv->base); + return -1; + } + + pthread_mutex_init(&(priv->mtx), NULL); + pthread_mutex_lock(&(priv->mtx)); + pthread_create(&(priv->event_listener), NULL, event_loop, self); + + printf("Enpoint listening.\n"); + + sleep(1); + return 0; +} + + + + + + + diff --git a/src/kiro-server.h b/src/kiro-server.h new file mode 100644 index 0000000..cb9b57c --- /dev/null +++ b/src/kiro-server.h @@ -0,0 +1,106 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +/** + * SECTION: kiro-server + * @Short_description: KIRO RDMA Server / Consumer + * @Title: KiroServer + * + * KiroServer implements the server / passive / provider side of the the RDMA + * Communication Channel. It uses a KIRO-TRB to manage its data. + */ + +#ifndef __KIRO_SERVER_H +#define __KIRO_SERVER_H + +#include +#include + +G_BEGIN_DECLS + +#define KIRO_TYPE_SERVER (kiro_server_get_type()) +#define KIRO_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KIRO_TYPE_SERVER, KiroServer)) +#define KIRO_IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KIRO_TYPE_SERVER)) +#define KIRO_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), KIRO_TYPE_SERVER, KiroServerClass)) +#define KIRO_IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), KIRO_TYPE_SERVER)) +#define KIRO_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), KIRO_TYPE_SERVER, KiroServerClass)) + + +typedef struct _KiroServer KiroServer; +typedef struct _KiroServerClass KiroServerClass; +typedef struct _KiroServerPrivate KiroServerPrivate; + + +struct _KiroServer { + + GObject parent; + + /*< private >*/ + KiroServerPrivate *priv; +}; + + +/** + * IbvConnectorInterface: + * + * Base interface for IbvConnectors. + */ + +struct _KiroServerClass { + + GObjectClass parent_class; + +}; + + + +/* GObject and GType functions */ +GType kiro_server_get_type (void); + +GObject kiro_server_new (void); + +/* server functions */ + +/** + * kiro_server_start - Starts the server, providing the given memory + * @server: KIRO SERVER to perform the operation on + * @bind_addr: Local address to bind the server to + * @bind_port: Local port to listen for connections + * @mem: Pointer to the memory that is to be provided + * @mem_size: Size in bytes of the given memory + * Description: + * Starts the server to provide the given memory to any connecting + * client. + * Notes: + * If the bind_addr is NULL, the server will bind to the first device + * it can find on the machine and listen across all IPs. Otherwise it + * will try to bind to the device associated with the given address. + * Address is given as a string of either a hostname or a dot-seperated + * IPv4 address or a colon-seperated IPv6 hex-address. + * If bind_port is NULL the server will choose a free port randomly + * and return the chosen port as return value. + * If server creation fails, -1 is returned instead. + * See also: + * kiro_trb_reshape, kiro_trb_adopt, + * kiro_trb_clone + */ +int kiro_server_start (KiroServer* server, char* bind_addr, char* bind_port, void* mem, size_t mem_size); + +G_END_DECLS + +#endif //__KIRO_SERVER_H \ No newline at end of file diff --git a/src/kiro-trb.c b/src/kiro-trb.c new file mode 100644 index 0000000..e81a4f7 --- /dev/null +++ b/src/kiro-trb.c @@ -0,0 +1,270 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +/** + * SECTION: kiro-trb + * @Short_description: KIRO 'Transmittable Ring Buffer' + * @Title: KiroTrb + * + * KiroTrb implements a 'Transmittable Ring Buffer' that holds all necessary information + * about its content inside itself, so its data can be exchanged between different + * instances of the KiroTrb Class and/or sent over a network. + */ + +#include + +#include +#include +#include +#include "kiro-trb.h" + + +/* + * Definition of 'private' structures and members and macro to access them + */ + +#define KIRO_TRB_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), KIRO_TYPE_TRB, KiroTrbPrivate)) + +struct _KiroTrbPrivate { + + /* Properties */ + // PLACEHOLDER // + + /* 'Real' private structures */ + /* (Not accessible by properties) */ + int initialized; // 1 if Buffer is Valid, 0 otherwise + void *mem; // Access to the actual buffer in Memory + void *frame_top; // First byte of the buffer storage + void *current; // Pointer to the current fill state + uint64_t element_size; + uint64_t max_elements; + uint64_t iteration; // How many times the buffer has wraped around + + /* easy access */ + uint64_t buff_size; +}; + + +G_DEFINE_TYPE_WITH_PRIVATE (KiroTrb, kiro_trb, G_TYPE_OBJECT); + + +static +void kiro_trb_init (KiroTrb *self) +{ + KiroTrbPrivate *priv = KIRO_TRB_GET_PRIVATE(self); + priv->initialized = 0; +} + +static void +kiro_trb_finalize (GObject *object) +{ + KiroTrb *self = KIRO_TRB(object); + KiroTrbPrivate *priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->mem) + free(priv->mem); +} + +static void +kiro_trb_class_init (KiroTrbClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + gobject_class->finalize = kiro_trb_finalize; +} + + +/* Privat functions */ + +void write_header (KiroTrbPrivate* priv) +{ + if(!priv) + return; + struct KiroTrbInfo* tmp_info = (struct KiroTrbInfo*)priv->mem; + tmp_info->buffer_size_bytes = priv->buff_size; + tmp_info->element_size = priv->element_size; + tmp_info->offset = (priv->iteration * priv->max_elements) + ((priv->current - priv->frame_top) / priv->element_size); + memcpy(priv->mem, tmp_info, sizeof(struct KiroTrbInfo)); +} + + + +/* TRB functions */ + +uint64_t kiro_trb_get_element_size (KiroTrb* self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return 0; + return priv->element_size; +} + + +uint64_t kiro_trb_get_max_elements (KiroTrb* self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return 0; + return priv->max_elements; +} + + +uint64_t kiro_trb_get_raw_size (KiroTrb* self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return 0; + return priv->buff_size; +} + + +void* kiro_trb_get_raw_buffer (KiroTrb* self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return NULL; + write_header(priv); + return priv->mem; +} + + + +void* kiro_trb_get_element (KiroTrb* self, uint64_t element) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return NULL; + + uint64_t relative = 0; + if(priv->iteration == 0) + relative = element * priv->element_size; + else + relative = ((priv->current - priv->frame_top) + (priv->element_size * element)) % (priv->buff_size - sizeof(struct KiroTrbInfo)); + + return priv->frame_top + relative; +} + + +void kiro_trb_flush (KiroTrb *self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + priv->iteration = 0; + priv->current = priv->frame_top; + write_header(priv); +} + + +int kiro_trb_is_setup (KiroTrb *self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + return priv->initialized; +} + + +int kiro_trb_reshape (KiroTrb *self, uint64_t element_size, uint64_t element_count) +{ + size_t new_size = (element_size * element_count) + sizeof(struct KiroTrbInfo); + void* newmem = malloc(new_size); + if(!newmem) + return -1; + ((struct KiroTrbInfo *)newmem)->buffer_size_bytes = new_size; + ((struct KiroTrbInfo *)newmem)->element_size = element_size; + ((struct KiroTrbInfo *)newmem)->offset = 0; + kiro_trb_adopt(self, newmem); + return 0; +} + + +int kiro_trb_push (KiroTrb *self, void *element_in) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return -1; + if((priv->current + priv->element_size) > (priv->mem + priv->buff_size)) + return -1; + memcpy(priv->current, element_in, priv->element_size); + priv->current += priv->element_size; + if(priv->current >= priv->frame_top + (priv->element_size * priv->max_elements)) + { + priv->current = priv->frame_top; + priv->iteration++; + } + write_header(priv); + return 0; +} + + +void* kiro_trb_dma_push (KiroTrb *self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return NULL; + if((priv->current + priv->element_size) > (priv->mem + priv->buff_size)) + return NULL; + void *mem_out = priv->current; + priv->current += priv->element_size; + if(priv->current >= priv->frame_top + (priv->element_size * priv->max_elements)) + { + priv->current = priv->frame_top; + priv->iteration++; + } + write_header(priv); + return mem_out; +} + + +void kiro_trb_refresh (KiroTrb *self) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->initialized != 1) + return; + struct KiroTrbInfo *tmp = (struct KiroTrbInfo *)priv->mem; + priv->buff_size = tmp->buffer_size_bytes; + priv->element_size = tmp->element_size; + priv->max_elements = (tmp->buffer_size_bytes - sizeof(struct KiroTrbInfo)) / tmp->element_size; + priv->iteration = tmp->offset / priv->max_elements; + priv->frame_top = priv->mem + sizeof(struct KiroTrbInfo); + priv->current = priv->frame_top + ((tmp->offset % priv->max_elements) * priv->element_size); + priv->initialized = 1; +} + + +void kiro_trb_adopt (KiroTrb *self, void *buff_in) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + if(priv->mem) + free(priv->mem); + priv->mem = buff_in; + priv->initialized = 1; + kiro_trb_refresh(self); +} + + +int kiro_trb_clone (KiroTrb *self, void *buff_in) +{ + KiroTrbPrivate* priv = KIRO_TRB_GET_PRIVATE(self); + struct KiroTrbInfo *header = (struct KiroTrbInfo *)buff_in; + void *newmem = malloc(header->buffer_size_bytes); + if(!newmem) + return -1; + memcpy(newmem, buff_in, header->buffer_size_bytes); + if(priv->mem) + free(priv->mem); + priv->mem = newmem; + priv->initialized = 1; + kiro_trb_refresh(self); + return 0; +} diff --git a/src/kiro-trb.h b/src/kiro-trb.h new file mode 100644 index 0000000..5c2b462 --- /dev/null +++ b/src/kiro-trb.h @@ -0,0 +1,332 @@ +/* Copyright (C) 2014 Timo Dritschler + (Karlsruhe Institute of Technology) + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2.1 of the License, or (at your + option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + details. + + You should have received a copy of the GNU Lesser General Public License along + with this library; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110, USA +*/ + +/** + * SECTION: kiro-trb + * @Short_description: KIRO 'Transmittable Ring Buffer' + * @Title: KiroTrb + * + * KiroTrb implements a 'Transmittable Ring Buffer' that holds all necessary information + * about its content inside itself, so its data can be exchanged between different + * instances of the KiroTrb Class and/or sent over a network. + */ + +#ifndef __KIRO_TRB_H +#define __KIRO_TBR_H + +#include +#include + +G_BEGIN_DECLS + +#define KIRO_TYPE_TRB (kiro_trb_get_type()) +#define KIRO_TRB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), KIRO_TYPE_TRB, KiroTrb)) +#define KIRO_IS_TRB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), KIRO_TYPE_TRB)) +#define KIRO_TRB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), KIRO_TYPE_TRB, KiroTrbClass)) +#define KIRO_IS_TRB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), KIRO_TYPE_TRB)) +#define KIRO_TRB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), KIRO_TYPE_TRB, KiroTrbClass)) + + +typedef struct _KiroTrb KiroTrb; +typedef struct _KiroTrbClass KiroTrbClass; +typedef struct _KiroTrbPrivate KiroTrbPrivate; + + +struct _KiroTrb { + + GObject parent; + +}; + + +/** + * IbvConnectorInterface: + * + * Base interface for IbvConnectors. + */ + +struct _KiroTrbClass { + + GObjectClass parent_class; + +}; + + +struct KiroTrbInfo { + + /* internal information about the buffer */ + uint64_t buffer_size_bytes; // Size in bytes INCLUDING this header + uint64_t element_size; // Size in bytes of one single element + uint64_t offset; // Current Offset to access the 'oldest' element (in element count!) + +} __attribute__((packed)); + + +/* GObject and GType functions */ +GType kiro_trb_get_type (void); + +GObject kiro_trb_new (void); + + +/* trb functions */ + +/** + * kiro_trb_get_element_size - Returns the element size in bytes + * @trb: KIRO TRB to perform the operation on + * Description: + * Returns the size of the individual elements in the buffer + * See also: + * kiro_trb_reshape, kiro_trb_adopt, kiro_trb_clone + */ +uint64_t kiro_trb_get_element_size (KiroTrb* trb); + +/** + * kiro_trb_get_max_elements - Returns the capacity of the buffer + * @trb: KIRO TRB to perform the operation on + * Description: + * Returns the mximal number of elements that can be stored in + * the buffer + * See also: + * kiro_trb_get_element_size, kiro_trb_reshape, kiro_trb_adopt, + * kiro_trb_clone + */ +uint64_t kiro_trb_get_max_elements (KiroTrb* trb); + + +/** + * kiro_trb_get_raw_size - Returns the size of the buffer memory + * @trb: KIRO TRB to perform the operation on + * Description: + * Returns the size of the buffers internal memory + * Notes: + * The returned size is given INCLUDING the header on top of the + * buffers internal memory + * See also: + * kiro_trb_reshape, kiro_trb_adopt, + * kiro_trb_clone + */ +uint64_t kiro_trb_get_raw_size (KiroTrb* trb); + + +/** + * kiro_trb_get_raw_buffer - Returns a pointer to the buffer memory + * @trb: KIRO TRB to perform the operation on + * Description: + * Returns a pointer to the memory structure of the given buffer. + * Notes: + * The returned pointer points to the beginning of the internal + * memory of the buffer, including all header information. The + * user is responsible to ensure the consistency of any data + * written to the memory and should call 'kiro_trb_refesh' in + * case any header information was changed. + * The pointed to memory might become invalid at any time by + * concurrent access to the TRB, reshaping, adopting or cloning + * a new memory block. + * Under no circumstances might the memory pointed to by the returned + * pointer be 'freed' by the user! + * If this function is called on a buffer that is not yet setup, + * a NULL pointer is returned instead. + * See also: + * kiro_trb_refesh, kiro_trb_reshape, kiro_trb_adopt, kiro_trb_clone + */ +void* kiro_trb_get_raw_buffer (KiroTrb* trb); + + +/** + * kiro_trb_get_element - Returns a pointer to the element at the given + * index. + * @trb: KIRO TRB to perform the operation on + * @index: Index of the element in the buffer to access + * Description: + * Returns a pointer to the element in the buffer at the given index. + * Notes: + * The returned pointer to the element is only guaranteed to be valid + * immediately after the function call. The user is responsible to + * ensure that no data is written to the returned memory. The + * element pointed to might become invalid at any time by any concurrent + * access to the buffer wraping around and overwriting the element or + * changing the buffer memory entirely. + * Under no circumstances might the memory pointed to by the returned + * pointer be 'freed' by the user! + * If this function is called on a buffer that is not yet setup, + * a NULL pointer is returned instead. + * See also: + * kiro_trb_get_element_size, kiro_trb_get_raw_buffer + */ +void* kiro_trb_get_element (KiroTrb* trb, uint64_t index); + + +/** + * kiro_trb_dma_push - Gives DMA to the next element and pushes the buffer + * @trb: KIRO TRB to perform the operation on + * Description: + * Returns a pointer to the next element in the buffer and increases + * all internal counters and meta data as if an element was pushed + * onto the buffer. + * Notes: + * The returned pointer to the element is only guaranteed to be valid + * immediately after the function call. The user is responsible to + * ensure that no more data is written than 'element_size'. The + * element pointed to might become invalid at any time by any concurrent + * access to the buffer wraping around and overwriting the element or + * changing the buffer memory entirely. + * Under no circumstances might the memory pointed to by the returned + * pointer be 'freed' by the user! + * If this function is called on a buffer that is not yet setup, + * a NULL pointer is returned instead. + * See also: + * kiro_trb_push, kiro_trb_get_element_size, kiro_trb_get_raw_buffer + */ +void* kiro_trb_dma_push (KiroTrb*); + + +/** + * kiro_trb_flush - Resets the buffer + * @trb: KIRO TRB to perform the operation on + * Description: + * Resets the internal buffer structures so the buffer is + * 'empty' again. + * Notes: + * The underlying memory is not cleared, freed or rewritten. + * Only the header is rewritten and the internal pointer and + * counter structures get reset to zero. + * See also: + * kiro_trb_reshape, kiro_trb_adopt, kiro_trb_clone + */ +void kiro_trb_flush (KiroTrb* trb); + + +/** + * kiro_trb_is_setup - Returns the setup status of the buffer + * @trb: KIRO TRB to perform the operation on + * Description: + * Returns an integer designating of the buffer is ready to + * be used or needs to be 'reshaped' before it can accept data + * Notes: + * A return value of 0 designates that the buffer is not ready + * to be used. Values greater than 0 designate that the buffer + * is setup properly and is ready to accept data. + * See also: + * kiro_trb_reshape, kiro_trb_adopt, kiro_trb_clone + */ +int kiro_trb_is_setup (KiroTrb* trb); + + +/** + * kiro_trb_reshape - Reallocates internal memory and structures + * @trb: KIRO TRB to perform the operation on + * @element_size: Individual size of the elements to store in bytes + * @element_count: Maximum number of elements to be stored + * Description: + * (Re)Allocates internal memory for the given ammount of elements + * at the given individual size + * Notes: + * If this function gets called when the buffer already has internal + * memory (buffer is setup), that memory gets freed automatically. + * If the function fails (Negative return value) none of the old + * memory and data structures get changed. + * See also: + * kiro_trb_is_setup, kiro_trb_reshape, kiro_trb_adopt, kiro_trb_clone + */ +int kiro_trb_reshape (KiroTrb* trb, uint64_t element_size, uint64_t element_count); + + +/** + * kiro_trb_clone - Clones the given memory into the internal memory + * @trb: KIRO TRB to perform the operation on + * @source: Pointer to the source memory to clone from + * Description: + * Interprets the given memory as a pointer to another KIRO TRB and + * tries to copy that memory into its own. + * Notes: + * The given memory is treated as a correct KIRO TRB memory block, + * including a consistend memory header. That header is read and + * then cloned into the internal memory according to the headers + * information. + * If the given memory is not a consistent KIRO TRB memory block, + * the behavior of this function is undefined. + * Returns 0 if the buffer was cloned and -1 if memory allocation + * failed. + * See also: + * kiro_trb_reshape, kiro_trb_adopt + */ +int kiro_trb_clone (KiroTrb* trb, void* source); + + +/** + * kiro_trb_push - Adds an element into the buffer + * @trb: KIRO TRB to perform the operation on + * @source: Pointer to the memory of the element to add + * Description: + * Copies the given element and adds it into the buffer + * Notes: + * This function will read n-Bytes from the given address according + * to the setup element_size. The read memory is copied directly + * into the internal memory structure. + * Returns 0 on success, -1 on failure. + * In case of failure, no internal memory will change as if the + * call to kiro_trb_push has never happened. + * See also: + * kiro_trb_dma_push, kiro_trb_get_element_size, kiro_trb_clone, + * kiro_trb_adopt + */ +int kiro_trb_push (KiroTrb* trb, void* source); + + +/** + * kiro_trb_refresh - Re-reads the TRBs memory header + * @trb: KIRO TRB to perform the operation on + * Description: + * Re-reads the internal memory header and sets up all pointers + * and counters in accordance to these information + * Notes: + * This function is used in case the TRBs memory got changed + * directly (For example, by a DMA operation) to make the TRB + * aware of the changes to its memory. Only the buffers memory + * header is examined and changes are made according to these + * informations. + * See also: + * kiro_trb_get_raw_buffer, kiro_trb_push_dma, kiro_trb_adopt + */ +void kiro_trb_refresh (KiroTrb* trb); + + +/** + * kiro_trb_adopt - Adopts the given memory into the TRB + * @trb: KIRO TRB to perform the operation on + * @source: Pointer to the source memory to adopt + * Description: + * Interprets the given memory as a pointer to another KIRO TRB and + * takes ownership over the memory. + * Notes: + * The given memory is treated as a correct KIRO TRB memory block, + * including a consistend memory header. That header is read and + * the TRB sets up all internal structures in accordance to that + * header. + * If the given memory is not a consistent KIRO TRB memory block, + * the behavior of this function is undefined. + * The TRB takes full ownership of the given memory and may free + * it at will. + * See also: + * kiro_trb_clone, kiro_trb_reshape + */ +void kiro_trb_adopt (KiroTrb* trb, void* source); + +G_END_DECLS + +#endif //__KIRO_TRB_H \ No newline at end of file -- cgit v1.2.3