TCP输入 之 tcp_prequeue
在未开启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的更多相关文章
- TCP输入 之 tcp_rcv_established
概述 tcp_rcv_established用于处理已连接状态下的输入,处理过程根据首部预测字段分为快速路径和慢速路径: 1. 在快路中,对是有有数据负荷进行不同处理: (1) 若无数据,则处理输入a ...
- TCP输入 之 tcp_v4_rcv
tcp_v4_rcv函数为TCP的总入口,数据包从IP层传递上来,进入该函数:其协议操作函数结构如下所示,其中handler即为IP层向TCP传递数据包的回调函数,设置为tcp_v4_rcv: sta ...
- tcp 输入 简析 转载
正常来说 TCP 收消息过程会涉及三个队列: Backlog Queue sk->sk_backlog Prequeue tp->ucopy.prequeue Receive Queue ...
- tcp 输入 prequeue以及backlog队列
/*ipv4_specific是TCP传输层到网络层数据发送以及TCP建立过程的真正OPS, 在tcp_prot->init中被赋值给inet_connection_sock->icsk_ ...
- TCP输入 之 快速路径和慢速路径
概述 快速路径:用于处理预期的,理想情况下的数据段,在这种情况下,不会对一些边缘情形进行检测,进而达到快速处理的目的: 慢速路径:用于处理那些非预期的,非理想情况下的数据段,即不满足快速路径的情况下数 ...
- TCP输入 之 tcp_data_queue
tcp_data_queue作用为数据段的接收处理,其中分为多种情况: (1) 无数据,释放skb,返回: (2) 预期接收的数据段,a. 进行0窗口判断:b. 进程上下文,复制数据到用户空间:c. ...
- TCP输入 之 tcp_queue_rcv
tcp_queue_rcv用于将接收到的skb加入到接收队列receive_queue中,首先会调用tcp_try_coalesce进行分段合并到队列中最后一个skb的尝试,若失败则调用__skb_q ...
- 前端学HTTP之连接管理
前面的话 HTTP连接是HTTP报文传输的关键通道.要掌握HTTP就需要理解HTTP连接的来龙去脉以及如何使用这些连接 如果想查看一个网页,浏览器收到URL时,会执行下图所示的步骤.将服务器的IP地址 ...
- atitit.http原理与概论attilax总结
atitit.http原理与概论attilax总结 1. 图解HTTP 作者:[日]上野宣 著1 2. HTTP权威指南(国内首本HTTP及其相关核心Web技术权威著作)1 3. TCP/IP详解(中 ...
随机推荐
- 13 Django之中间件
一.什么是中间件 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影 ...
- JS中的SRC
当应用SRC属性时,首先需要创建一个JS文件.为什么不在此文件中使用<script>标记?您可以直接使用输出语句吗?我会分享我的报告一个答案 JS文件不是HTM文件,因此内部不能有HTML ...
- Java高并发程序设计学习笔记(七):并行设计模式
转自:https://blog.csdn.net/dataiyangu/article/details/87123586 什么是设计模式架构模式设计模式代码模式(成例 Idiom)单例模式普通单例假如 ...
- ASE19 团队项目 模型组 scrum report集合
scrum report 链接 scrum1 report scrum2 report scrum3 report scrum4 report scrum5 report scrum6 report ...
- 基于Dockerfile搭建JAVA Tomcat运行环境
前言 在第一篇文字中,我们完全人工方式,一个命令一个命令输入,实现一个java tomcat运行环境,虽然也初见成效,但很累人.如果依靠依靠脚本构建一个Tomcat容器实例,一个命令可以搞定,何乐而不 ...
- ubuntu install opencv
1. install the newest opencv version pip install opencv-python
- SQL语句复习【专题三】
SQL语句复习[专题三] DML 数据操作语言[insert into update delete]创建表 简单的方式[使用查询的结果集来创建一张表]create table temp as sele ...
- three.js之创建坐标系网格
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>My first thr ...
- Hadoop_04_Hadoop 的HDFS客户端shell命令
1.Hdfs shell客户端命令操作: 1.1.查看命令列表:hadoop fs 帮助如下: Usage: hadoop fs [generic options] [-appendToFile &l ...
- C++——函数
C++基础函数 (一)函数的参数传递 在没有调用函数之前,函数的形参并没有占据实际的空间. 1.值传递 传入的仅仅只是一个值--就是把实参的值赋给形参.形参自己会在内存中开辟一个空间! 2.传引用 这 ...