Linux C++ 使用 io_uring 技能批量读取 tun 文件形貌符的数据。
以下是参考的实现代码,IO_URING 操作必须要举行按页大小对齐(仅在O_DIRECT直接I/O下),不能是非对称的,一样寻常大多数操作系统页大小为:4KB。批量读取、writev 批量简写。
static constexpr int MTU = ITap::Mtu;
struct io_uring ring;
memset(&ring, 0, sizeof(ring));
struct iovec tun_write_iov_data;
Byte packets;
SsmtThreadLocalTls& tls = ssmt_tls_;
tls.tun_write_iov_data = tun_write_iov_data;
if (io_uring_queue_init(PPP_TUN_ENTRIES_PACKET_SIZE, &ring, 0) < 0) {
Dispose();
return false;
}
bool any = false;
for (int i = 0; i < PPP_TUN_ENTRIES_PACKET_SIZE; i++) {
struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
if (NULL == sqe) {
goto LABEL_exit;
}
io_uring_prep_read(sqe, tun_fd, packets, MTU, 0);
sqe->user_data = (__u64)&packets;
}
io_uring_submit(&ring);
while (!disposed_) {
struct io_uring_cqe* cqes;
__u32 count = io_uring_peek_batch_cqe(&ring, cqes, PPP_TUN_ENTRIES_PACKET_SIZE);
if (count == 0) {
int err = io_uring_wait_cqe(&ring, &cqes);
if (err == -EINTR) {
continue;
}
elif(err >= 0) {
count = 1;
}
else {
break;
}
}
ssmt_tls_.tun_wirte_iov_size = 0;
for (__u32 i = 0; i < count; i++) {
struct io_uring_cqe* cqe = cqes;
assert(NULL != cqe);
Byte* packet = (Byte*)cqe->user_data;
if (int bytes_transferred = cqe->res; bytes_transferred > 0) {
PacketInputEventArgs e{ packet, bytes_transferred };
tls.tun_fd_ = tun_fd;
OnInput(e);
}
struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
assert(NULL != sqe);
io_uring_prep_read(sqe, tun_fd, packet, MTU, 0);
sqe->user_data = (__u64)packet;
io_uring_cqe_seen(&ring, cqe);
}
tls.tun_fd_ = -1;
io_uring_submit(&ring);
if (tls.tun_wirte_iov_size > 0) {
int err = writev(tun_fd, tun_write_iov_data, tls.tun_wirte_iov_size);
for (int i = 0; i < tls.tun_wirte_iov_size; i++) {
struct iovec& iov = tls.tun_write_iov_data;
Mfree(iov.iov_base);
}
tls.tun_wirte_iov_size = 0;
if (err < 0) {
break;
}
}
}
LABEL_exit:
io_uring_queue_exit(&ring);
Dispose();
return any; write 批量收集或超限写出:
bool TapLinux::Output(const void* packet, int packet_size) noexcept {
if (NULL == packet || packet_size < 1) {
return false;
}
int disposed = disposed_.load();
if (disposed != FALSE) {
return false;
}
// https://man7.org/linux/man-pages/man2/write.2.html
int tun = static_cast<int>(reinterpret_cast<std::intptr_t>(GetHandle()));
if (Ssmt()) {
SsmtThreadLocalTls& tls = ssmt_tls_;
int fd = tls.tun_fd_;
if (fd != -1) {
tun = fd;
#if defined(BOOST_ASIO_HAS_IO_URING)
void* packet_copy = Malloc(packet_size);
if (NULL == packet_copy) {
return false;
}
struct iovec& iov = tls.tun_write_iov_data;
memcpy(packet_copy, packet, packet_size);
iov.iov_base = packet_copy;
iov.iov_len = packet_size;
if (tls.tun_wirte_iov_size >= PPP_TUN_ENTRIES_PACKET_SIZE) {
int err = writev(fd, tls.tun_write_iov_data, tls.tun_wirte_iov_size);
for (int i = 0; i < tls.tun_wirte_iov_size; i++) {
struct iovec& iov = tls.tun_write_iov_data;
Mfree(iov.iov_base);
}
tls.tun_wirte_iov_size = 0;
if (err < 0) {
return false;
}
}
#endif
}
}
ssize_t bytes_transferred = ::write(tun, (void*)packet, (size_t)packet_size);
return bytes_transferred > -1;
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]