TCP输入 之 tcp_prequeue
时间:2019-10-28
本文章向大家介绍TCP输入 之 tcp_prequeue,主要包括TCP输入 之 tcp_prequeue使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在未开启tcp_low_latency的情况下,软中断将skb送上来,加入到prequeue中,然后
在未启用tcp_low_latency且有用户进程在读取数据的情况下,skb入队到prequeue,入队之后,若达到队列长度上限或者内存上限,则将队列中的skb出队,调用tcp_v4_do_rcv处理,若入队skb为队列的第一个skb,则需要唤醒进程,通知可读事件,并设置延迟ack定时器;
1 bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) 2 { 3 struct tcp_sock *tp = tcp_sk(sk); 4 5 /* 启用了latency || 没有进程读取数据 */ 6 if (sysctl_tcp_low_latency || !tp->ucopy.task) 7 return false; 8 9 /* 长度<= tcp头部长度,无数据&& prequeue队列长度为0,空队列 */ 10 /* 队列为空,无数据skb不入队, 11 有数据或者之前队列中有skb,则入队,防止乱序?? 12 */ 13 if (skb->len <= tcp_hdrlen(skb) && 14 skb_queue_len(&tp->ucopy.prequeue) == 0) 15 return false; 16 17 /* Before escaping RCU protected region, we need to take care of skb 18 * dst. Prequeue is only enabled for established sockets. 19 * For such sockets, we might need the skb dst only to set sk->sk_rx_dst 20 * Instead of doing full sk_rx_dst validity here, let's perform 21 * an optimistic check. 22 */ 23 /* 释放skb路由缓存 */ 24 if (likely(sk->sk_rx_dst)) 25 skb_dst_drop(skb); 26 else 27 skb_dst_force_safe(skb); 28 29 /* 加入队列尾部 */ 30 __skb_queue_tail(&tp->ucopy.prequeue, skb); 31 /* 内存增加 */ 32 tp->ucopy.memory += skb->truesize; 33 34 /* 队列长度>=32 || 内存消耗> rcvbuf */ 35 if (skb_queue_len(&tp->ucopy.prequeue) >= 32 || 36 tp->ucopy.memory + atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) { 37 struct sk_buff *skb1; 38 39 BUG_ON(sock_owned_by_user(sk)); 40 __NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED, 41 skb_queue_len(&tp->ucopy.prequeue)); 42 43 /* skb出队,调用tcp_v4_do_rcv处理 */ 44 while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) 45 sk_backlog_rcv(sk, skb1); 46 47 /* 重置消耗内存 */ 48 tp->ucopy.memory = 0; 49 } 50 /* 空队列新增的第一个skb */ 51 else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { 52 /* 唤醒进程可读 */ 53 wake_up_interruptible_sync_poll(sk_sleep(sk), 54 POLLIN | POLLRDNORM | POLLRDBAND); 55 /* 没有ack要发送,则设置延迟ack定时器 */ 56 if (!inet_csk_ack_scheduled(sk)) 57 inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 58 (3 * tcp_rto_min(sk)) / 4, 59 TCP_RTO_MAX); 60 } 61 return true; 62 }
上面函数中的tp->ucopy.task是在tcp_recvmsg中设置的,简要截取一部分代码,后续补充该函数的详细分析;
1 int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, 2 int flags, int *addr_len) 3 { 4 do { 5 if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) { 6 /* Install new reader */ 7 if (!user_recv && !(flags & (MSG_TRUNC | MSG_PEEK))) { 8 user_recv = current; 9 /* 设置task */ 10 tp->ucopy.task = user_recv; 11 tp->ucopy.msg = msg; 12 } 13 } while (len > 0); 14 15 /*...*/ 16 17 if (user_recv) { 18 if (!skb_queue_empty(&tp->ucopy.prequeue)) { 19 int chunk; 20 21 tp->ucopy.len = copied > 0 ? len : 0; 22 23 tcp_prequeue_process(sk); 24 25 if (copied > 0 && (chunk = len - tp->ucopy.len) != 0) { 26 NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); 27 len -= chunk; 28 copied += chunk; 29 } 30 } 31 /* 清除task */ 32 tp->ucopy.task = NULL; 33 tp->ucopy.len = 0; 34 } 35 }
原文地址:https://www.cnblogs.com/wanpengcoder/p/11752007.html
- 工作流参考模型点评
- 按图索骥:SQL中数据倾斜问题的处理思路与方法
- [方法“Boolean Contains(System.Guid)”不支持转换为 SQL]的解决办法
- DataBind的一些试验
- 继承HibernateDaoSupport时遇到的问题 使用注解为HibernateDaoSupport注入sessionFa
- 常用代码
- 小程序的新功能你知道吗
- Mapxtreme之活活气死
- 仿淘宝的交易到计时JS
- 继小程序之后“小游戏”也来了,微信为此再次开启神秘入口
- (Head First 设计模式)学习笔记(3) --装饰者模式(StarBuzz咖啡店实例)
- 我的Js代码-按钮按下时判断是否选择了最后一行,给出提示
- (Head First 设计模式)学习笔记(2) --观察者模式(气象站实例)
- Spring Boot使用HandlerInterceptorAdapter和WebMvcConfigurerAdapter实现原始的登录验证
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法