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详解(中 ...
随机推荐
- char 、 unsigned char 互相转化
1. 利用unsigned char (即uchar) 保存char 数据 ,直接赋值即可 unsigned char uc; char c=-33; uc= c; cout<<(int ...
- qq快捷打开聊天窗口的代码
pc代码: http://wpa.qq.com/msgrd?v=3&uin=8423291&site=qq&menu=yes
- vue入门:(计算属性和侦听器)
methods watch computed 一.methods-方法 在数据渲染是需要基于多个数据时第一种方法,可以采用methods属性中的方法计算返回值来实现,先来看示例: <div id ...
- HTML之盒子变形动画
4个圆形球作圆周运动 代码: <div class="box"> <div class="box1"></div> < ...
- Python脚本带-的参数脚本
一.故事背景 由于先前的工作内容是做后台开发,对于脚本写的很少: 昨天参加面试遇到一道面试题,写一个python脚本: 通过脚本的后面的参数选项获取参数选项后面的字符串进行处理: 问题没记错的话大概是 ...
- textarea回填数据显示自适应高度
queryTextArea(){ var textAll = document.getElementById('templaInner').querySelectorAll("textare ...
- 第十章· MySQL的主从复制
一.主从复制简介  2015年5月28日11时,12小时后恢复,损失:平均每小时106.48W$ 1)高可用 2)辅助备份 3)分担负载 复制是 MySQL 的一项功能,允许服务器将更改从一个实例复 ...
- 网络协议相关面试问题-TLS与SSL握手
HTTPS是什么? HTTPS并不是一个单独的协议,而是对工作在一加密连接(SSL / TLS)上的常规HTTP协议.通过在TCP和HTTP之间加入TLS(Transport Layer Securi ...
- 热门前沿知识相关面试问题-MVC/MVP/MVVM架构设计模式面试问题详解
MVC[最常用]: MVC的定义:M:业务逻辑处理.[业务MODEL]V:处理数据显示的部分.[如xml布局文件]C:Activity处理用户交互的问题.[也就是Activity在MVC中扮演着C的角 ...
- qt libusb
https://github.com/Kakadu/Qt_libusb https://github.com/mcvsama/libusbcc/tree/master/src/libusbcc htt ...