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详解(中 ...
随机推荐
- js之常用正则
//用户名正则,4到16位(字母,数字,下划线,减号) let uPattern = /^[a-zA-Z0-9_-]{4,16}$/; //密码强度正则,最少6位,包括至少1个大写字母,1个小写字母, ...
- 【持续集成工具】 Jenkins
一.什么是持续集成 持续集成(CI):简单来说就是指将开发者的工作内容频繁地集成到主干中. 而持续集成工具可以将开发者频繁需要构建,编译,测试,部署等操作自动进行,为开发提供了非常大便利. 二.持续集 ...
- Matplotlib 随机漫步图
import matplotlib.pyplot as plt from random import choice class Randomwalk(): def __init__(self,num_ ...
- java_day06_java高级特性
Advance Java Programming 第六章: java语言高级特性(part1) 1.static修饰符 1)static变量 在类中,使用static修饰的成员变量,就是静态变量,反之 ...
- Linux服务器开发:工具
预处理 将所有#defined删除,并且展开 处理所有条件预处理指令 处理#include,将被包含的文件插入到该预编译指令的位置 过滤所有的//./**/ 保留所有#pragma编译指令 编译 词法 ...
- yocto project user’s guide
http://www.yoctoproject.org/docs/2.1/ref-manual/ref-manual.html 参考手册 http://www.yoctoproject.org/doc ...
- 03-【request对象获取请求的数据 & request对象存取值】
request概述(封装了客户端所有的请求数据) request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest.在 ...
- 数据总线&地址总线&控制总线
数据总线 (1) 是CPU与内存或其他器件之间的数据传送的通道. (2)数据总线的宽度决定了CPU和外界的数据传送速度. (3)每条传输线一次只能传输1位二进制数据.eg: 8根数据线一次可传送一个8 ...
- jdk提供的线程协调API suspend/resume wait/notify park/unpark
线程通信(如 线程执行先后顺序,获取某个线程执行的结果等)有多种方式: 文件共享 线程1 --写入--> 文件 < --读取-- 线程2 网络共享 变量共享 线程1 --写入--> ...
- 《Python基础教程》第六章:抽象(一)
用def定义函数 __doc__是函数属性.属性名中的双下划线表示它是个特殊属性