prequeue和backlog和receive

本文详细解析了TCP接收过程中skb挂载到prequeue、backlog和receive的不同状态,通过组合sk_lock和ucopy.task的值来表示进程状态,解释了组合4在recv系统调用中 skb挂到prequeue的原因。

网上找了很多文章,对于基础不太好的我来说,还是不懂到底什么时候skb挂到prequeue中,又是什么时候挂到backlog中,或者receive中。

于是只能不停的看代码,尽量每一行都能看懂。功夫不负有心人,终于理解了。在此做一下笔记。


首先,有2种方式表示标识用户正在调用recv函数,及内核的tcp_recvmsg:

1:sk->sk_lock.owned,其值为1表示有进程进入了tcp_recvmsg函数,并且执行了lock_sock。

注意:sk->sk_lock.owned其值为0,肯定是被release了,但是tcp_recvmsg函数中,并不是仅仅执行完函数,退出时,才会执行release。

在sk_wait_data函数中,让进程休眠时,也会release。


2:tp->ucopy.task

不等于null,表示进程正在读数据。


1和2的各个组合,正好能够表示进程的状态:


组合1:

sk->sk_lock.owned ==0 && tp->ucopy.task == null

要么就是压根没调用tcp_recvmsg,要么是调用后,退出了tcp_recvmsg


组合2:

sk->sk_lock.owned ==1 && tp->ucopy.task == null

执行中,即进程上下文中,进程已经进入tcp_recvmsg,但是还没读,准备读。


组合3:

sk->sk_lock.owned ==1 && && tp->ucopy.task ==null

进程进入tcp_recvmsg,并且正在读。


组合4:

sk->sk_lock.owned ==0 && && tp->ucopy.task != null


组合4最最重要!!!!!

tcp_do_rcv函数中,当sk->sk_lock.owned ==0 时,就会去执行tcp_prequeue。

tcp_prequeue中,就是判断如果tp->ucopy.task != null,就把skb挂到prequeue中。

而组合4出现的愿意,就是recv系统调用调用tcp_reccmsg之后,发现skb中的字节数,不够我们需要拷贝的字节数,导致进程休眠,即阻塞形系统调用导致进程休眠,

这种情况下,会将skb挂到prequeue中。



如果sk->sk_lock.owned ==0并且tp->ucopy.task == null,那就乖乖的挂到receive中。

如果sk->sk_lock.owned ==1 ,表示进程正在处于recv调用中,可能在执行代码的某个部分,反正在执行,进程没有休眠,也没有退出。。等等,为了软中断和进程上下文同步,将收到的skb挂到backlog中。进程在release_sock()中会处理backlog队列中的数据。



/* Packet is added to VJ-style prequeue for processing in process
 * context, if a reader task is waiting. Apparently, this exciting
 * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93)
 * failed somewhere. Latency? Burstiness? Well, at least now we will
 * see, why it failed. 8)8)				  --ANK
 *
 * NOTE: is this not too big to inline?
 */
//能进入这个函数,表示sk->sk_lock.owned ==0
static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb)
{
	struct tcp_sock *tp = tcp_sk(sk);

	if (sysctl_tcp_low_latency || !tp->ucopy.task)
		return 0;
//sysctl_tcp_low_latency 默认为0,!tp->ucopy.task不等于null,表示正在读取数据,而进入函数的条件又是进程没有锁住,
//出现这种现象的唯一情况,就是进程没有读够想要的数据,休眠了

	__skb_queue_tail(&tp->ucopy.prequeue, skb);
	tp->ucopy.memory += skb->truesize;
	if (tp->ucopy.memory > sk->sk_rcvbuf) {
		struct sk_buff *skb1;

		BUG_ON(sock_owned_by_user(sk));

		while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) {
			sk_backlog_rcv(sk, skb1);
			NET_INC_STATS_BH(sock_net(sk),
					 LINUX_MIB_TCPPREQUEUEDROPPED);
		}

		tp->ucopy.memory = 0;
	} else if (skb_queue_len(&tp->ucopy.prequeue) == 1) {
//唤醒进程,进程立刻读取prequeue中的数据。
		wake_up_interruptible_poll(sk->sk_sleep,
					   POLLIN | POLLRDNORM | POLLRDBAND);
		if (!inet_csk_ack_scheduled(sk))
			inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
						  (3 * tcp_rto_min(sk)) / 4,
						  TCP_RTO_MAX);
	}
	return 1;
}




<think>我们正在讨论用户故事backlog的关系。根据引用[1][2],用户故事是backlog中的基本单位,它们描述了从用户角度出发的功能需求。backlog作为一个整体,包含了多个用户故事,并且可能还包含其他类型的条目(如技术任务、缺陷等)。引用[1]提到,backlog维护了用户故事到功能点之间的联系,以及功能点对应的功能区域,这样便于跟踪查看。 用户故事通常包含三个要素:角色(who)、活动(what)价值(value)[^2]。在backlog中,这些故事被管理起来,通常按照优先级排序,以便团队知道接下来要开发什么。 引用[3]进一步说明了用户故事的结构,包括用户故事ID、用户角色、目标行为、背后动机、验收标准、优先级状态等字段。这些字段帮助团队理解故事细节,并为开发提供明确的标准。 因此,用户故事与backlog的关系可以总结为: 1. 用户故事是backlog中的主要组成部分,是表达需求的主要形式。 2. backlog是用户故事的容器,它管理着多个用户故事,并可能包含其他类型的条目。 3. backlog通过优先级排序用户故事,指导开发顺序。 4. backlog还维护用户故事与其他系统元素(如功能点、功能区域)的关联,以支持多角度跟踪。 下面我们用代码示例展示一个简单的backlog结构,其中包含用户故事功能点: ```python # 用户故事示例 user_stories = [ { "id": "US001", "title": "作为注册用户,我想修改密码,以便保障账户安全", "acceptance_criteria": "1. 输入原密码正确才能修改;2. 新密码必须符合复杂度要求;3. 修改成功后系统提示成功并发送邮件通知", "priority": "Must", "status": "To Do", "estimated_points": 3 }, { "id": "US002", "title": "作为游客,我想查看商品列表,以便选择感兴趣的商品", "acceptance_criteria": "1. 分页展示商品;2. 可按价格排序;3. 显示商品名称、图片、价格", "priority": "Must", "status": "In Progress", "estimated_points": 5 } ] # 功能点示例 function_points = [ { "id": "FP001", "name": "密码修改功能", "related_user_story": "US001", "function_area": "用户账户管理" }, { "id": "FP002", "name": "商品列表展示", "related_user_story": "US002", "function_area": "商品管理" } ] # Backlog结构 product_backlog = { "user_stories": user_stories, "function_points": function_points } ``` 在这个示例中,backlog包含了用户故事列表功能点列表,并且每个功能点都关联到对应的用户故事。这样,我们可以通过用户故事追踪到实现它的具体功能点,也可以通过功能区域(如“用户账户管理”)来查看相关功能。 §§相关问题§§ 1. 如何将用户故事拆分成更小的开发任务? 2. 在backlog中,除了用户故事还有哪些常见类型的条目? 3. 如何利用用户故事地图来构建backlog? 4. 用户故事被标记为“已完成”的标准是什么? </think>### 用户故事与Backlog的关系详解 用户故事产品待办列表(Backlog)在敏捷开发中形成**分层协作关系**,具体表现为: 1. **用户故事是Backlog的核心内容** - Backlog本质上是一个**用户故事容器**,其中每个条目都是用户故事或由其衍生的任务[^1][^3] - 用户故事作为最小价值单位(PBI),构成Backlog的**基础颗粒**,例如: ```markdown [用户故事ID: Story-001] 角色:注册用户 目标:修改个人密码 价值:保障账户安全 ``` - Backlog通过优先级排序将这些故事组织成**可执行的开发队列**[^1] 2. **Backlog是用户故事的管理框架** - 维护用户故事的关键元数据,包括: - 功能区域映射(如"用户账户管理") - 验收标准(AC) - 优先级(Must/Should/Could) - 状态跟踪(待开发/开发中/已完成)[^1][^3] - 建立**跨维度关联**:通过功能点(Function Point)连接用户故事与底层实现[^1] ```mermaid graph LR A[用户故事] --> B[功能点FP-001] B --> C[功能区域] B --> D[技术任务] ``` 3. **双向价值流动** - **向上**:用户故事确保Backlog始终聚焦**业务价值**(如"保障账户安全")[^2] - **向下**:Backlog将故事转化为**可执行路径**,通过功能点衔接技术实现[^1] - 二者共同维护**用户故事地图**,保障端到端追溯性[^1][^3] 4. **动态演进特性** - 用户故事随需求变化而**细化/拆分**(如将"修改密码"拆解为密码强度验证、邮件通知等子故事) - Backlog通过**持续优先级重排**响应变化,形成"活文档"[^3] ```python # Backlog管理示例 class ProductBacklog: def __init__(self): self.stories = [] # 用户故事列表 self.function_points = [] # 功能点映射 def add_story(self, role, goal, value): new_id = f"Story-{len(self.stories)+1:03d}" self.stories.append({ "id": new_id, "role": role, "goal": goal, "value": value, "status": "To Do" }) return new_id def link_function_point(self, story_id, function_area): self.function_points.append({ "fp_id": f"FP-{len(self.function_points)+1:03d}", "story_id": story_id, "area": function_area }) # 使用示例 backlog = ProductBacklog() story_id = backlog.add_story("注册用户", "修改密码", "账户安全") backlog.link_function_point(story_id, "用户账户管理") ``` ### 关键区别对比 | 维度 | 用户故事 | Backlog | |--------------|------------------------------|-----------------------------| | **本质** | 需求描述单元 | 需求管理容器 | | **焦点** | 用户价值(Why/What)[^2] | 执行顺序(When/How)[^1] | | **形态** | 自然语言描述 | 结构化条目集合 | | **生命周期** | 创建→细化→完成 | 持续演进的优先级队列[^3] | | **维护内容** | 角色/目标/价值/验收标准[^3] | 优先级/状态/关联关系[^1] | 通过这种关系,团队能始终聚焦用户价值,同时保持开发过程的可控性可追溯性[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值