xref: /linux/Documentation/translations/zh_CN/scheduler/completion.rst (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1*f2c3bb11SYanteng Si.. include:: ../disclaimer-zh_CN.rst
2*f2c3bb11SYanteng Si
3*f2c3bb11SYanteng Si:Original: Documentation/scheduler/completion.rst
4*f2c3bb11SYanteng Si
5*f2c3bb11SYanteng Si:翻译:
6*f2c3bb11SYanteng Si
7*f2c3bb11SYanteng Si 司延腾 Yanteng Si <siyanteng@loongson.cn>
8*f2c3bb11SYanteng Si
9*f2c3bb11SYanteng Si:校译:
10*f2c3bb11SYanteng Si
11*f2c3bb11SYanteng Si 唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
12*f2c3bb11SYanteng Si
13*f2c3bb11SYanteng Si=======================================
14*f2c3bb11SYanteng Si完成 - "等待完成" 屏障应用程序接口(API)
15*f2c3bb11SYanteng Si=======================================
16*f2c3bb11SYanteng Si
17*f2c3bb11SYanteng Si简介:
18*f2c3bb11SYanteng Si-----
19*f2c3bb11SYanteng Si
20*f2c3bb11SYanteng Si如果你有一个或多个线程必须等待某些内核活动达到某个点或某个特定的状态,完成可以为这
21*f2c3bb11SYanteng Si个问题提供一个无竞争的解决方案。从语义上讲,它们有点像pthread_barrier(),并且使
22*f2c3bb11SYanteng Si用的案例类似
23*f2c3bb11SYanteng Si
24*f2c3bb11SYanteng Si完成是一种代码同步机制,它比任何滥用锁/信号量和忙等待循环的行为都要好。当你想用yield()
25*f2c3bb11SYanteng Si或一些古怪的msleep(1)循环来允许其它代码继续运行时,你可能想用wait_for_completion*()
26*f2c3bb11SYanteng Si调用和completion()来代替。
27*f2c3bb11SYanteng Si
28*f2c3bb11SYanteng Si使用“完成”的好处是,它们有一个良好定义、聚焦的目标,这不仅使得我们很容易理解代码的意图,
29*f2c3bb11SYanteng Si而且它们也会生成更高效的代码,因为所有线程都可以继续执行,直到真正需要结果的时刻。而且等
30*f2c3bb11SYanteng Si待和信号都高效的使用了低层调度器的睡眠/唤醒设施。
31*f2c3bb11SYanteng Si
32*f2c3bb11SYanteng Si完成是建立在Linux调度器的等待队列和唤醒基础设施之上的。等待队列中的线程所等待的
33*f2c3bb11SYanteng Si事件被简化为 ``struct completion`` 中的一个简单标志,被恰如其名地称为‘done’。
34*f2c3bb11SYanteng Si
35*f2c3bb11SYanteng Si由于完成与调度有关,代码可以在kernel/sched/completion.c中找到。
36*f2c3bb11SYanteng Si
37*f2c3bb11SYanteng Si
38*f2c3bb11SYanteng Si用法:
39*f2c3bb11SYanteng Si-----
40*f2c3bb11SYanteng Si
41*f2c3bb11SYanteng Si使用完成需要三个主要部分:
42*f2c3bb11SYanteng Si
43*f2c3bb11SYanteng Si - 'struct completion' 同步对象的初始化
44*f2c3bb11SYanteng Si - 通过调用wait_for_completion()的一个变体来实现等待部分。
45*f2c3bb11SYanteng Si - 通过调用complete()或complete_all()实现发信端。
46*f2c3bb11SYanteng Si
47*f2c3bb11SYanteng Si也有一些辅助函数用于检查完成的状态。请注意,虽然必须先做初始化,但等待和信号部分可以
48*f2c3bb11SYanteng Si按任何时间顺序出现。也就是说,一个线程在另一个线程检查是否需要等待它之前,已经将一个
49*f2c3bb11SYanteng Si完成标记为 "done",这是完全正常的。
50*f2c3bb11SYanteng Si
51*f2c3bb11SYanteng Si要使用完成API,你需要#include <linux/completion.h>并创建一个静态或动态的
52*f2c3bb11SYanteng Si``struct completion`` 类型的变量,它只有两个字段::
53*f2c3bb11SYanteng Si
54*f2c3bb11SYanteng Si	struct completion {
55*f2c3bb11SYanteng Si		unsigned int done;
56*f2c3bb11SYanteng Si		wait_queue_head_t wait;
57*f2c3bb11SYanteng Si	};
58*f2c3bb11SYanteng Si
59*f2c3bb11SYanteng Si结构体提供了->wait等待队列来放置任务进行等待(如果有的话),以及->done完成标志来表明它
60*f2c3bb11SYanteng Si是否完成。
61*f2c3bb11SYanteng Si
62*f2c3bb11SYanteng Si完成的命名应当与正在被同步的事件名一致。一个好的例子是::
63*f2c3bb11SYanteng Si
64*f2c3bb11SYanteng Si	wait_for_completion(&early_console_added);
65*f2c3bb11SYanteng Si
66*f2c3bb11SYanteng Si	complete(&early_console_added);
67*f2c3bb11SYanteng Si
68*f2c3bb11SYanteng Si好的、直观的命名(一如既往地)有助于代码的可读性。将一个完成命名为 ``complete``
69*f2c3bb11SYanteng Si是没有帮助的,除非其目的是超级明显的...
70*f2c3bb11SYanteng Si
71*f2c3bb11SYanteng Si
72*f2c3bb11SYanteng Si初始化完成:
73*f2c3bb11SYanteng Si-----------
74*f2c3bb11SYanteng Si
75*f2c3bb11SYanteng Si动态分配的完成对象最好被嵌入到数据结构中,以确保在函数/驱动的生命周期内存活,以防
76*f2c3bb11SYanteng Si止与异步complete()调用发生竞争。
77*f2c3bb11SYanteng Si
78*f2c3bb11SYanteng Si在使用wait_for_completion()的_timeout()或_killable()/_interruptible()变体
79*f2c3bb11SYanteng Si时应特别小心,因为必须保证在所有相关活动(complete()或reinit_completion())发生
80*f2c3bb11SYanteng Si之前不会发生内存解除分配,即使这些等待函数由于超时或信号触发而过早返回。
81*f2c3bb11SYanteng Si
82*f2c3bb11SYanteng Si动态分配的完成对象的初始化是通过调用init_completion()来完成的::
83*f2c3bb11SYanteng Si
84*f2c3bb11SYanteng Si	init_completion(&dynamic_object->done);
85*f2c3bb11SYanteng Si
86*f2c3bb11SYanteng Si在这个调用中,我们初始化 waitqueue 并将 ->done 设置为 0,即“not completed”或
87*f2c3bb11SYanteng Si“not done”。
88*f2c3bb11SYanteng Si
89*f2c3bb11SYanteng Si重新初始化函数reinit_completion(),只是将->done字段重置为0(“not done”),而
90*f2c3bb11SYanteng Si不触及等待队列。这个函数的调用者必须确保没有任何令人讨厌的wait_for_completion()
91*f2c3bb11SYanteng Si调用在并行进行。
92*f2c3bb11SYanteng Si
93*f2c3bb11SYanteng Si在同一个完成对象上调用init_completion()两次很可能是一个bug,因为它将队列重新初始
94*f2c3bb11SYanteng Si化为一个空队列,已排队的任务可能会“丢失”--在这种情况下使用reinit_completion(),但
95*f2c3bb11SYanteng Si要注意其他竞争。
96*f2c3bb11SYanteng Si
97*f2c3bb11SYanteng Si对于静态声明和初始化,可以使用宏。
98*f2c3bb11SYanteng Si
99*f2c3bb11SYanteng Si对于文件范围内的静态(或全局)声明,你可以使用 DECLARE_COMPLETION()::
100*f2c3bb11SYanteng Si
101*f2c3bb11SYanteng Si	static DECLARE_COMPLETION(setup_done);
102*f2c3bb11SYanteng Si	DECLARE_COMPLETION(setup_done);
103*f2c3bb11SYanteng Si
104*f2c3bb11SYanteng Si注意,在这种情况下,完成在启动时(或模块加载时)被初始化为“not done”,不需要调用
105*f2c3bb11SYanteng Siinit_completion()。
106*f2c3bb11SYanteng Si
107*f2c3bb11SYanteng Si当完成被声明为一个函数中的局部变量时,那么应该总是明确地使用
108*f2c3bb11SYanteng SiDECLARE_COMPLETION_ONSTACK()来初始化,这不仅仅是为了让lockdep正确运行,也是明确表
109*f2c3bb11SYanteng Si名它有限的使用范围是有意为之并被仔细考虑的::
110*f2c3bb11SYanteng Si
111*f2c3bb11SYanteng Si	DECLARE_COMPLETION_ONSTACK(setup_done)
112*f2c3bb11SYanteng Si
113*f2c3bb11SYanteng Si请注意,当使用完成对象作为局部变量时,你必须敏锐地意识到函数堆栈的短暂生命期:在所有
114*f2c3bb11SYanteng Si活动(如等待的线程)停止并且完成对象完全未被使用之前,函数不得返回到调用上下文。
115*f2c3bb11SYanteng Si
116*f2c3bb11SYanteng Si再次强调这一点:特别是在使用一些具有更复杂结果的等待API变体时,比如超时或信号
117*f2c3bb11SYanteng Si(_timeout(), _killable()和_interruptible())变体,等待可能会提前完成,而对象可
118*f2c3bb11SYanteng Si能仍在被其他线程使用 - 从wait_on_completion*()调用者函数的返回会取消分配函数栈,如
119*f2c3bb11SYanteng Si果complete()在其它某线程中完成调用,会引起微小的数据损坏。简单的测试可能不会触发这
120*f2c3bb11SYanteng Si些类型的竞争。
121*f2c3bb11SYanteng Si
122*f2c3bb11SYanteng Si如果不确定的话,使用动态分配的完成对象, 最好是嵌入到其它一些生命周期长的对象中,长到
123*f2c3bb11SYanteng Si超过使用完成对象的任何辅助线程的生命周期,或者有一个锁或其他同步机制来确保complete()
124*f2c3bb11SYanteng Si不会在一个被释放的对象中调用。
125*f2c3bb11SYanteng Si
126*f2c3bb11SYanteng Si在堆栈上单纯地调用DECLARE_COMPLETION()会触发一个lockdep警告。
127*f2c3bb11SYanteng Si
128*f2c3bb11SYanteng Si等待完成:
129*f2c3bb11SYanteng Si---------
130*f2c3bb11SYanteng Si
131*f2c3bb11SYanteng Si对于一个线程来说,要等待一些并发活动的完成,它要在初始化的完成结构体上调用
132*f2c3bb11SYanteng Siwait_for_completion()::
133*f2c3bb11SYanteng Si
134*f2c3bb11SYanteng Si	void wait_for_completion(struct completion *done)
135*f2c3bb11SYanteng Si
136*f2c3bb11SYanteng Si一个典型的使用场景是::
137*f2c3bb11SYanteng Si
138*f2c3bb11SYanteng Si	CPU#1					CPU#2
139*f2c3bb11SYanteng Si
140*f2c3bb11SYanteng Si	struct completion setup_done;
141*f2c3bb11SYanteng Si
142*f2c3bb11SYanteng Si	init_completion(&setup_done);
143*f2c3bb11SYanteng Si	initialize_work(...,&setup_done,...);
144*f2c3bb11SYanteng Si
145*f2c3bb11SYanteng Si	/* run non-dependent code */		/* do setup */
146*f2c3bb11SYanteng Si
147*f2c3bb11SYanteng Si	wait_for_completion(&setup_done);	complete(setup_done);
148*f2c3bb11SYanteng Si
149*f2c3bb11SYanteng Si这并不意味着调用wait_for_completion()和complete()有任何特定的时间顺序--如果调
150*f2c3bb11SYanteng Si用complete()发生在调用wait_for_completion()之前,那么等待方将立即继续执行,因为
151*f2c3bb11SYanteng Si所有的依赖都得到了满足;如果没有,它将阻塞,直到complete()发出完成的信号。
152*f2c3bb11SYanteng Si
153*f2c3bb11SYanteng Si注意,wait_for_completion()是在调用spin_lock_irq()/spin_unlock_irq(),所以
154*f2c3bb11SYanteng Si只有当你知道中断被启用时才能安全地调用它。从IRQs-off的原子上下文中调用它将导致难以检
155*f2c3bb11SYanteng Si测的错误的中断启用。
156*f2c3bb11SYanteng Si
157*f2c3bb11SYanteng Si默认行为是不带超时的等待,并将任务标记为“UNINTERRUPTIBLE”状态。wait_for_completion()
158*f2c3bb11SYanteng Si及其变体只有在进程上下文中才是安全的(因为它们可以休眠),但在原子上下文、中断上下文、IRQ
159*f2c3bb11SYanteng Si被禁用或抢占被禁用的情况下是不安全的--关于在原子/中断上下文中处理完成的问题,还请看下面的
160*f2c3bb11SYanteng Sitry_wait_for_completion()。
161*f2c3bb11SYanteng Si
162*f2c3bb11SYanteng Si由于wait_for_completion()的所有变体都可能(很明显)阻塞很长时间,这取决于它们所等
163*f2c3bb11SYanteng Si待的活动的性质,所以在大多数情况下,你可能不想在持有mutex锁的情况下调用它。
164*f2c3bb11SYanteng Si
165*f2c3bb11SYanteng Si
166*f2c3bb11SYanteng Siwait_for_completion*()可用的变体:
167*f2c3bb11SYanteng Si---------------------------------
168*f2c3bb11SYanteng Si
169*f2c3bb11SYanteng Si下面的变体都会返回状态,在大多数(/所有)情况下都应该检查这个状态--在故意不检查状态的情
170*f2c3bb11SYanteng Si况下,你可能要做一个说明(例如,见arch/arm/kernel/smp.c:__cpu_up())。
171*f2c3bb11SYanteng Si
172*f2c3bb11SYanteng Si一个常见的问题是不准确的返回类型赋值,所以要注意将返回值赋值给适当类型的变量。
173*f2c3bb11SYanteng Si
174*f2c3bb11SYanteng Si检查返回值的具体含义也可能被发现是相当不准确的,例如,像这样的构造::
175*f2c3bb11SYanteng Si
176*f2c3bb11SYanteng Si	if (!wait_for_completion_interruptible_timeout(...))
177*f2c3bb11SYanteng Si
178*f2c3bb11SYanteng Si...会在成功完成和中断的情况下执行相同的代码路径--这可能不是你想要的结果::
179*f2c3bb11SYanteng Si
180*f2c3bb11SYanteng Si	int wait_for_completion_interruptible(struct completion *done)
181*f2c3bb11SYanteng Si
182*f2c3bb11SYanteng Si这个函数在任务等待时标记为TASK_INTERRUPTIBLE。如果在等待期间收到信号,它将返回
183*f2c3bb11SYanteng Si-ERESTARTSYS;否则为0::
184*f2c3bb11SYanteng Si
185*f2c3bb11SYanteng Si	unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout)
186*f2c3bb11SYanteng Si
187*f2c3bb11SYanteng Si该任务被标记为TASK_UNINTERRUPTIBLE,并将最多超时等待“timeout”个jiffies。如果超时发生,则
188*f2c3bb11SYanteng Si返回0,否则返回剩余的时间(但至少是1)。
189*f2c3bb11SYanteng Si
190*f2c3bb11SYanteng Si超时最好用msecs_to_jiffies()或usecs_to_jiffies()计算,以使代码在很大程度上不受
191*f2c3bb11SYanteng SiHZ的影响。
192*f2c3bb11SYanteng Si
193*f2c3bb11SYanteng Si如果返回的超时值被故意忽略,那么注释应该解释原因
194*f2c3bb11SYanteng Si(例如,见drivers/mfd/wm8350-core.c wm8350_read_auxadc()::
195*f2c3bb11SYanteng Si
196*f2c3bb11SYanteng Si	long wait_for_completion_interruptible_timeout(struct completion *done, unsigned long timeout)
197*f2c3bb11SYanteng Si
198*f2c3bb11SYanteng Si这个函数传递一个以jiffies为单位的超时,并将任务标记为TASK_INTERRUPTIBLE。如果收到
199*f2c3bb11SYanteng Si信号,则返回-ERESTARTSYS;否则,如果完成超时,则返回0;如果完成了,则返回剩余的时间
200*f2c3bb11SYanteng Si(jiffies)。
201*f2c3bb11SYanteng Si
202*f2c3bb11SYanteng Si更多的变体包括_killable,它使用TASK_KILLABLE作为指定的任务状态,如果它被中断,将返
203*f2c3bb11SYanteng Si回-ERESTARTSYS,如果完成了,则返回0。它也有一个_timeout变体::
204*f2c3bb11SYanteng Si
205*f2c3bb11SYanteng Si	long wait_for_completion_killable(struct completion *done)
206*f2c3bb11SYanteng Si	long wait_for_completion_killable_timeout(struct completion *done, unsigned long timeout)
207*f2c3bb11SYanteng Si
208*f2c3bb11SYanteng Siwait_for_completion_io()的_io变体的行为与非_io变体相同,只是将等待时间计为“IO等待”,
209*f2c3bb11SYanteng Si这对任务在调度/IO统计中的计算方式有影响::
210*f2c3bb11SYanteng Si
211*f2c3bb11SYanteng Si	void wait_for_completion_io(struct completion *done)
212*f2c3bb11SYanteng Si	unsigned long wait_for_completion_io_timeout(struct completion *done, unsigned long timeout)
213*f2c3bb11SYanteng Si
214*f2c3bb11SYanteng Si
215*f2c3bb11SYanteng Si对完成发信号:
216*f2c3bb11SYanteng Si-------------
217*f2c3bb11SYanteng Si
218*f2c3bb11SYanteng Si一个线程想要发出信号通知继续的条件已经达到,就会调用complete(),向其中一个等待者发出信
219*f2c3bb11SYanteng Si号表明它可以继续::
220*f2c3bb11SYanteng Si
221*f2c3bb11SYanteng Si	void complete(struct completion *done)
222*f2c3bb11SYanteng Si
223*f2c3bb11SYanteng Si... or calls complete_all() to signal all current and future waiters::
224*f2c3bb11SYanteng Si
225*f2c3bb11SYanteng Si	void complete_all(struct completion *done)
226*f2c3bb11SYanteng Si
227*f2c3bb11SYanteng Si即使在线程开始等待之前就发出了完成的信号,信号传递也会继续进行。这是通过等待者
228*f2c3bb11SYanteng Si“consuming”(递减)“struct completion” 的完成字段来实现的。等待的线程唤醒的顺序
229*f2c3bb11SYanteng Si与它们被排队的顺序相同(FIFO顺序)。
230*f2c3bb11SYanteng Si
231*f2c3bb11SYanteng Si如果多次调用complete(),那么这将允许该数量的等待者继续进行--每次调用complete()将
232*f2c3bb11SYanteng Si简单地增加已完成的字段。但多次调用complete_all()是一个错误。complete()和
233*f2c3bb11SYanteng Sicomplete_all()都可以在IRQ/atomic上下文中安全调用。
234*f2c3bb11SYanteng Si
235*f2c3bb11SYanteng Si在任何时候,只能有一个线程在一个特定的 “struct completion”上调用 complete() 或
236*f2c3bb11SYanteng Sicomplete_all() - 通过等待队列自旋锁进行序列化。任何对 complete() 或
237*f2c3bb11SYanteng Sicomplete_all() 的并发调用都可能是一个设计错误。
238*f2c3bb11SYanteng Si
239*f2c3bb11SYanteng Si从IRQ上下文中发出完成信号 是可行的,因为它将正确地用
240*f2c3bb11SYanteng Sispin_lock_irqsave()/spin_unlock_irqrestore()执行锁操作
241*f2c3bb11SYanteng Si
242*f2c3bb11SYanteng Si
243*f2c3bb11SYanteng Sitry_wait_for_completion()/completion_done():
244*f2c3bb11SYanteng Si--------------------------------------------
245*f2c3bb11SYanteng Si
246*f2c3bb11SYanteng Sitry_wait_for_completion()函数不会将线程放在等待队列中,而是在需要排队(阻塞)线
247*f2c3bb11SYanteng Si程时返回false,否则会消耗一个已发布的完成并返回true::
248*f2c3bb11SYanteng Si
249*f2c3bb11SYanteng Si	bool try_wait_for_completion(struct completion *done)
250*f2c3bb11SYanteng Si
251*f2c3bb11SYanteng Si最后,为了在不以任何方式改变完成的情况下检查完成的状态,可以调用completion_done(),
252*f2c3bb11SYanteng Si如果没有发布的完成尚未被等待者消耗,则返回false(意味着存在等待者),否则返回true::
253*f2c3bb11SYanteng Si
254*f2c3bb11SYanteng Si	bool completion_done(struct completion *done)
255*f2c3bb11SYanteng Si
256*f2c3bb11SYanteng Sitry_wait_for_completion()和completion_done()都可以在IRQ或原子上下文中安全调用。
257