diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/kiro-client.c | 256 | ||||
| -rw-r--r-- | src/kiro-client.h | 90 | ||||
| -rw-r--r-- | src/kiro-rdma.h | 230 | ||||
| -rw-r--r-- | src/kiro-server.c | 361 | ||||
| -rw-r--r-- | src/kiro-server.h | 106 | ||||
| -rw-r--r-- | src/kiro-trb.c | 270 | ||||
| -rw-r--r-- | src/kiro-trb.h | 332 | 
8 files changed, 1647 insertions, 0 deletions
| 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 <timo.dritschler@kit.edu> +   (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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <rdma/rdma_verbs.h> +#include <glib.h> +#include "kiro-client.h" +#include "kiro-rdma.h" +#include "kiro-trb.h" + +#include <errno.h> + + +/* + * 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 <timo.dritschler@kit.edu> +   (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 <stdint.h> +#include <glib-object.h> + +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 <timo.dritschler@kit.edu> +   (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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#ifndef __KIRO_RDMA_H__ +#define __KIRO_RDMA_H__ + + +#include <rdma/rdma_cma.h> + +   +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 <timo.dritschler@kit.edu> +   (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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include <rdma/rdma_verbs.h> +#include <glib.h> +#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 <timo.dritschler@kit.edu> +   (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 <stdint.h> +#include <glib-object.h> + +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 <timo.dritschler@kit.edu> +   (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 <stdio.h> +  +#include <stdlib.h> +#include <string.h> +#include <glib.h> +#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 <timo.dritschler@kit.edu> +   (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 <stdint.h> +#include <glib-object.h> + +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 | 
