在未开启tcp_low_latency的情况下,软中断将skb送上来,加入到prequeue中,然后

在未启用tcp_low_latency且有用户进程在读取数据的情况下,skb入队到prequeue,入队之后,若达到队列长度上限或者内存上限,则将队列中的skb出队,调用tcp_v4_do_rcv处理,若入队skb为队列的第一个skb,则需要唤醒进程,通知可读事件,并设置延迟ack定时器;

 bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk); /* 启用了latency || 没有进程读取数据 */
if (sysctl_tcp_low_latency || !tp->ucopy.task)
return false; /* 长度<= tcp头部长度,无数据&& prequeue队列长度为0,空队列 */
/* 队列为空,无数据skb不入队,
有数据或者之前队列中有skb,则入队,防止乱序??
*/
if (skb->len <= tcp_hdrlen(skb) &&
skb_queue_len(&tp->ucopy.prequeue) == )
return false; /* Before escaping RCU protected region, we need to take care of skb
* dst. Prequeue is only enabled for established sockets.
* For such sockets, we might need the skb dst only to set sk->sk_rx_dst
* Instead of doing full sk_rx_dst validity here, let's perform
* an optimistic check.
*/
/* 释放skb路由缓存 */
if (likely(sk->sk_rx_dst))
skb_dst_drop(skb);
else
skb_dst_force_safe(skb); /* 加入队列尾部 */
__skb_queue_tail(&tp->ucopy.prequeue, skb);
/* 内存增加 */
tp->ucopy.memory += skb->truesize; /* 队列长度>=32 || 内存消耗> rcvbuf */
if (skb_queue_len(&tp->ucopy.prequeue) >= ||
tp->ucopy.memory + atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) {
struct sk_buff *skb1; BUG_ON(sock_owned_by_user(sk));
__NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED,
skb_queue_len(&tp->ucopy.prequeue)); /* skb出队,调用tcp_v4_do_rcv处理 */
while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
sk_backlog_rcv(sk, skb1); /* 重置消耗内存 */
tp->ucopy.memory = ;
}
/* 空队列新增的第一个skb */
else if (skb_queue_len(&tp->ucopy.prequeue) == ) {
/* 唤醒进程可读 */
wake_up_interruptible_sync_poll(sk_sleep(sk),
POLLIN | POLLRDNORM | POLLRDBAND);
/* 没有ack要发送,则设置延迟ack定时器 */
if (!inet_csk_ack_scheduled(sk))
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
( * tcp_rto_min(sk)) / ,
TCP_RTO_MAX);
}
return true;
}

上面函数中的tp->ucopy.task是在tcp_recvmsg中设置的,简要截取一部分代码,后续补充该函数的详细分析;

 int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
int flags, int *addr_len)
{
do {
if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) {
/* Install new reader */
if (!user_recv && !(flags & (MSG_TRUNC | MSG_PEEK))) {
user_recv = current;
/* 设置task */
tp->ucopy.task = user_recv;
tp->ucopy.msg = msg;
}
} while (len > ); /*...*/ if (user_recv) {
if (!skb_queue_empty(&tp->ucopy.prequeue)) {
int chunk; tp->ucopy.len = copied > ? len : ; tcp_prequeue_process(sk); if (copied > && (chunk = len - tp->ucopy.len) != ) {
NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk);
len -= chunk;
copied += chunk;
}
}
/* 清除task */
tp->ucopy.task = NULL;
tp->ucopy.len = ;
}
}

TCP输入 之 tcp_prequeue的更多相关文章

  1. TCP输入 之 tcp_rcv_established

    概述 tcp_rcv_established用于处理已连接状态下的输入,处理过程根据首部预测字段分为快速路径和慢速路径: 1. 在快路中,对是有有数据负荷进行不同处理: (1) 若无数据,则处理输入a ...

  2. TCP输入 之 tcp_v4_rcv

    tcp_v4_rcv函数为TCP的总入口,数据包从IP层传递上来,进入该函数:其协议操作函数结构如下所示,其中handler即为IP层向TCP传递数据包的回调函数,设置为tcp_v4_rcv: sta ...

  3. tcp 输入 简析 转载

    正常来说 TCP 收消息过程会涉及三个队列: Backlog Queue sk->sk_backlog Prequeue tp->ucopy.prequeue Receive Queue  ...

  4. tcp 输入 prequeue以及backlog队列

    /*ipv4_specific是TCP传输层到网络层数据发送以及TCP建立过程的真正OPS, 在tcp_prot->init中被赋值给inet_connection_sock->icsk_ ...

  5. TCP输入 之 快速路径和慢速路径

    概述 快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的: 慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数 ...

  6. TCP输入 之 tcp_data_queue

    tcp_data_queue作用为数据段的接收处理,其中分为多种情况: (1) 无数据,释放skb,返回: (2) 预期接收的数据段,a. 进行0窗口判断:b. 进程上下文,复制数据到用户空间:c. ...

  7. TCP输入 之 tcp_queue_rcv

    tcp_queue_rcv用于将接收到的skb加入到接收队列receive_queue中,首先会调用tcp_try_coalesce进行分段合并到队列中最后一个skb的尝试,若失败则调用__skb_q ...

  8. 前端学HTTP之连接管理

    前面的话 HTTP连接是HTTP报文传输的关键通道.要掌握HTTP就需要理解HTTP连接的来龙去脉以及如何使用这些连接 如果想查看一个网页,浏览器收到URL时,会执行下图所示的步骤.将服务器的IP地址 ...

  9. atitit.http原理与概论attilax总结

    atitit.http原理与概论attilax总结 1. 图解HTTP 作者:[日]上野宣 著1 2. HTTP权威指南(国内首本HTTP及其相关核心Web技术权威著作)1 3. TCP/IP详解(中 ...

随机推荐

  1. 【Opencv 源码剖析】 一、 create函数

    1. inline Mat::Mat(int _rows, int _cols, int _type) : size(&rows) { initEmpty();//将data.cols.row ...

  2. Java反射【四、成员变量的反射和构造的反射】

    获取一个类下所有字段信息 Field[] fs = c.getFields(); 获取所有字段(public) Field[] fs = c.getDeclaredFields(); 获取所有声明字段 ...

  3. 关于php的发展前景

    php7 宣称速度比php5.6快两倍,宣称要打破一切旧规则 2015年,php 7.0发布 2016年,php 7.1发布 2017年,php 7.2发布 2018年,php 7.3发布 2019年 ...

  4. 关于PXELINUX的一些重要描述摘录

    以下资源都来自官方文档,原文摘录 PXELINUX is a SYSLINUX derivative, for booting Linux off a network server, using a ...

  5. deep_learning_MNIST数据集

    Code_link:https://pan.baidu.com/s/1dshQt57196fhh67F8nqWow 本文是为既没有机器学习基础也没了解过TensorFlow的码农.序媛们准备的.如果已 ...

  6. docker镜像pull不下来最终解决方法

    pull镜像wordpress下来,但是出现如下错误: # docker pull wordpress:latest Error response from daemon: Get https://r ...

  7. Excel种的数据类型研究【原创】【精】

    因为要做一个项目,开始研究Excel种的数据类型.发现偌大的一个cnblogs竟然没人写这个,自己研究以后记录下来. 在我们通常的认识中,Excel中的数据类型有这么几种 1.常规:2.数值:3.货币 ...

  8. NOIP2017 Day1 T3 逛公园

    NOIP2017 Day1 T3 更好的阅读体验 题目描述 策策同学特别喜欢逛公园.公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,\(N\)号点 ...

  9. 关于GRPC的讲解

    gRPC服务发现&负载均衡 https://segmentfault.com/a/1190000008672912?utm_source=tag-newest GRPC编程指南 gRPC 介绍 ...

  10. 使用IDA Pro逆向C++程序

    使用IDA Pro逆向C++程序 附:中科院李_硕博 : IDA用来做二进制分析还是很强大的 .lib程序是不是很容易分析出源码? 这个得看编译选项是怎么设置的 如果没混淆 没太过优化 大体能恢复源码 ...