【C/C++】手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发

目录

  • [手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发](#手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发)
    • [1. 结构:注册表和就绪表不能混在一起](#1. 结构:注册表和就绪表不能混在一起)
    • [2. 从 TCP 数据到 EPOLLIN](#2. 从 TCP 数据到 EPOLLIN)
    • [3. 使用方式](#3. 使用方式)
    • [4. 并发语义的三个难点](#4. 并发语义的三个难点)
    • 小结

手写 DPDK 协议栈(十二):TCP 并发与自实现 epoll 的就绪事件分发

标签:DPDK TCP epoll 并发 红黑树

tcp_multi/ 在 TCP socket 基础上实现 nepoll_createnepoll_ctlnepoll_wait。它展示了 epoll 的本质:注册表记录"关心什么",就绪队列记录"现在有什么可处理",等待者只从就绪队列取事件。

1. 结构:注册表和就绪表不能混在一起

text 复制代码
epoll instance
  ├─ 红黑树 rbr:sockfd -> epitem,支持 ctl ADD/MOD/DEL
  ├─ 就绪链表 rdlist:仅保存已发生事件的 epitem
  └─ cond + mutex:没有事件时阻塞/唤醒 nepoll_wait

课程 eventpoll 使用红黑树查找注册项,使用链表维护 ready list,并分别对树与就绪表设置同步机制。这样不会在每次 wait 时扫描全部 fd。

c 复制代码
struct eventpoll {
    ep_rb_tree rbr;
    int rbcnt;
    LIST_HEAD(, epitem) rdlist;
    int rdnum;
    pthread_mutex_t mtx;
    pthread_spinlock_t lock;
    pthread_cond_t cond;
};

2. 从 TCP 数据到 EPOLLIN

TCP 协议线程收到 PSH 数据后,将 tcp_offload_t 放入连接的 in ring;socket 层再调用事件回调,将对应 epitem 放入 ready list 并唤醒等待线程。

text 复制代码
NIC RX -> TCP ESTABLISHED
       -> socket.in ring
       -> nepoll_event_callback(ep, sockfd, EPOLLIN)
       -> rdlist
       -> nepoll_wait 返回
       -> nrecv 读取 socket.in

EPOLLOUT 通常在 socket 可继续发送时产生;EPOLLERREPOLLHUPEPOLLRDHUP 则要在 FIN、RST、队列错误等状态转移中明确生成,不能凭空假定。

3. 使用方式

c 复制代码
int epfd = nepoll_create(1024);
struct epoll_event ev = {.events = EPOLLIN, .data.fd = connfd};
nepoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);

struct epoll_event events[128];
int n = nepoll_wait(epfd, events, 128, -1);
for (int i = 0; i < n; i++) {
    if (events[i].events & EPOLLIN)
        nrecv(events[i].data.fd, buf, sizeof(buf), 0);
}

教学接口前缀为 n,用于与 Linux 系统调用区分。应用层永远应在读取前检查返回值,处理短读、关闭与错误。

4. 并发语义的三个难点

  1. 只入 ready list 一次 :同一个 fd 已就绪时再次到包,不能无限重复插入;epitem.rdy 是这一去重状态。
  2. 事件和数据的顺序 :先把数据安全入 socket ring,再发布 EPOLLIN;否则 wait 返回后可能读到空队列。
  3. 删除与回收EPOLL_CTL_DEL、socket close、协议线程回调可能并发,必须先从注册树和 ready list 摘除,再释放对象。

小结

DPDK 负责高性能报文收发,TCP 状态机把包转为 socket 数据,epoll 再把 socket 数据转为应用可等待的事件。三层之间通过明确的队列和所有权衔接,才能在并发连接下既快又可维护。

学习链接: https://github.com/0voice

相关推荐
小小龙学IT43 分钟前
C++ 正则表达式完全指南:从 std::regex 实战到 RE2 引擎原理(NFA/DFA/回溯陷阱)
c++·正则表达式
Fa_Mian_Tuan4 小时前
图论基础|邻接矩阵超详细讲解(含无向/有向/带权图+完整可运行C语言代码)
c语言·数据结构·笔记·算法·图论
码匠许师傅4 小时前
【C++ 面试真题】聊聊 C++ 的序列容器
java·c++·面试
C++ 老炮儿的技术栈4 小时前
Qt5.9.1 Windows 完整开发环境搭建流程
开发语言·c++·windows·qt·编辑器·代码化
欧特克_Glodon4 小时前
OpenCV计算机视觉开发入门与实践<十一>:矩阵的复制和矩形类Rect
c++·opencv·计算机视觉·矩阵
键盘会跳舞5 小时前
C++:std::tuple 源码级深度拆解——变参模板、SFINAE与模板元编程核心技巧
开发语言·c++·sfinae·变参模板
bkspiderx5 小时前
从零开始:VS Code搭建C/C++开发环境全指南(Windows/macOS/Linux)
c语言·c++·windows·vs code·c/c++开发环境
东华万里5 小时前
第40篇C++核心基础与工程实践:从底层逻辑到避坑指南
开发语言·c++·面试·大学生专区
wuyk5555 小时前
第 6 章 FOC 完整系统整合:从算法到真机跑起来
c语言·开发语言·stm32·单片机·嵌入式硬件
luj_17685 小时前
元设计的诱惑与现实
c语言·开发语言·c++·经验分享·算法