Program Listing for File agnocast_ioctl.hpp

Return to documentation for file (include/agnocast/agnocast_ioctl.hpp)

#pragma once

#include <sys/ioctl.h>
#include <sys/types.h>

#include <algorithm>
#include <cstdint>

namespace agnocast
{

#define MAX_PUBLISHER_NUM 1024   // Maximum number of publishers per topic
#define MAX_TOPIC_LOCAL_ID 4096  // Bitmap size for per-entry subscriber reference tracking
#define MAX_SUBSCRIBER_NUM \
  (MAX_TOPIC_LOCAL_ID - MAX_PUBLISHER_NUM)  // Maximum number of subscribers per topic
/* Maximum number of entries that can be received at one ioctl. This value is heuristically set to
 * balance the number of calling ioctl and the overhead of copying data between user and kernel
 * space. */
#define MAX_RECEIVE_NUM 10
#define MAX_RELEASE_NUM 3      // Maximum number of entries that can be released at one ioctl
#define VERSION_BUFFER_LEN 32  // Maximum size of version number represented as a string

#define MAX_TOPIC_INFO_RET_NUM std::max(MAX_PUBLISHER_NUM, MAX_SUBSCRIBER_NUM)

#define NODE_NAME_BUFFER_SIZE 256
#define TOPIC_NAME_BUFFER_SIZE 256
#define MAX_SUBSCRIPTION_NUM_PER_PROCESS 256

constexpr const char * AGNOCAST_DEVICE_NOT_FOUND_MSG =
  "Failed to open /dev/agnocast: Device not found. "
  "Please ensure the agnocast kernel module is installed. "
  "Run 'sudo modprobe agnocast' or 'sudo insmod <path-to-agnocast.ko>' to load the module.";

using topic_local_id_t = int32_t;
struct publisher_shm_info
{
  pid_t pid;
  uint64_t shm_addr;
  uint64_t shm_size;
};
struct name_info
{
  const char * ptr;
  uint64_t len;
};

struct ioctl_get_version_args
{
  char ret_version[VERSION_BUFFER_LEN];
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_add_process_args {
  struct
  {
    bool is_performance_bridge_manager;
  };
  struct
  {
    uint64_t ret_addr;
    uint64_t ret_shm_size;
    bool ret_unlink_daemon_exist;
    bool ret_performance_bridge_daemon_exist;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_add_subscriber_args {
  struct
  {
    struct name_info topic_name;
    struct name_info node_name;
    uint32_t qos_depth;
    bool qos_is_transient_local;
    bool qos_is_reliable;
    bool is_take_sub;
    bool ignore_local_publications;
    bool is_bridge;
  };
  struct
  {
    topic_local_id_t ret_id;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_add_publisher_args {
  struct
  {
    struct name_info topic_name;
    struct name_info node_name;
    uint32_t qos_depth;
    bool qos_is_transient_local;
    bool is_bridge;
  };
  struct
  {
    topic_local_id_t ret_id;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
struct ioctl_update_entry_args
{
  struct name_info topic_name;
  topic_local_id_t pubsub_id;
  int64_t entry_id;
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_receive_msg_args {
  struct
  {
    struct name_info topic_name;
    topic_local_id_t subscriber_id;
    // Unlike ret_* fields which are returned via the union copy, publisher shm info is written
    // directly to this user-space buffer via copy_to_user. The caller must ensure the buffer
    // remains valid until the ioctl returns.
    uint64_t pub_shm_info_addr;
    uint32_t pub_shm_info_size;
  };
  struct
  {
    uint16_t ret_entry_num;
    bool ret_call_again;
    int64_t ret_entry_ids[MAX_RECEIVE_NUM];
    uint64_t ret_entry_addrs[MAX_RECEIVE_NUM];
    uint32_t ret_pub_shm_num;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_publish_msg_args {
  struct
  {
    struct name_info topic_name;
    topic_local_id_t publisher_id;
    uint64_t msg_virtual_address;
    // Unlike ret_* fields which are returned via the union copy, subscriber IDs are written
    // directly to this user-space buffer via copy_to_user. The caller must ensure the buffer
    // remains valid until the ioctl returns.
    uint64_t subscriber_ids_buffer_addr;
    uint32_t subscriber_ids_buffer_size;
  };
  struct
  {
    int64_t ret_entry_id;
    uint32_t ret_subscriber_num;
    uint32_t ret_released_num;
    uint64_t ret_released_addrs[MAX_RELEASE_NUM];
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_take_msg_args {
  struct
  {
    struct name_info topic_name;
    topic_local_id_t subscriber_id;
    bool allow_same_message;
    // Unlike ret_* fields which are returned via the union copy, publisher shm info is written
    // directly to this user-space buffer via copy_to_user. The caller must ensure the buffer
    // remains valid until the ioctl returns.
    uint64_t pub_shm_info_addr;
    uint32_t pub_shm_info_size;
  };
  struct
  {
    uint64_t ret_addr;
    int64_t ret_entry_id;
    uint32_t ret_pub_shm_num;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_get_subscriber_num_args {
  struct name_info topic_name;
  struct
  {
    uint32_t ret_other_process_subscriber_num;
    uint32_t ret_same_process_subscriber_num;
    uint32_t ret_ros2_subscriber_num;
    bool ret_a2r_bridge_exist;
    bool ret_r2a_bridge_exist;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_get_publisher_num_args {
  struct name_info topic_name;
  struct
  {
    uint32_t ret_publisher_num;
    uint32_t ret_ros2_publisher_num;
    bool ret_r2a_bridge_exist;
    bool ret_a2r_bridge_exist;
  };
};
#pragma GCC diagnostic pop

struct exit_subscription_mq_info
{
  char topic_name[TOPIC_NAME_BUFFER_SIZE];
  topic_local_id_t subscriber_id;
};

struct ioctl_get_exit_process_args
{
  // input: user-space buffer for subscription MQ info
  uint64_t subscription_mq_info_buffer_addr;
  uint32_t subscription_mq_info_buffer_size;
  // output
  bool ret_daemon_should_exit;
  pid_t ret_pid;
  uint32_t ret_subscription_mq_info_num;
};

struct topic_info_ret
{
  char node_name[NODE_NAME_BUFFER_SIZE];
  uint32_t qos_depth;
  bool qos_is_transient_local;
  bool qos_is_reliable;
  bool is_bridge;
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
union ioctl_topic_info_args {
  struct
  {
    struct name_info topic_name;
    uint64_t topic_info_ret_buffer_addr;
    uint32_t topic_info_ret_buffer_size;
  };
  uint32_t ret_topic_info_ret_num;
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
struct ioctl_get_subscriber_qos_args
{
  struct
  {
    struct name_info topic_name;
    topic_local_id_t subscriber_id;
  };
  struct
  {
    uint32_t ret_depth;
    bool ret_is_transient_local;
    bool ret_is_reliable;
  };
};
#pragma GCC diagnostic pop

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
struct ioctl_get_publisher_qos_args
{
  struct
  {
    struct name_info topic_name;
    topic_local_id_t publisher_id;
  };
  struct
  {
    uint32_t ret_depth;
    bool ret_is_transient_local;
  };
};
#pragma GCC diagnostic pop

struct ioctl_remove_subscriber_args
{
  struct name_info topic_name;
  topic_local_id_t subscriber_id;
};

struct ioctl_remove_publisher_args
{
  struct name_info topic_name;
  topic_local_id_t publisher_id;
};

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
struct ioctl_add_bridge_args
{
  struct
  {
    struct name_info topic_name;
    bool is_r2a;
  };
  struct
  {
    pid_t ret_pid;
    bool ret_has_r2a;
    bool ret_has_a2r;
  };
};
#pragma GCC diagnostic pop

struct ioctl_remove_bridge_args
{
  struct name_info topic_name;
  bool is_r2a;
};

struct ioctl_check_and_request_bridge_shutdown_args
{
  bool ret_should_shutdown;
};

struct ioctl_set_ros2_subscriber_num_args
{
  struct name_info topic_name;
  uint32_t ros2_subscriber_num;
};

struct ioctl_set_ros2_publisher_num_args
{
  struct name_info topic_name;
  uint32_t ros2_publisher_num;
};

#define AGNOCAST_GET_VERSION_CMD _IOR(0xA6, 1, struct ioctl_get_version_args)
#define AGNOCAST_ADD_PROCESS_CMD _IOWR(0xA6, 2, union ioctl_add_process_args)
#define AGNOCAST_ADD_SUBSCRIBER_CMD _IOWR(0xA6, 3, union ioctl_add_subscriber_args)
#define AGNOCAST_ADD_PUBLISHER_CMD _IOWR(0xA6, 4, union ioctl_add_publisher_args)
#define AGNOCAST_RELEASE_SUB_REF_CMD _IOW(0xA6, 6, struct ioctl_update_entry_args)
#define AGNOCAST_PUBLISH_MSG_CMD _IOWR(0xA6, 7, union ioctl_publish_msg_args)
#define AGNOCAST_RECEIVE_MSG_CMD _IOWR(0xA6, 8, union ioctl_receive_msg_args)
#define AGNOCAST_TAKE_MSG_CMD _IOWR(0xA6, 9, union ioctl_take_msg_args)
#define AGNOCAST_GET_SUBSCRIBER_NUM_CMD _IOWR(0xA6, 10, union ioctl_get_subscriber_num_args)
#define AGNOCAST_GET_EXIT_PROCESS_CMD _IOWR(0xA6, 11, struct ioctl_get_exit_process_args)
#define AGNOCAST_GET_SUBSCRIBER_QOS_CMD _IOWR(0xA6, 12, struct ioctl_get_subscriber_qos_args)
#define AGNOCAST_GET_PUBLISHER_QOS_CMD _IOWR(0xA6, 13, struct ioctl_get_publisher_qos_args)
#define AGNOCAST_ADD_BRIDGE_CMD _IOWR(0xA6, 14, struct ioctl_add_bridge_args)
#define AGNOCAST_REMOVE_BRIDGE_CMD _IOW(0xA6, 15, struct ioctl_remove_bridge_args)
#define AGNOCAST_GET_PUBLISHER_NUM_CMD _IOWR(0xA6, 16, union ioctl_get_publisher_num_args)
#define AGNOCAST_REMOVE_SUBSCRIBER_CMD _IOW(0xA6, 17, struct ioctl_remove_subscriber_args)
#define AGNOCAST_REMOVE_PUBLISHER_CMD _IOW(0xA6, 18, struct ioctl_remove_publisher_args)
#define AGNOCAST_CHECK_AND_REQUEST_BRIDGE_SHUTDOWN_CMD \
  _IOR(0xA6, 19, struct ioctl_check_and_request_bridge_shutdown_args)
#define AGNOCAST_GET_TOPIC_SUBSCRIBER_INFO_CMD _IOWR(0xA6, 21, union ioctl_topic_info_args)
#define AGNOCAST_SET_ROS2_SUBSCRIBER_NUM_CMD \
  _IOW(0xA6, 25, struct ioctl_set_ros2_subscriber_num_args)
#define AGNOCAST_SET_ROS2_PUBLISHER_NUM_CMD _IOW(0xA6, 26, struct ioctl_set_ros2_publisher_num_args)
#define AGNOCAST_NOTIFY_BRIDGE_SHUTDOWN_CMD _IO(0xA6, 27)

}  // namespace agnocast