.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/scheduler/completion.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> :æ ¡è¯‘: å”艺舟 Tang Yizhou <tangyeechou@gmail.com> ======================================= å®Œæˆ - "ç‰å¾…完æˆ" å±éšœåº”ç”¨ç¨‹åºæŽ¥å£(API) ======================================= 简介: ----- å¦‚æžœä½ æœ‰ä¸€ä¸ªæˆ–å¤šä¸ªçº¿ç¨‹å¿…é¡»ç‰å¾…æŸäº›å†…æ ¸æ´»åŠ¨è¾¾åˆ°æŸä¸ªç‚¹æˆ–æŸä¸ªç‰¹å®šçš„状æ€ï¼Œå®Œæˆå¯ä»¥ä¸ºè¿™ 个问题æä¾›ä¸€ä¸ªæ— 竞争的解决方案。从è¯ä¹‰ä¸Šè®²ï¼Œå®ƒä»¬æœ‰ç‚¹åƒpthread_barrier(),并且使 用的案例类似 å®Œæˆæ˜¯ä¸€ç§ä»£ç åŒæ¥æœºåˆ¶ï¼Œå®ƒæ¯”任何滥用é”/ä¿¡å·é‡å’Œå¿™ç‰å¾…循环的行为都è¦å¥½ã€‚å½“ä½ æƒ³ç”¨yield() æˆ–ä¸€äº›å¤æ€ªçš„msleep(1)循环æ¥å…许其它代ç ç»§ç»è¿è¡Œæ—¶ï¼Œä½ å¯èƒ½æƒ³ç”¨wait_for_completion*() 调用和completion()æ¥ä»£æ›¿ã€‚ 使用“完æˆâ€çš„好处是,它们有一个良好定义ã€èšç„¦çš„ç›®æ ‡ï¼Œè¿™ä¸ä»…使得我们很容易ç†è§£ä»£ç çš„æ„图, è€Œä¸”å®ƒä»¬ä¹Ÿä¼šç”Ÿæˆæ›´é«˜æ•ˆçš„代ç ï¼Œå› ä¸ºæ‰€æœ‰çº¿ç¨‹éƒ½å¯ä»¥ç»§ç»æ‰§è¡Œï¼Œç›´åˆ°çœŸæ£éœ€è¦ç»“æžœçš„æ—¶åˆ»ã€‚è€Œä¸”ç‰ å¾…å’Œä¿¡å·éƒ½é«˜æ•ˆçš„使用了低层调度器的ç¡çœ /唤醒设施。 å®Œæˆæ˜¯å»ºç«‹åœ¨Linux调度器的ç‰å¾…队列和唤醒基础设施之上的。ç‰å¾…队列ä¸çš„线程所ç‰å¾…çš„ 事件被简化为 ``struct completion`` ä¸çš„ä¸€ä¸ªç®€å•æ ‡å¿—,被æ°å¦‚å…¶å地称为‘done’。 由于完æˆä¸Žè°ƒåº¦æœ‰å…³ï¼Œä»£ç å¯ä»¥åœ¨kernel/sched/completion.c䏿‰¾åˆ°ã€‚ 用法: ----- 使用完æˆéœ€è¦ä¸‰ä¸ªä¸»è¦éƒ¨åˆ†: - 'struct completion' åŒæ¥å¯¹è±¡çš„åˆå§‹åŒ– - 通过调用wait_for_completion()的一个å˜ä½“æ¥å®žçްç‰å¾…部分。 - 通过调用complete()或complete_all()实现å‘信端。 也有一些辅助函数用于检查完æˆçš„状æ€ã€‚请注æ„,虽然必须先åšåˆå§‹åŒ–,但ç‰å¾…和信å·éƒ¨åˆ†å¯ä»¥ 按任何时间顺åºå‡ºçŽ°ã€‚ä¹Ÿå°±æ˜¯è¯´ï¼Œä¸€ä¸ªçº¿ç¨‹åœ¨å¦ä¸€ä¸ªçº¿ç¨‹æ£€æŸ¥æ˜¯å¦éœ€è¦ç‰å¾…它之å‰ï¼Œå·²ç»å°†ä¸€ä¸ª å®Œæˆæ ‡è®°ä¸º "done",这是完全æ£å¸¸çš„。 è¦ä½¿ç”¨å®ŒæˆAPIï¼Œä½ éœ€è¦#include <linux/completion.h>å¹¶åˆ›å»ºä¸€ä¸ªé™æ€æˆ–动æ€çš„ ``struct completion`` 类型的å˜é‡ï¼Œå®ƒåªæœ‰ä¸¤ä¸ªå—段:: struct completion { unsigned int done; wait_queue_head_t wait; }; 结构体æä¾›äº†->waitç‰å¾…é˜Ÿåˆ—æ¥æ”¾ç½®ä»»åŠ¡è¿›è¡Œç‰å¾…(如果有的è¯ï¼‰ï¼Œä»¥åŠ->doneå®Œæˆæ ‡å¿—æ¥è¡¨æ˜Žå®ƒ 是å¦å®Œæˆã€‚ 完æˆçš„命å应当与æ£åœ¨è¢«åŒæ¥çš„事件åä¸€è‡´ã€‚ä¸€ä¸ªå¥½çš„ä¾‹åæ˜¯:: wait_for_completion(&early_console_added); complete(&early_console_added); 好的ã€ç›´è§‚的命å(一如既往地)有助于代ç çš„å¯è¯»æ€§ã€‚将一个完æˆå‘½å为 ``complete`` 是没有帮助的,除éžå…¶ç›®çš„æ˜¯è¶…级明显的... åˆå§‹åŒ–完æˆ: ----------- 动æ€åˆ†é…的完æˆå¯¹è±¡æœ€å¥½è¢«åµŒå…¥åˆ°æ•°æ®ç»“æž„ä¸ï¼Œä»¥ç¡®ä¿åœ¨å‡½æ•°/é©±åŠ¨çš„ç”Ÿå‘½å‘¨æœŸå†…å˜æ´»ï¼Œä»¥é˜² æ¢ä¸Žå¼‚æ¥complete()调用å‘生竞争。 在使用wait_for_completion()çš„_timeout()或_killable()/_interruptible()å˜ä½“ 时应特别å°å¿ƒï¼Œå› 为必须ä¿è¯åœ¨æ‰€æœ‰ç›¸å…³æ´»åŠ¨ï¼ˆcomplete()或reinit_completion())å‘生 之å‰ä¸ä¼šå‘生内å˜è§£é™¤åˆ†é…,å³ä½¿è¿™äº›ç‰å¾…函数由于超时或信å·è§¦å‘而过早返回。 动æ€åˆ†é…的完æˆå¯¹è±¡çš„åˆå§‹åŒ–是通过调用init_completion()æ¥å®Œæˆçš„:: init_completion(&dynamic_object->done); 在这个调用ä¸ï¼Œæˆ‘们åˆå§‹åŒ– waitqueue å¹¶å°† ->done 设置为 0,å³â€œnot completedâ€æˆ– “not doneâ€ã€‚ 釿–°åˆå§‹åŒ–函数reinit_completion()ï¼Œåªæ˜¯å°†->doneå—æ®µé‡ç½®ä¸º0(“not doneâ€ï¼‰ï¼Œè€Œ ä¸è§¦åŠç‰å¾…é˜Ÿåˆ—ã€‚è¿™ä¸ªå‡½æ•°çš„è°ƒç”¨è€…å¿…é¡»ç¡®ä¿æ²¡æœ‰ä»»ä½•令人讨厌的wait_for_completion() 调用在并行进行。 在åŒä¸€ä¸ªå®Œæˆå¯¹è±¡ä¸Šè°ƒç”¨init_completion()两次很å¯èƒ½æ˜¯ä¸€ä¸ªbugï¼Œå› ä¸ºå®ƒå°†é˜Ÿåˆ—é‡æ–°åˆå§‹ 化为一个空队列,已排队的任务å¯èƒ½ä¼šâ€œä¸¢å¤±â€--åœ¨è¿™ç§æƒ…况下使用reinit_completion(),但 è¦æ³¨æ„其他竞争。 å¯¹äºŽé™æ€å£°æ˜Žå’Œåˆå§‹åŒ–,å¯ä»¥ä½¿ç”¨å®ã€‚ å¯¹äºŽæ–‡ä»¶èŒƒå›´å†…çš„é™æ€ï¼ˆæˆ–å…¨å±€ï¼‰å£°æ˜Žï¼Œä½ å¯ä»¥ä½¿ç”¨ DECLARE_COMPLETION():: static DECLARE_COMPLETION(setup_done); DECLARE_COMPLETION(setup_done); 注æ„ï¼Œåœ¨è¿™ç§æƒ…况下,完æˆåœ¨å¯åŠ¨æ—¶ï¼ˆæˆ–æ¨¡å—åŠ è½½æ—¶ï¼‰è¢«åˆå§‹åŒ–为“not doneâ€ï¼Œä¸éœ€è¦è°ƒç”¨ init_completion()。 当完æˆè¢«å£°æ˜Žä¸ºä¸€ä¸ªå‡½æ•°ä¸çš„局部å˜é‡æ—¶ï¼Œé‚£ä¹ˆåº”该总是明确地使用 DECLARE_COMPLETION_ONSTACK()æ¥åˆå§‹åŒ–,这ä¸ä»…仅是为了让lockdepæ£ç¡®è¿è¡Œï¼Œä¹Ÿæ˜¯æ˜Žç¡®è¡¨ å它有é™çš„使用范围是有æ„为之并被仔细考虑的:: DECLARE_COMPLETION_ONSTACK(setup_done) 请注æ„,当使用完æˆå¯¹è±¡ä½œä¸ºå±€éƒ¨å˜é‡æ—¶ï¼Œä½ å¿…é¡»æ•é”地æ„è¯†åˆ°å‡½æ•°å †æ ˆçš„çŸæš‚生命期:在所有 活动(如ç‰å¾…çš„çº¿ç¨‹ï¼‰åœæ¢å¹¶ä¸”完æˆå¯¹è±¡å®Œå…¨æœªè¢«ä½¿ç”¨ä¹‹å‰ï¼Œå‡½æ•°ä¸å¾—返回到调用上下文。 冿¬¡å¼ºè°ƒè¿™ä¸€ç‚¹ï¼šç‰¹åˆ«æ˜¯åœ¨ä½¿ç”¨ä¸€äº›å…·æœ‰æ›´å¤æ‚结果的ç‰å¾…APIå˜ä½“æ—¶ï¼Œæ¯”å¦‚è¶…æ—¶æˆ–ä¿¡å· ï¼ˆ_timeout(), _killable()å’Œ_interruptible())å˜ä½“,ç‰å¾…å¯èƒ½ä¼šæå‰å®Œæˆï¼Œè€Œå¯¹è±¡å¯ 能ä»åœ¨è¢«å…¶ä»–线程使用 - 从wait_on_completion*()è°ƒç”¨è€…å‡½æ•°çš„è¿”å›žä¼šå–æ¶ˆåˆ†é…å‡½æ•°æ ˆï¼Œå¦‚ æžœcomplete()在其它æŸçº¿ç¨‹ä¸å®Œæˆè°ƒç”¨ï¼Œä¼šå¼•èµ·å¾®å°çš„æ•°æ®æŸå。简å•的测试å¯èƒ½ä¸ä¼šè§¦å‘è¿™ 些类型的竞争。 如果ä¸ç¡®å®šçš„è¯ï¼Œä½¿ç”¨åЍæ€åˆ†é…的完æˆå¯¹è±¡ï¼Œ 最好是嵌入到其它一些生命周期长的对象ä¸ï¼Œé•¿åˆ° 超过使用完æˆå¯¹è±¡çš„ä»»ä½•è¾…åŠ©çº¿ç¨‹çš„ç”Ÿå‘½å‘¨æœŸï¼Œæˆ–è€…æœ‰ä¸€ä¸ªé”æˆ–å…¶ä»–åŒæ¥æœºåˆ¶æ¥ç¡®ä¿complete() ä¸ä¼šåœ¨ä¸€ä¸ªè¢«é‡Šæ”¾çš„对象ä¸è°ƒç”¨ã€‚ åœ¨å †æ ˆä¸Šå•纯地调用DECLARE_COMPLETION()会触å‘一个lockdepè¦å‘Šã€‚ ç‰å¾…完æˆ: --------- 对于一个线程æ¥è¯´ï¼Œè¦ç‰å¾…ä¸€äº›å¹¶å‘æ´»åŠ¨çš„å®Œæˆï¼Œå®ƒè¦åœ¨åˆå§‹åŒ–的完æˆç»“构体上调用 wait_for_completion():: void wait_for_completion(struct completion *done) 一个典型的使用场景是:: CPU#1 CPU#2 struct completion setup_done; init_completion(&setup_done); initialize_work(...,&setup_done,...); /* run non-dependent code */ /* do setup */ wait_for_completion(&setup_done); complete(setup_done); è¿™å¹¶ä¸æ„味ç€è°ƒç”¨wait_for_completion()å’Œcomplete()有任何特定的时间顺åº--如果调 用complete()å‘生在调用wait_for_completion()之å‰ï¼Œé‚£ä¹ˆç‰å¾…方将立å³ç»§ç»æ‰§è¡Œï¼Œå› 为 所有的ä¾èµ–都得到了满足;如果没有,它将阻塞,直到complete()å‘出完æˆçš„ä¿¡å·ã€‚ 注æ„,wait_for_completion()是在调用spin_lock_irq()/spin_unlock_irq(),所以 åªæœ‰å½“ä½ çŸ¥é“䏿–被å¯ç”¨æ—¶æ‰èƒ½å®‰å…¨åœ°è°ƒç”¨å®ƒã€‚从IRQs-off的原å上下文ä¸è°ƒç”¨å®ƒå°†å¯¼è‡´éš¾ä»¥æ£€ æµ‹çš„é”™è¯¯çš„ä¸æ–å¯ç”¨ã€‚ 默认行为是ä¸å¸¦è¶…æ—¶çš„ç‰å¾…ï¼Œå¹¶å°†ä»»åŠ¡æ ‡è®°ä¸ºâ€œUNINTERRUPTIBLEâ€çжæ€ã€‚wait_for_completion() åŠå…¶å˜ä½“åªæœ‰åœ¨è¿›ç¨‹ä¸Šä¸‹æ–‡ä¸æ‰æ˜¯å®‰å…¨çš„ï¼ˆå› ä¸ºå®ƒä»¬å¯ä»¥ä¼‘çœ ï¼‰ï¼Œä½†åœ¨åŽŸå上下文ã€ä¸æ–上下文ã€IRQ 被ç¦ç”¨æˆ–抢å 被ç¦ç”¨çš„æƒ…况下是ä¸å®‰å…¨çš„--关于在原å/䏿–上下文ä¸å¤„ç†å®Œæˆçš„问题,还请看下é¢çš„ try_wait_for_completion()。 由于wait_for_completion()的所有å˜ä½“都å¯èƒ½ï¼ˆå¾ˆæ˜Žæ˜¾ï¼‰é˜»å¡žå¾ˆé•¿æ—¶é—´ï¼Œè¿™å–å†³äºŽå®ƒä»¬æ‰€ç‰ å¾…çš„æ´»åŠ¨çš„æ€§è´¨ï¼Œæ‰€ä»¥åœ¨å¤§å¤šæ•°æƒ…å†µä¸‹ï¼Œä½ å¯èƒ½ä¸æƒ³åœ¨æŒæœ‰mutexé”的情况下调用它。 wait_for_completion*()å¯ç”¨çš„å˜ä½“: --------------------------------- 下é¢çš„å˜ä½“都会返回状æ€ï¼Œåœ¨å¤§å¤šæ•°(/所有)情况下都应该检查这个状æ€--在故æ„䏿£€æŸ¥çжæ€çš„æƒ… å†µä¸‹ï¼Œä½ å¯èƒ½è¦åšä¸€ä¸ªè¯´æ˜Ž(例如,è§arch/arm/kernel/smp.c:__cpu_up())。 一个常è§çš„问题是ä¸å‡†ç¡®çš„è¿”å›žç±»åž‹èµ‹å€¼ï¼Œæ‰€ä»¥è¦æ³¨æ„将返回值赋值给适当类型的å˜é‡ã€‚ 检查返回值的具体å«ä¹‰ä¹Ÿå¯èƒ½è¢«å‘现是相当ä¸å‡†ç¡®çš„,例如,åƒè¿™æ ·çš„æž„é€ :: if (!wait_for_completion_interruptible_timeout(...)) ...会在æˆåŠŸå®Œæˆå’Œä¸æ–的情况下执行相åŒçš„代ç 路径--è¿™å¯èƒ½ä¸æ˜¯ä½ 想è¦çš„结果:: int wait_for_completion_interruptible(struct completion *done) 这个函数在任务ç‰å¾…æ—¶æ ‡è®°ä¸ºTASK_INTERRUPTIBLE。如果在ç‰å¾…期间收到信å·ï¼Œå®ƒå°†è¿”回 -ERESTARTSYSï¼›å¦åˆ™ä¸º0:: unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout) è¯¥ä»»åŠ¡è¢«æ ‡è®°ä¸ºTASK_UNINTERRUPTIBLE,并将最多超时ç‰å¾…“timeoutâ€ä¸ªjiffies。如果超时å‘生,则 返回0,å¦åˆ™è¿”回剩余的时间(但至少是1)。 超时最好用msecs_to_jiffies()或usecs_to_jiffies()计算,以使代ç 在很大程度上ä¸å— HZ的影å“。 如果返回的超时值被故æ„å¿½ç•¥ï¼Œé‚£ä¹ˆæ³¨é‡Šåº”è¯¥è§£é‡ŠåŽŸå› ï¼ˆä¾‹å¦‚ï¼Œè§drivers/mfd/wm8350-core.c wm8350_read_auxadc():: long wait_for_completion_interruptible_timeout(struct completion *done, unsigned long timeout) è¿™ä¸ªå‡½æ•°ä¼ é€’ä¸€ä¸ªä»¥jiffies为å•ä½çš„è¶…æ—¶ï¼Œå¹¶å°†ä»»åŠ¡æ ‡è®°ä¸ºTASK_INTERRUPTIBLE。如果收到 ä¿¡å·ï¼Œåˆ™è¿”回-ERESTARTSYSï¼›å¦åˆ™ï¼Œå¦‚果完æˆè¶…时,则返回0;如果完æˆäº†ï¼Œåˆ™è¿”回剩余的时间 (jiffies)。 更多的å˜ä½“包括_killable,它使用TASK_KILLABLE作为指定的任务状æ€ï¼Œå¦‚æžœå®ƒè¢«ä¸æ–,将返 回-ERESTARTSYS,如果完æˆäº†ï¼Œåˆ™è¿”回0。它也有一个_timeoutå˜ä½“:: long wait_for_completion_killable(struct completion *done) long wait_for_completion_killable_timeout(struct completion *done, unsigned long timeout) wait_for_completion_io()çš„_ioå˜ä½“的行为与éž_ioå˜ä½“相åŒï¼Œåªæ˜¯å°†ç‰å¾…时间计为“IOç‰å¾…â€ï¼Œ 这对任务在调度/IO统计ä¸çš„è®¡ç®—æ–¹å¼æœ‰å½±å“:: void wait_for_completion_io(struct completion *done) unsigned long wait_for_completion_io_timeout(struct completion *done, unsigned long timeout) 对完æˆå‘ä¿¡å·: ------------- 一个线程想è¦å‘出信å·é€šçŸ¥ç»§ç»çš„æ¡ä»¶å·²ç»è¾¾åˆ°ï¼Œå°±ä¼šè°ƒç”¨complete(),å‘å…¶ä¸ä¸€ä¸ªç‰å¾…者å‘出信 å·è¡¨æ˜Žå®ƒå¯ä»¥ç»§ç»:: void complete(struct completion *done) ... or calls complete_all() to signal all current and future waiters:: void complete_all(struct completion *done) å³ä½¿åœ¨çº¿ç¨‹å¼€å§‹ç‰å¾…之å‰å°±å‘出了完æˆçš„ä¿¡å·ï¼Œä¿¡å·ä¼ 递也会继ç»è¿›è¡Œã€‚这是通过ç‰å¾…者 “consumingâ€ï¼ˆé€’å‡ï¼‰â€œstruct completion†的完æˆå—段æ¥å®žçŽ°çš„ã€‚ç‰å¾…çš„çº¿ç¨‹å”¤é†’çš„é¡ºåº ä¸Žå®ƒä»¬è¢«æŽ’é˜Ÿçš„é¡ºåºç›¸åŒï¼ˆFIFO顺åºï¼‰ã€‚ 如果多次调用complete(),那么这将å…许该数é‡çš„ç‰å¾…者继ç»è¿›è¡Œ--æ¯æ¬¡è°ƒç”¨complete()å°† 简å•åœ°å¢žåŠ å·²å®Œæˆçš„å—æ®µã€‚但多次调用complete_all()是一个错误。complete()å’Œ complete_all()都å¯ä»¥åœ¨IRQ/atomic上下文ä¸å®‰å…¨è°ƒç”¨ã€‚ 在任何时候,åªèƒ½æœ‰ä¸€ä¸ªçº¿ç¨‹åœ¨ä¸€ä¸ªç‰¹å®šçš„ “struct completionâ€ä¸Šè°ƒç”¨ complete() 或 complete_all() - 通过ç‰å¾…队列自旋é”进行åºåˆ—化。任何对 complete() 或 complete_all() 的并å‘调用都å¯èƒ½æ˜¯ä¸€ä¸ªè®¾è®¡é”™è¯¯ã€‚ 从IRQ上下文ä¸å‘出完æˆä¿¡å· 是å¯è¡Œçš„ï¼Œå› ä¸ºå®ƒå°†æ£ç¡®åœ°ç”¨ spin_lock_irqsave()/spin_unlock_irqrestore()æ‰§è¡Œé”æ“作 try_wait_for_completion()/completion_done(): -------------------------------------------- try_wait_for_completion()函数ä¸ä¼šå°†çº¿ç¨‹æ”¾åœ¨ç‰å¾…队列ä¸ï¼Œè€Œæ˜¯åœ¨éœ€è¦æŽ’队(阻塞)线 程时返回false,å¦åˆ™ä¼šæ¶ˆè€—一个已å‘布的完æˆå¹¶è¿”回true:: bool try_wait_for_completion(struct completion *done) 最åŽï¼Œä¸ºäº†åœ¨ä¸ä»¥ä»»ä½•æ–¹å¼æ”¹å˜å®Œæˆçš„æƒ…况下检查完æˆçš„状æ€ï¼Œå¯ä»¥è°ƒç”¨completion_done(), 如果没有å‘布的完æˆå°šæœªè¢«ç‰å¾…者消耗,则返回false(æ„味ç€å˜åœ¨ç‰å¾…者),å¦åˆ™è¿”回true:: bool completion_done(struct completion *done) try_wait_for_completion()å’Œcompletion_done()都å¯ä»¥åœ¨IRQ或原å上下文ä¸å®‰å…¨è°ƒç”¨ã€‚