/* Copyright 2019-2020 National Research Foundation (SARAO)
 *
 * This program 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 3 of the License, or (at your option) any
 * later version.
 *
 * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file
 *
 * This file is automatically generated. Do not edit.
 */

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <spead2/common_features.h>

#if SPEAD2_USE_MLX5DV

#include <spead2/common_loader_mlx5dv.h>
#include <spead2/common_loader_utils.h>
#include <spead2/common_logging.h>
#include <mutex>
#include <exception>

namespace spead2
{

static std::once_flag init_once;
static std::exception_ptr init_result;

static void init();

bool mlx5dv_is_supported_stub(struct ibv_device *device)
{
    (void) device;
    std::rethrow_exception(init_result);
}

bool mlx5dv_is_supported_first(struct ibv_device *device)
{
    std::call_once(init_once, init);
    return mlx5dv_is_supported(device);
}

int mlx5dv_query_device_stub(struct ibv_context *ctx_in, struct mlx5dv_context *attrs_out)
{
    (void) ctx_in;
    (void) attrs_out;
    std::rethrow_exception(init_result);
}

int mlx5dv_query_device_first(struct ibv_context *ctx_in, struct mlx5dv_context *attrs_out)
{
    std::call_once(init_once, init);
    return mlx5dv_query_device(ctx_in, attrs_out);
}

struct ibv_wq *mlx5dv_create_wq_stub(struct ibv_context *context, struct ibv_wq_init_attr *wq_init_attr, struct mlx5dv_wq_init_attr *mlx5_wq_attr)
{
    (void) context;
    (void) wq_init_attr;
    (void) mlx5_wq_attr;
    std::rethrow_exception(init_result);
}

struct ibv_wq *mlx5dv_create_wq_first(struct ibv_context *context, struct ibv_wq_init_attr *wq_init_attr, struct mlx5dv_wq_init_attr *mlx5_wq_attr)
{
    std::call_once(init_once, init);
    return mlx5dv_create_wq(context, wq_init_attr, mlx5_wq_attr);
}

int mlx5dv_init_obj_stub(struct mlx5dv_obj *obj, uint64_t obj_type)
{
    (void) obj;
    (void) obj_type;
    std::rethrow_exception(init_result);
}

int mlx5dv_init_obj_first(struct mlx5dv_obj *obj, uint64_t obj_type)
{
    std::call_once(init_once, init);
    return mlx5dv_init_obj(obj, obj_type);
}


bool (*mlx5dv_is_supported)(struct ibv_device *device) = mlx5dv_is_supported_first;
int (*mlx5dv_query_device)(struct ibv_context *ctx_in, struct mlx5dv_context *attrs_out) = mlx5dv_query_device_first;
struct ibv_wq *(*mlx5dv_create_wq)(struct ibv_context *context, struct ibv_wq_init_attr *wq_init_attr, struct mlx5dv_wq_init_attr *mlx5_wq_attr) = mlx5dv_create_wq_first;
int (*mlx5dv_init_obj)(struct mlx5dv_obj *obj, uint64_t obj_type) = mlx5dv_init_obj_first;

static void reset_stubs()
{
    mlx5dv_is_supported = mlx5dv_is_supported_stub;
    mlx5dv_query_device = mlx5dv_query_device_stub;
    mlx5dv_create_wq = mlx5dv_create_wq_stub;
    mlx5dv_init_obj = mlx5dv_init_obj_stub;
}

static void init()
{
    try
    {
        dl_handle lib("libmlx5.so.1");
        mlx5dv_is_supported = reinterpret_cast<bool (*)(struct ibv_device *device)>(
            lib.sym("mlx5dv_is_supported"));
        mlx5dv_query_device = reinterpret_cast<int (*)(struct ibv_context *ctx_in, struct mlx5dv_context *attrs_out)>(
            lib.sym("mlx5dv_query_device"));
        mlx5dv_create_wq = reinterpret_cast<struct ibv_wq *(*)(struct ibv_context *context, struct ibv_wq_init_attr *wq_init_attr, struct mlx5dv_wq_init_attr *mlx5_wq_attr)>(
            lib.sym("mlx5dv_create_wq"));
        mlx5dv_init_obj = reinterpret_cast<int (*)(struct mlx5dv_obj *obj, uint64_t obj_type)>(
            lib.sym("mlx5dv_init_obj"));
        // Prevent the library being closed, so that the symbols stay valid
        lib.release();
    }
    catch (std::system_error &e)
    {
        init_result = std::current_exception();
        reset_stubs();
        log_debug("could not load libmlx5.so.1: %s", e.what());
    }
}

} // namespace spead2


#endif // SPEAD2_USE_IBV
