.. 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或原å上下文ä¸å®‰å…¨è°ƒç”¨ã€‚